summaryrefslogtreecommitdiffstats
path: root/dbaccess/source
diff options
context:
space:
mode:
Diffstat (limited to 'dbaccess/source')
-rw-r--r--dbaccess/source/core/api/BookmarkSet.cxx204
-rw-r--r--dbaccess/source/core/api/BookmarkSet.hxx57
-rw-r--r--dbaccess/source/core/api/CIndexes.cxx87
-rw-r--r--dbaccess/source/core/api/CIndexes.hxx47
-rw-r--r--dbaccess/source/core/api/CRowSetColumn.cxx92
-rw-r--r--dbaccess/source/core/api/CRowSetColumn.hxx49
-rw-r--r--dbaccess/source/core/api/CRowSetDataColumn.cxx236
-rw-r--r--dbaccess/source/core/api/CRowSetDataColumn.hxx99
-rw-r--r--dbaccess/source/core/api/CacheSet.cxx580
-rw-r--r--dbaccess/source/core/api/CacheSet.hxx172
-rw-r--r--dbaccess/source/core/api/FilteredContainer.cxx459
-rw-r--r--dbaccess/source/core/api/HelperCollections.cxx106
-rw-r--r--dbaccess/source/core/api/HelperCollections.hxx106
-rw-r--r--dbaccess/source/core/api/KeySet.cxx1463
-rw-r--r--dbaccess/source/core/api/KeySet.hxx216
-rw-r--r--dbaccess/source/core/api/OptimisticSet.cxx586
-rw-r--r--dbaccess/source/core/api/OptimisticSet.hxx76
-rw-r--r--dbaccess/source/core/api/PrivateRow.cxx133
-rw-r--r--dbaccess/source/core/api/PrivateRow.hxx58
-rw-r--r--dbaccess/source/core/api/RowSet.cxx2965
-rw-r--r--dbaccess/source/core/api/RowSet.hxx527
-rw-r--r--dbaccess/source/core/api/RowSetBase.cxx1438
-rw-r--r--dbaccess/source/core/api/RowSetBase.hxx402
-rw-r--r--dbaccess/source/core/api/RowSetCache.cxx1713
-rw-r--r--dbaccess/source/core/api/RowSetCache.hxx190
-rw-r--r--dbaccess/source/core/api/RowSetCacheIterator.cxx91
-rw-r--r--dbaccess/source/core/api/RowSetCacheIterator.hxx72
-rw-r--r--dbaccess/source/core/api/RowSetRow.hxx52
-rw-r--r--dbaccess/source/core/api/SingleSelectQueryComposer.cxx1922
-rw-r--r--dbaccess/source/core/api/StaticSet.cxx280
-rw-r--r--dbaccess/source/core/api/StaticSet.hxx75
-rw-r--r--dbaccess/source/core/api/TableDeco.cxx634
-rw-r--r--dbaccess/source/core/api/View.cxx120
-rw-r--r--dbaccess/source/core/api/WrappedResultSet.cxx184
-rw-r--r--dbaccess/source/core/api/WrappedResultSet.hxx60
-rw-r--r--dbaccess/source/core/api/callablestatement.cxx250
-rw-r--r--dbaccess/source/core/api/column.cxx411
-rw-r--r--dbaccess/source/core/api/columnsettings.cxx150
-rw-r--r--dbaccess/source/core/api/datacolumn.cxx396
-rw-r--r--dbaccess/source/core/api/datacolumn.hxx107
-rw-r--r--dbaccess/source/core/api/datasettings.cxx191
-rw-r--r--dbaccess/source/core/api/definitioncolumn.cxx610
-rw-r--r--dbaccess/source/core/api/preparedstatement.cxx412
-rw-r--r--dbaccess/source/core/api/query.cxx383
-rw-r--r--dbaccess/source/core/api/query.hxx147
-rw-r--r--dbaccess/source/core/api/querycomposer.cxx265
-rw-r--r--dbaccess/source/core/api/querycontainer.cxx430
-rw-r--r--dbaccess/source/core/api/querydescriptor.cxx269
-rw-r--r--dbaccess/source/core/api/querydescriptor.hxx143
-rw-r--r--dbaccess/source/core/api/resultcolumn.cxx296
-rw-r--r--dbaccess/source/core/api/resultcolumn.hxx87
-rw-r--r--dbaccess/source/core/api/resultset.cxx994
-rw-r--r--dbaccess/source/core/api/resultset.hxx221
-rw-r--r--dbaccess/source/core/api/statement.cxx591
-rw-r--r--dbaccess/source/core/api/table.cxx352
-rw-r--r--dbaccess/source/core/api/tablecontainer.cxx456
-rw-r--r--dbaccess/source/core/api/viewcontainer.cxx254
-rw-r--r--dbaccess/source/core/dataaccess/ComponentDefinition.cxx285
-rw-r--r--dbaccess/source/core/dataaccess/ComponentDefinition.hxx159
-rw-r--r--dbaccess/source/core/dataaccess/ContentHelper.cxx615
-rw-r--r--dbaccess/source/core/dataaccess/ModelImpl.cxx1432
-rw-r--r--dbaccess/source/core/dataaccess/SharedConnection.cxx154
-rw-r--r--dbaccess/source/core/dataaccess/SharedConnection.hxx118
-rw-r--r--dbaccess/source/core/dataaccess/bookmarkcontainer.cxx301
-rw-r--r--dbaccess/source/core/dataaccess/commandcontainer.cxx100
-rw-r--r--dbaccess/source/core/dataaccess/commandcontainer.hxx72
-rw-r--r--dbaccess/source/core/dataaccess/commanddefinition.cxx153
-rw-r--r--dbaccess/source/core/dataaccess/commanddefinition.hxx125
-rw-r--r--dbaccess/source/core/dataaccess/connection.cxx808
-rw-r--r--dbaccess/source/core/dataaccess/connection.hxx229
-rw-r--r--dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx229
-rw-r--r--dbaccess/source/core/dataaccess/databasecontext.cxx753
-rw-r--r--dbaccess/source/core/dataaccess/databasedocument.cxx2211
-rw-r--r--dbaccess/source/core/dataaccess/databasedocument.hxx753
-rw-r--r--dbaccess/source/core/dataaccess/databaseregistrations.cxx369
-rw-r--r--dbaccess/source/core/dataaccess/databaseregistrations.hxx32
-rw-r--r--dbaccess/source/core/dataaccess/datasource.cxx1437
-rw-r--r--dbaccess/source/core/dataaccess/datasource.hxx220
-rw-r--r--dbaccess/source/core/dataaccess/definitioncontainer.cxx679
-rw-r--r--dbaccess/source/core/dataaccess/documentcontainer.cxx770
-rw-r--r--dbaccess/source/core/dataaccess/documentcontainer.hxx137
-rw-r--r--dbaccess/source/core/dataaccess/documentdefinition.cxx2102
-rw-r--r--dbaccess/source/core/dataaccess/documentdefinition.hxx356
-rw-r--r--dbaccess/source/core/dataaccess/documenteventexecutor.cxx199
-rw-r--r--dbaccess/source/core/dataaccess/documenteventexecutor.hxx59
-rw-r--r--dbaccess/source/core/dataaccess/documenteventnotifier.cxx290
-rw-r--r--dbaccess/source/core/dataaccess/documenteventnotifier.hxx128
-rw-r--r--dbaccess/source/core/dataaccess/documentevents.cxx216
-rw-r--r--dbaccess/source/core/dataaccess/intercept.cxx363
-rw-r--r--dbaccess/source/core/dataaccess/intercept.hxx113
-rw-r--r--dbaccess/source/core/dataaccess/myucp_datasupplier.cxx330
-rw-r--r--dbaccess/source/core/dataaccess/myucp_datasupplier.hxx59
-rw-r--r--dbaccess/source/core/dataaccess/myucp_resultset.cxx74
-rw-r--r--dbaccess/source/core/dataaccess/myucp_resultset.hxx49
-rw-r--r--dbaccess/source/core/inc/ContainerMediator.hxx79
-rw-r--r--dbaccess/source/core/inc/ContentHelper.hxx183
-rw-r--r--dbaccess/source/core/inc/DatabaseDataProvider.hxx262
-rw-r--r--dbaccess/source/core/inc/FilteredContainer.hxx136
-rw-r--r--dbaccess/source/core/inc/ModelImpl.hxx542
-rw-r--r--dbaccess/source/core/inc/PropertyForward.hxx69
-rw-r--r--dbaccess/source/core/inc/RefreshListener.hxx42
-rw-r--r--dbaccess/source/core/inc/SingleSelectQueryComposer.hxx263
-rw-r--r--dbaccess/source/core/inc/TableDeco.hxx164
-rw-r--r--dbaccess/source/core/inc/View.hxx71
-rw-r--r--dbaccess/source/core/inc/bookmarkcontainer.hxx148
-rw-r--r--dbaccess/source/core/inc/callablestatement.hxx80
-rw-r--r--dbaccess/source/core/inc/column.hxx217
-rw-r--r--dbaccess/source/core/inc/columnsettings.hxx88
-rw-r--r--dbaccess/source/core/inc/commandbase.hxx50
-rw-r--r--dbaccess/source/core/inc/composertools.hxx121
-rw-r--r--dbaccess/source/core/inc/containerapprove.hxx57
-rw-r--r--dbaccess/source/core/inc/databasecontext.hxx180
-rw-r--r--dbaccess/source/core/inc/datasettings.hxx77
-rw-r--r--dbaccess/source/core/inc/definitioncolumn.hxx291
-rw-r--r--dbaccess/source/core/inc/definitioncontainer.hxx323
-rw-r--r--dbaccess/source/core/inc/documentevents.hxx75
-rw-r--r--dbaccess/source/core/inc/migrwarndlg.hxx24
-rw-r--r--dbaccess/source/core/inc/object.hxx30
-rw-r--r--dbaccess/source/core/inc/objectnameapproval.hxx75
-rw-r--r--dbaccess/source/core/inc/preparedstatement.hxx105
-rw-r--r--dbaccess/source/core/inc/querycomposer.hxx91
-rw-r--r--dbaccess/source/core/inc/querycontainer.hxx165
-rw-r--r--dbaccess/source/core/inc/recovery/dbdocrecovery.hxx71
-rw-r--r--dbaccess/source/core/inc/sdbcoretools.hxx55
-rw-r--r--dbaccess/source/core/inc/statement.hxx179
-rw-r--r--dbaccess/source/core/inc/table.hxx140
-rw-r--r--dbaccess/source/core/inc/tablecontainer.hxx96
-rw-r--r--dbaccess/source/core/inc/veto.hxx55
-rw-r--r--dbaccess/source/core/inc/viewcontainer.hxx94
-rw-r--r--dbaccess/source/core/misc/ContainerMediator.cxx231
-rw-r--r--dbaccess/source/core/misc/DatabaseDataProvider.cxx1066
-rw-r--r--dbaccess/source/core/misc/PropertyForward.cxx146
-rw-r--r--dbaccess/source/core/misc/apitools.cxx114
-rw-r--r--dbaccess/source/core/misc/dsntypes.cxx565
-rw-r--r--dbaccess/source/core/misc/migrwarndlg.cxx22
-rw-r--r--dbaccess/source/core/misc/objectnameapproval.cxx74
-rw-r--r--dbaccess/source/core/misc/sdbcoretools.cxx142
-rw-r--r--dbaccess/source/core/misc/veto.cxx49
-rw-r--r--dbaccess/source/core/recovery/dbdocrecovery.cxx347
-rw-r--r--dbaccess/source/core/recovery/settingsimport.cxx216
-rw-r--r--dbaccess/source/core/recovery/settingsimport.hxx163
-rw-r--r--dbaccess/source/core/recovery/storagestream.cxx55
-rw-r--r--dbaccess/source/core/recovery/storagestream.hxx51
-rw-r--r--dbaccess/source/core/recovery/storagetextstream.cxx71
-rw-r--r--dbaccess/source/core/recovery/storagetextstream.hxx52
-rw-r--r--dbaccess/source/core/recovery/storagexmlstream.cxx151
-rw-r--r--dbaccess/source/core/recovery/storagexmlstream.hxx88
-rw-r--r--dbaccess/source/core/recovery/subcomponentloader.cxx124
-rw-r--r--dbaccess/source/core/recovery/subcomponentloader.hxx71
-rw-r--r--dbaccess/source/core/recovery/subcomponentrecovery.cxx628
-rw-r--r--dbaccess/source/core/recovery/subcomponentrecovery.hxx114
-rw-r--r--dbaccess/source/core/recovery/subcomponents.hxx61
-rw-r--r--dbaccess/source/core/resource/core_resource.cxx41
-rw-r--r--dbaccess/source/filter/hsqldb/alterparser.cxx56
-rw-r--r--dbaccess/source/filter/hsqldb/alterparser.hxx52
-rw-r--r--dbaccess/source/filter/hsqldb/columndef.cxx44
-rw-r--r--dbaccess/source/filter/hsqldb/columndef.hxx47
-rw-r--r--dbaccess/source/filter/hsqldb/createparser.cxx298
-rw-r--r--dbaccess/source/filter/hsqldb/createparser.hxx68
-rw-r--r--dbaccess/source/filter/hsqldb/fbalterparser.cxx53
-rw-r--r--dbaccess/source/filter/hsqldb/fbalterparser.hxx30
-rw-r--r--dbaccess/source/filter/hsqldb/fbcreateparser.cxx218
-rw-r--r--dbaccess/source/filter/hsqldb/fbcreateparser.hxx37
-rw-r--r--dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx58
-rw-r--r--dbaccess/source/filter/hsqldb/hsqlbinarynode.hxx63
-rw-r--r--dbaccess/source/filter/hsqldb/hsqlimport.cxx388
-rw-r--r--dbaccess/source/filter/hsqldb/hsqlimport.hxx60
-rw-r--r--dbaccess/source/filter/hsqldb/parseschema.cxx204
-rw-r--r--dbaccess/source/filter/hsqldb/parseschema.hxx84
-rw-r--r--dbaccess/source/filter/hsqldb/rowinputbinary.cxx399
-rw-r--r--dbaccess/source/filter/hsqldb/rowinputbinary.hxx52
-rw-r--r--dbaccess/source/filter/hsqldb/utils.cxx141
-rw-r--r--dbaccess/source/filter/hsqldb/utils.hxx27
-rw-r--r--dbaccess/source/filter/xml/dbaxml.component46
-rw-r--r--dbaccess/source/filter/xml/dbloader2.cxx535
-rw-r--r--dbaccess/source/filter/xml/xmlAutoStyle.cxx82
-rw-r--r--dbaccess/source/filter/xml/xmlAutoStyle.hxx45
-rw-r--r--dbaccess/source/filter/xml/xmlColumn.cxx162
-rw-r--r--dbaccess/source/filter/xml/xmlColumn.hxx53
-rw-r--r--dbaccess/source/filter/xml/xmlComponent.cxx99
-rw-r--r--dbaccess/source/filter/xml/xmlComponent.hxx40
-rw-r--r--dbaccess/source/filter/xml/xmlConnectionData.cxx93
-rw-r--r--dbaccess/source/filter/xml/xmlConnectionData.hxx41
-rw-r--r--dbaccess/source/filter/xml/xmlConnectionResource.cxx88
-rw-r--r--dbaccess/source/filter/xml/xmlConnectionResource.hxx36
-rw-r--r--dbaccess/source/filter/xml/xmlDataSource.cxx251
-rw-r--r--dbaccess/source/filter/xml/xmlDataSource.hxx47
-rw-r--r--dbaccess/source/filter/xml/xmlDataSourceInfo.cxx119
-rw-r--r--dbaccess/source/filter/xml/xmlDataSourceInfo.hxx37
-rw-r--r--dbaccess/source/filter/xml/xmlDataSourceSetting.cxx215
-rw-r--r--dbaccess/source/filter/xml/xmlDataSourceSetting.hxx60
-rw-r--r--dbaccess/source/filter/xml/xmlDataSourceSettings.cxx66
-rw-r--r--dbaccess/source/filter/xml/xmlDataSourceSettings.hxx39
-rw-r--r--dbaccess/source/filter/xml/xmlDatabase.cxx135
-rw-r--r--dbaccess/source/filter/xml/xmlDatabase.hxx41
-rw-r--r--dbaccess/source/filter/xml/xmlDatabaseDescription.cxx79
-rw-r--r--dbaccess/source/filter/xml/xmlDatabaseDescription.hxx41
-rw-r--r--dbaccess/source/filter/xml/xmlDocuments.cxx99
-rw-r--r--dbaccess/source/filter/xml/xmlDocuments.hxx56
-rw-r--r--dbaccess/source/filter/xml/xmlEnums.hxx23
-rw-r--r--dbaccess/source/filter/xml/xmlExport.cxx1342
-rw-r--r--dbaccess/source/filter/xml/xmlExport.hxx176
-rw-r--r--dbaccess/source/filter/xml/xmlFileBasedDatabase.cxx113
-rw-r--r--dbaccess/source/filter/xml/xmlFileBasedDatabase.hxx36
-rw-r--r--dbaccess/source/filter/xml/xmlHelper.cxx157
-rw-r--r--dbaccess/source/filter/xml/xmlHelper.hxx57
-rw-r--r--dbaccess/source/filter/xml/xmlHierarchyCollection.cxx131
-rw-r--r--dbaccess/source/filter/xml/xmlHierarchyCollection.hxx55
-rw-r--r--dbaccess/source/filter/xml/xmlLogin.cxx111
-rw-r--r--dbaccess/source/filter/xml/xmlLogin.hxx37
-rw-r--r--dbaccess/source/filter/xml/xmlQuery.cxx117
-rw-r--r--dbaccess/source/filter/xml/xmlQuery.hxx46
-rw-r--r--dbaccess/source/filter/xml/xmlServerDatabase.cxx136
-rw-r--r--dbaccess/source/filter/xml/xmlServerDatabase.hxx36
-rw-r--r--dbaccess/source/filter/xml/xmlStyleImport.cxx263
-rw-r--r--dbaccess/source/filter/xml/xmlStyleImport.hxx98
-rw-r--r--dbaccess/source/filter/xml/xmlTable.cxx226
-rw-r--r--dbaccess/source/filter/xml/xmlTable.hxx67
-rw-r--r--dbaccess/source/filter/xml/xmlTableFilterList.cxx95
-rw-r--r--dbaccess/source/filter/xml/xmlTableFilterList.hxx64
-rw-r--r--dbaccess/source/filter/xml/xmlTableFilterPattern.cxx59
-rw-r--r--dbaccess/source/filter/xml/xmlTableFilterPattern.hxx44
-rw-r--r--dbaccess/source/filter/xml/xmlfilter.cxx617
-rw-r--r--dbaccess/source/filter/xml/xmlfilter.hxx121
-rw-r--r--dbaccess/source/inc/OAuthenticationContinuation.hxx67
-rw-r--r--dbaccess/source/inc/apitools.hxx52
-rw-r--r--dbaccess/source/inc/dsntypes.hxx218
-rw-r--r--dbaccess/source/inc/stringconstants.hxx171
-rw-r--r--dbaccess/source/sdbtools/connection/connectiontools.cxx132
-rw-r--r--dbaccess/source/sdbtools/connection/datasourcemetadata.cxx51
-rw-r--r--dbaccess/source/sdbtools/connection/datasourcemetadata.hxx69
-rw-r--r--dbaccess/source/sdbtools/connection/objectnames.cxx420
-rw-r--r--dbaccess/source/sdbtools/connection/objectnames.hxx74
-rw-r--r--dbaccess/source/sdbtools/connection/tablename.cxx232
-rw-r--r--dbaccess/source/sdbtools/connection/tablename.hxx84
-rw-r--r--dbaccess/source/sdbtools/inc/connectiondependent.hxx135
-rw-r--r--dbaccess/source/sdbtools/inc/connectiontools.hxx77
-rw-r--r--dbaccess/source/ui/app/AppController.cxx2834
-rw-r--r--dbaccess/source/ui/app/AppController.hxx540
-rw-r--r--dbaccess/source/ui/app/AppControllerDnD.cxx869
-rw-r--r--dbaccess/source/ui/app/AppControllerGen.cxx736
-rw-r--r--dbaccess/source/ui/app/AppDetailPageHelper.cxx1221
-rw-r--r--dbaccess/source/ui/app/AppDetailPageHelper.hxx349
-rw-r--r--dbaccess/source/ui/app/AppDetailView.cxx510
-rw-r--r--dbaccess/source/ui/app/AppDetailView.hxx318
-rw-r--r--dbaccess/source/ui/app/AppIconControl.cxx238
-rw-r--r--dbaccess/source/ui/app/AppIconControl.hxx67
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.cxx133
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.hxx88
-rw-r--r--dbaccess/source/ui/app/AppTitleWindow.cxx65
-rw-r--r--dbaccess/source/ui/app/AppTitleWindow.hxx67
-rw-r--r--dbaccess/source/ui/app/AppView.cxx473
-rw-r--r--dbaccess/source/ui/app/AppView.hxx302
-rw-r--r--dbaccess/source/ui/app/ChildWindow.cxx25
-rw-r--r--dbaccess/source/ui/app/DocumentInfoPreview.cxx164
-rw-r--r--dbaccess/source/ui/app/DocumentInfoPreview.hxx59
-rw-r--r--dbaccess/source/ui/app/subcomponentmanager.cxx551
-rw-r--r--dbaccess/source/ui/app/subcomponentmanager.hxx120
-rw-r--r--dbaccess/source/ui/app/templwin.cxx38
-rw-r--r--dbaccess/source/ui/app/templwin.hxx28
-rw-r--r--dbaccess/source/ui/app/window_layout.txt49
-rw-r--r--dbaccess/source/ui/browser/AsynchronousLink.cxx81
-rw-r--r--dbaccess/source/ui/browser/brwctrlr.cxx2616
-rw-r--r--dbaccess/source/ui/browser/brwview.cxx333
-rw-r--r--dbaccess/source/ui/browser/dataview.cxx154
-rw-r--r--dbaccess/source/ui/browser/dbexchange.cxx251
-rw-r--r--dbaccess/source/ui/browser/dbloader.cxx269
-rw-r--r--dbaccess/source/ui/browser/dbtreemodel.cxx33
-rw-r--r--dbaccess/source/ui/browser/dbtreemodel.hxx57
-rw-r--r--dbaccess/source/ui/browser/dsEntriesNoExp.cxx154
-rw-r--r--dbaccess/source/ui/browser/dsbrowserDnD.cxx258
-rw-r--r--dbaccess/source/ui/browser/exsrcbrw.cxx413
-rw-r--r--dbaccess/source/ui/browser/formadapter.cxx1877
-rw-r--r--dbaccess/source/ui/browser/genericcontroller.cxx1217
-rw-r--r--dbaccess/source/ui/browser/sbagrid.cxx1364
-rw-r--r--dbaccess/source/ui/browser/sbamultiplex.cxx528
-rw-r--r--dbaccess/source/ui/browser/unodatbr.cxx3819
-rw-r--r--dbaccess/source/ui/control/ColumnControlWindow.cxx182
-rw-r--r--dbaccess/source/ui/control/FieldControls.cxx60
-rw-r--r--dbaccess/source/ui/control/FieldDescControl.cxx1384
-rw-r--r--dbaccess/source/ui/control/RelationControl.cxx695
-rw-r--r--dbaccess/source/ui/control/SqlNameEdit.cxx85
-rw-r--r--dbaccess/source/ui/control/TableGrantCtrl.cxx476
-rw-r--r--dbaccess/source/ui/control/charsetlistbox.cxx69
-rw-r--r--dbaccess/source/ui/control/curledit.cxx89
-rw-r--r--dbaccess/source/ui/control/dbtreelistbox.cxx512
-rw-r--r--dbaccess/source/ui/control/opendoccontrols.cxx194
-rw-r--r--dbaccess/source/ui/control/sqledit.cxx515
-rw-r--r--dbaccess/source/ui/control/tabletree.cxx707
-rw-r--r--dbaccess/source/ui/control/undosqledit.cxx34
-rw-r--r--dbaccess/source/ui/dlg/CollectionView.cxx316
-rw-r--r--dbaccess/source/ui/dlg/ConnectionHelper.cxx720
-rw-r--r--dbaccess/source/ui/dlg/ConnectionHelper.hxx103
-rw-r--r--dbaccess/source/ui/dlg/ConnectionPage.cxx284
-rw-r--r--dbaccess/source/ui/dlg/ConnectionPage.hxx72
-rw-r--r--dbaccess/source/ui/dlg/ConnectionPageSetup.cxx153
-rw-r--r--dbaccess/source/ui/dlg/ConnectionPageSetup.hxx63
-rw-r--r--dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx786
-rw-r--r--dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx270
-rw-r--r--dbaccess/source/ui/dlg/DbAdminImpl.cxx1074
-rw-r--r--dbaccess/source/ui/dlg/DbAdminImpl.hxx167
-rw-r--r--dbaccess/source/ui/dlg/DriverSettings.hxx78
-rw-r--r--dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx60
-rw-r--r--dbaccess/source/ui/dlg/RelationDlg.cxx215
-rw-r--r--dbaccess/source/ui/dlg/TablesSingleDlg.cxx105
-rw-r--r--dbaccess/source/ui/dlg/TextConnectionHelper.cxx392
-rw-r--r--dbaccess/source/ui/dlg/TextConnectionHelper.hxx89
-rw-r--r--dbaccess/source/ui/dlg/UserAdmin.cxx316
-rw-r--r--dbaccess/source/ui/dlg/UserAdmin.hxx74
-rw-r--r--dbaccess/source/ui/dlg/UserAdminDlg.cxx162
-rw-r--r--dbaccess/source/ui/dlg/admincontrols.cxx201
-rw-r--r--dbaccess/source/ui/dlg/admincontrols.hxx65
-rw-r--r--dbaccess/source/ui/dlg/adminpages.cxx278
-rw-r--r--dbaccess/source/ui/dlg/adminpages.hxx233
-rw-r--r--dbaccess/source/ui/dlg/adodatalinks.cxx141
-rw-r--r--dbaccess/source/ui/dlg/adodatalinks.hxx26
-rw-r--r--dbaccess/source/ui/dlg/adtabdlg.cxx467
-rw-r--r--dbaccess/source/ui/dlg/advancedsettings.cxx472
-rw-r--r--dbaccess/source/ui/dlg/advancedsettings.hxx116
-rw-r--r--dbaccess/source/ui/dlg/dbadmin.cxx433
-rw-r--r--dbaccess/source/ui/dlg/dbfindex.cxx430
-rw-r--r--dbaccess/source/ui/dlg/dbfindex.hxx110
-rw-r--r--dbaccess/source/ui/dlg/dbwiz.cxx336
-rw-r--r--dbaccess/source/ui/dlg/dbwizsetup.cxx994
-rw-r--r--dbaccess/source/ui/dlg/detailpages.cxx717
-rw-r--r--dbaccess/source/ui/dlg/detailpages.hxx253
-rw-r--r--dbaccess/source/ui/dlg/directsql.cxx430
-rw-r--r--dbaccess/source/ui/dlg/dlgattr.cxx60
-rw-r--r--dbaccess/source/ui/dlg/dlgsave.cxx351
-rw-r--r--dbaccess/source/ui/dlg/dlgsize.cxx83
-rw-r--r--dbaccess/source/ui/dlg/dsnItem.hxx48
-rw-r--r--dbaccess/source/ui/dlg/dsselect.cxx133
-rw-r--r--dbaccess/source/ui/dlg/dsselect.hxx61
-rw-r--r--dbaccess/source/ui/dlg/finteraction.cxx59
-rw-r--r--dbaccess/source/ui/dlg/finteraction.hxx54
-rw-r--r--dbaccess/source/ui/dlg/generalpage.cxx700
-rw-r--r--dbaccess/source/ui/dlg/generalpage.hxx189
-rw-r--r--dbaccess/source/ui/dlg/indexdialog.cxx707
-rw-r--r--dbaccess/source/ui/dlg/indexfieldscontrol.cxx447
-rw-r--r--dbaccess/source/ui/dlg/odbcconfig.cxx325
-rw-r--r--dbaccess/source/ui/dlg/odbcconfig.hxx106
-rw-r--r--dbaccess/source/ui/dlg/optionalboolitem.cxx44
-rw-r--r--dbaccess/source/ui/dlg/optionalboolitem.hxx51
-rw-r--r--dbaccess/source/ui/dlg/paramdialog.cxx334
-rw-r--r--dbaccess/source/ui/dlg/queryfilter.cxx748
-rw-r--r--dbaccess/source/ui/dlg/queryorder.cxx218
-rw-r--r--dbaccess/source/ui/dlg/sqlmessage.cxx604
-rw-r--r--dbaccess/source/ui/dlg/tablespage.cxx488
-rw-r--r--dbaccess/source/ui/dlg/tablespage.hxx81
-rw-r--r--dbaccess/source/ui/dlg/textconnectionsettings.cxx69
-rw-r--r--dbaccess/source/ui/inc/AppElementType.hxx53
-rw-r--r--dbaccess/source/ui/inc/ChildWindow.hxx38
-rw-r--r--dbaccess/source/ui/inc/CollectionView.hxx65
-rw-r--r--dbaccess/source/ui/inc/ColumnControlWindow.hxx82
-rw-r--r--dbaccess/source/ui/inc/ConnectionLine.hxx71
-rw-r--r--dbaccess/source/ui/inc/ConnectionLineAccess.hxx91
-rw-r--r--dbaccess/source/ui/inc/ConnectionLineData.hxx80
-rw-r--r--dbaccess/source/ui/inc/DExport.hxx162
-rw-r--r--dbaccess/source/ui/inc/FieldControls.hxx120
-rw-r--r--dbaccess/source/ui/inc/FieldDescControl.hxx201
-rw-r--r--dbaccess/source/ui/inc/FieldDescriptions.hxx111
-rw-r--r--dbaccess/source/ui/inc/GeneralUndo.hxx40
-rw-r--r--dbaccess/source/ui/inc/HtmlReader.hxx68
-rw-r--r--dbaccess/source/ui/inc/IClipBoardTest.hxx40
-rw-r--r--dbaccess/source/ui/inc/IItemSetHelper.hxx72
-rw-r--r--dbaccess/source/ui/inc/IUpdateHelper.hxx44
-rw-r--r--dbaccess/source/ui/inc/JAccess.hxx70
-rw-r--r--dbaccess/source/ui/inc/JoinController.hxx154
-rw-r--r--dbaccess/source/ui/inc/JoinDesignView.hxx68
-rw-r--r--dbaccess/source/ui/inc/JoinExchange.hxx62
-rw-r--r--dbaccess/source/ui/inc/JoinTableView.hxx325
-rw-r--r--dbaccess/source/ui/inc/QEnumTypes.hxx79
-rw-r--r--dbaccess/source/ui/inc/QueryDesignView.hxx154
-rw-r--r--dbaccess/source/ui/inc/QueryPropertiesDialog.hxx45
-rw-r--r--dbaccess/source/ui/inc/QueryTableView.hxx116
-rw-r--r--dbaccess/source/ui/inc/QueryTextView.hxx69
-rw-r--r--dbaccess/source/ui/inc/QueryViewSwitch.hxx94
-rw-r--r--dbaccess/source/ui/inc/RTableConnectionData.hxx79
-rw-r--r--dbaccess/source/ui/inc/RelControliFace.hxx40
-rw-r--r--dbaccess/source/ui/inc/RelationControl.hxx91
-rw-r--r--dbaccess/source/ui/inc/RelationController.hxx79
-rw-r--r--dbaccess/source/ui/inc/RelationDesignView.hxx45
-rw-r--r--dbaccess/source/ui/inc/RelationDlg.hxx74
-rw-r--r--dbaccess/source/ui/inc/RelationTableView.hxx74
-rw-r--r--dbaccess/source/ui/inc/RtfReader.hxx59
-rw-r--r--dbaccess/source/ui/inc/SqlNameEdit.hxx121
-rw-r--r--dbaccess/source/ui/inc/TableConnection.hxx98
-rw-r--r--dbaccess/source/ui/inc/TableConnectionData.hxx101
-rw-r--r--dbaccess/source/ui/inc/TableController.hxx129
-rw-r--r--dbaccess/source/ui/inc/TableCopyHelper.hxx188
-rw-r--r--dbaccess/source/ui/inc/TableDesignControl.hxx78
-rw-r--r--dbaccess/source/ui/inc/TableDesignHelpBar.hxx59
-rw-r--r--dbaccess/source/ui/inc/TableDesignView.hxx112
-rw-r--r--dbaccess/source/ui/inc/TableFieldDescription.hxx150
-rw-r--r--dbaccess/source/ui/inc/TableGrantCtrl.hxx104
-rw-r--r--dbaccess/source/ui/inc/TableRow.hxx76
-rw-r--r--dbaccess/source/ui/inc/TableRowExchange.hxx40
-rw-r--r--dbaccess/source/ui/inc/TableWindow.hxx183
-rw-r--r--dbaccess/source/ui/inc/TableWindowAccess.hxx94
-rw-r--r--dbaccess/source/ui/inc/TableWindowData.hxx95
-rw-r--r--dbaccess/source/ui/inc/TableWindowListBox.hxx121
-rw-r--r--dbaccess/source/ui/inc/TableWindowTitle.hxx44
-rw-r--r--dbaccess/source/ui/inc/TablesSingleDlg.hxx71
-rw-r--r--dbaccess/source/ui/inc/TokenWriter.hxx206
-rw-r--r--dbaccess/source/ui/inc/TypeInfo.hxx121
-rw-r--r--dbaccess/source/ui/inc/UITools.hxx396
-rw-r--r--dbaccess/source/ui/inc/UserAdminDlg.hxx76
-rw-r--r--dbaccess/source/ui/inc/WCPage.hxx78
-rw-r--r--dbaccess/source/ui/inc/WColumnSelect.hxx82
-rw-r--r--dbaccess/source/ui/inc/WCopyTable.hxx413
-rw-r--r--dbaccess/source/ui/inc/WExtendPages.hxx69
-rw-r--r--dbaccess/source/ui/inc/WNameMatch.hxx63
-rw-r--r--dbaccess/source/ui/inc/WTabPage.hxx46
-rw-r--r--dbaccess/source/ui/inc/WTypeSelect.hxx139
-rw-r--r--dbaccess/source/ui/inc/adtabdlg.hxx98
-rw-r--r--dbaccess/source/ui/inc/advancedsettingsdlg.hxx70
-rw-r--r--dbaccess/source/ui/inc/asyncmodaldialog.hxx47
-rw-r--r--dbaccess/source/ui/inc/browserids.hxx98
-rw-r--r--dbaccess/source/ui/inc/brwctrlr.hxx332
-rw-r--r--dbaccess/source/ui/inc/brwview.hxx96
-rw-r--r--dbaccess/source/ui/inc/callbacks.hxx123
-rw-r--r--dbaccess/source/ui/inc/charsetlistbox.hxx48
-rw-r--r--dbaccess/source/ui/inc/charsets.hxx105
-rw-r--r--dbaccess/source/ui/inc/commontypes.hxx39
-rw-r--r--dbaccess/source/ui/inc/curledit.hxx102
-rw-r--r--dbaccess/source/ui/inc/databaseobjectview.hxx230
-rw-r--r--dbaccess/source/ui/inc/datasourceconnector.hxx76
-rw-r--r--dbaccess/source/ui/inc/dbadmin.hxx114
-rw-r--r--dbaccess/source/ui/inc/dbexchange.hxx83
-rw-r--r--dbaccess/source/ui/inc/dbtreelistbox.hxx164
-rw-r--r--dbaccess/source/ui/inc/dbu_dlg.hxx24
-rw-r--r--dbaccess/source/ui/inc/dbwiz.hxx101
-rw-r--r--dbaccess/source/ui/inc/dbwizsetup.hxx170
-rw-r--r--dbaccess/source/ui/inc/defaultobjectnamecheck.hxx120
-rw-r--r--dbaccess/source/ui/inc/directsql.hxx113
-rw-r--r--dbaccess/source/ui/inc/dlgattr.hxx41
-rw-r--r--dbaccess/source/ui/inc/dlgsave.hxx81
-rw-r--r--dbaccess/source/ui/inc/dlgsize.hxx44
-rw-r--r--dbaccess/source/ui/inc/dsitems.hxx95
-rw-r--r--dbaccess/source/ui/inc/dsmeta.hxx125
-rw-r--r--dbaccess/source/ui/inc/exsrcbrw.hxx96
-rw-r--r--dbaccess/source/ui/inc/formadapter.hxx436
-rw-r--r--dbaccess/source/ui/inc/imageprovider.hxx105
-rw-r--r--dbaccess/source/ui/inc/indexcollection.hxx94
-rw-r--r--dbaccess/source/ui/inc/indexdialog.hxx103
-rw-r--r--dbaccess/source/ui/inc/indexes.hxx81
-rw-r--r--dbaccess/source/ui/inc/indexfieldscontrol.hxx91
-rw-r--r--dbaccess/source/ui/inc/linkeddocuments.hxx108
-rw-r--r--dbaccess/source/ui/inc/objectnamecheck.hxx57
-rw-r--r--dbaccess/source/ui/inc/opendoccontrols.hxx78
-rw-r--r--dbaccess/source/ui/inc/paramdialog.hxx103
-rw-r--r--dbaccess/source/ui/inc/propertystorage.hxx54
-rw-r--r--dbaccess/source/ui/inc/querycontainerwindow.hxx104
-rw-r--r--dbaccess/source/ui/inc/querycontroller.hxx217
-rw-r--r--dbaccess/source/ui/inc/queryfilter.hxx109
-rw-r--r--dbaccess/source/ui/inc/queryorder.hxx81
-rw-r--r--dbaccess/source/ui/inc/sbagrid.hrc37
-rw-r--r--dbaccess/source/ui/inc/sbagrid.hxx293
-rw-r--r--dbaccess/source/ui/inc/sbamultiplex.hxx308
-rw-r--r--dbaccess/source/ui/inc/singledoccontroller.hxx78
-rw-r--r--dbaccess/source/ui/inc/sqledit.hxx99
-rw-r--r--dbaccess/source/ui/inc/sqlmessage.hxx145
-rw-r--r--dbaccess/source/ui/inc/stringlistitem.hxx48
-rw-r--r--dbaccess/source/ui/inc/tabletree.hxx155
-rw-r--r--dbaccess/source/ui/inc/textconnectionsettings.hxx59
-rw-r--r--dbaccess/source/ui/inc/undosqledit.hxx45
-rw-r--r--dbaccess/source/ui/inc/unoadmin.hxx59
-rw-r--r--dbaccess/source/ui/inc/unodatbr.hxx447
-rw-r--r--dbaccess/source/ui/inc/unosqlmessage.hxx68
-rw-r--r--dbaccess/source/ui/misc/DExport.cxx840
-rw-r--r--dbaccess/source/ui/misc/HtmlReader.cxx481
-rw-r--r--dbaccess/source/ui/misc/RowSetDrop.cxx247
-rw-r--r--dbaccess/source/ui/misc/RtfReader.cxx309
-rw-r--r--dbaccess/source/ui/misc/TableCopyHelper.cxx306
-rw-r--r--dbaccess/source/ui/misc/TokenWriter.cxx965
-rw-r--r--dbaccess/source/ui/misc/UITools.cxx1370
-rw-r--r--dbaccess/source/ui/misc/UpdateHelperImpl.hxx74
-rw-r--r--dbaccess/source/ui/misc/WCPage.cxx325
-rw-r--r--dbaccess/source/ui/misc/WColumnSelect.cxx403
-rw-r--r--dbaccess/source/ui/misc/WCopyTable.cxx1554
-rw-r--r--dbaccess/source/ui/misc/WExtendPages.cxx62
-rw-r--r--dbaccess/source/ui/misc/WNameMatch.cxx330
-rw-r--r--dbaccess/source/ui/misc/WTypeSelect.cxx417
-rw-r--r--dbaccess/source/ui/misc/asyncmodaldialog.cxx91
-rw-r--r--dbaccess/source/ui/misc/charsets.cxx130
-rw-r--r--dbaccess/source/ui/misc/controllerframe.cxx390
-rw-r--r--dbaccess/source/ui/misc/databaseobjectview.cxx280
-rw-r--r--dbaccess/source/ui/misc/datasourceconnector.cxx202
-rw-r--r--dbaccess/source/ui/misc/dbaundomanager.cxx324
-rw-r--r--dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx606
-rw-r--r--dbaccess/source/ui/misc/defaultobjectnamecheck.cxx160
-rw-r--r--dbaccess/source/ui/misc/dsmeta.cxx182
-rw-r--r--dbaccess/source/ui/misc/imageprovider.cxx202
-rw-r--r--dbaccess/source/ui/misc/indexcollection.cxx328
-rw-r--r--dbaccess/source/ui/misc/linkeddocuments.cxx354
-rw-r--r--dbaccess/source/ui/misc/propertystorage.cxx106
-rw-r--r--dbaccess/source/ui/misc/singledoccontroller.cxx184
-rw-r--r--dbaccess/source/ui/misc/stringlistitem.cxx62
-rw-r--r--dbaccess/source/ui/querydesign/ConnectionLine.cxx356
-rw-r--r--dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx187
-rw-r--r--dbaccess/source/ui/querydesign/ConnectionLineData.cxx76
-rw-r--r--dbaccess/source/ui/querydesign/JAccess.cxx91
-rw-r--r--dbaccess/source/ui/querydesign/JoinController.cxx406
-rw-r--r--dbaccess/source/ui/querydesign/JoinDesignView.cxx100
-rw-r--r--dbaccess/source/ui/querydesign/JoinExchange.cxx114
-rw-r--r--dbaccess/source/ui/querydesign/JoinTableView.cxx1568
-rw-r--r--dbaccess/source/ui/querydesign/QTableConnection.cxx73
-rw-r--r--dbaccess/source/ui/querydesign/QTableConnection.hxx46
-rw-r--r--dbaccess/source/ui/querydesign/QTableConnectionData.cxx112
-rw-r--r--dbaccess/source/ui/querydesign/QTableConnectionData.hxx67
-rw-r--r--dbaccess/source/ui/querydesign/QTableWindow.cxx175
-rw-r--r--dbaccess/source/ui/querydesign/QTableWindow.hxx76
-rw-r--r--dbaccess/source/ui/querydesign/QTableWindowData.cxx34
-rw-r--r--dbaccess/source/ui/querydesign/QTableWindowData.hxx38
-rw-r--r--dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx49
-rw-r--r--dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx138
-rw-r--r--dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx39
-rw-r--r--dbaccess/source/ui/querydesign/QueryDesignView.cxx3441
-rw-r--r--dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx40
-rw-r--r--dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx54
-rw-r--r--dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx70
-rw-r--r--dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx117
-rw-r--r--dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx50
-rw-r--r--dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx51
-rw-r--r--dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx112
-rw-r--r--dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx61
-rw-r--r--dbaccess/source/ui/querydesign/QueryTableView.cxx889
-rw-r--r--dbaccess/source/ui/querydesign/QueryTextView.cxx177
-rw-r--r--dbaccess/source/ui/querydesign/QueryViewSwitch.cxx292
-rw-r--r--dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx2720
-rw-r--r--dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx324
-rw-r--r--dbaccess/source/ui/querydesign/TableConnection.cxx190
-rw-r--r--dbaccess/source/ui/querydesign/TableConnectionData.cxx147
-rw-r--r--dbaccess/source/ui/querydesign/TableFieldDescription.cxx196
-rw-r--r--dbaccess/source/ui/querydesign/TableFieldInfo.cxx30
-rw-r--r--dbaccess/source/ui/querydesign/TableFieldInfo.hxx43
-rw-r--r--dbaccess/source/ui/querydesign/TableWindow.cxx716
-rw-r--r--dbaccess/source/ui/querydesign/TableWindowAccess.cxx250
-rw-r--r--dbaccess/source/ui/querydesign/TableWindowData.cxx135
-rw-r--r--dbaccess/source/ui/querydesign/TableWindowListBox.cxx292
-rw-r--r--dbaccess/source/ui/querydesign/TableWindowTitle.cxx97
-rw-r--r--dbaccess/source/ui/querydesign/class.jpgbin0 -> 224242 bytes
-rw-r--r--dbaccess/source/ui/querydesign/limitboxcontroller.cxx322
-rw-r--r--dbaccess/source/ui/querydesign/limitboxcontroller.hxx65
-rw-r--r--dbaccess/source/ui/querydesign/querycontainerwindow.cxx222
-rw-r--r--dbaccess/source/ui/querydesign/querycontroller.cxx1790
-rw-r--r--dbaccess/source/ui/querydesign/querydlg.cxx313
-rw-r--r--dbaccess/source/ui/querydesign/querydlg.hxx77
-rw-r--r--dbaccess/source/ui/relationdesign/RTableConnection.cxx117
-rw-r--r--dbaccess/source/ui/relationdesign/RTableConnection.hxx40
-rw-r--r--dbaccess/source/ui/relationdesign/RTableConnectionData.cxx398
-rw-r--r--dbaccess/source/ui/relationdesign/RTableWindow.hxx40
-rw-r--r--dbaccess/source/ui/relationdesign/RelationController.cxx548
-rw-r--r--dbaccess/source/ui/relationdesign/RelationDesignView.cxx74
-rw-r--r--dbaccess/source/ui/relationdesign/RelationTableView.cxx410
-rw-r--r--dbaccess/source/ui/tabledesign/FieldDescriptions.cxx639
-rw-r--r--dbaccess/source/ui/tabledesign/TEditControl.cxx1679
-rw-r--r--dbaccess/source/ui/tabledesign/TEditControl.hxx204
-rw-r--r--dbaccess/source/ui/tabledesign/TableController.cxx1495
-rw-r--r--dbaccess/source/ui/tabledesign/TableDesignControl.cxx172
-rw-r--r--dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx62
-rw-r--r--dbaccess/source/ui/tabledesign/TableDesignView.cxx260
-rw-r--r--dbaccess/source/ui/tabledesign/TableFieldControl.cxx154
-rw-r--r--dbaccess/source/ui/tabledesign/TableFieldControl.hxx66
-rw-r--r--dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx140
-rw-r--r--dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx91
-rw-r--r--dbaccess/source/ui/tabledesign/TableRow.cxx183
-rw-r--r--dbaccess/source/ui/tabledesign/TableRowExchange.cxx67
-rw-r--r--dbaccess/source/ui/tabledesign/TableUndo.cxx352
-rw-r--r--dbaccess/source/ui/tabledesign/TableUndo.hxx136
-rw-r--r--dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx117
-rw-r--r--dbaccess/source/ui/uno/ColumnControl.cxx146
-rw-r--r--dbaccess/source/ui/uno/ColumnControl.hxx46
-rw-r--r--dbaccess/source/ui/uno/ColumnModel.cxx180
-rw-r--r--dbaccess/source/ui/uno/ColumnModel.hxx97
-rw-r--r--dbaccess/source/ui/uno/ColumnPeer.cxx148
-rw-r--r--dbaccess/source/ui/uno/ColumnPeer.hxx47
-rw-r--r--dbaccess/source/ui/uno/DBTypeWizDlg.cxx85
-rw-r--r--dbaccess/source/ui/uno/DBTypeWizDlg.hxx56
-rw-r--r--dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx104
-rw-r--r--dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx59
-rw-r--r--dbaccess/source/ui/uno/TableFilterDlg.cxx85
-rw-r--r--dbaccess/source/ui/uno/TableFilterDlg.hxx57
-rw-r--r--dbaccess/source/ui/uno/UserSettingsDlg.cxx85
-rw-r--r--dbaccess/source/ui/uno/UserSettingsDlg.hxx57
-rw-r--r--dbaccess/source/ui/uno/admindlg.cxx92
-rw-r--r--dbaccess/source/ui/uno/admindlg.hxx56
-rw-r--r--dbaccess/source/ui/uno/composerdialogs.cxx270
-rw-r--r--dbaccess/source/ui/uno/composerdialogs.hxx123
-rw-r--r--dbaccess/source/ui/uno/copytablewizard.cxx1579
-rw-r--r--dbaccess/source/ui/uno/dbinteraction.cxx387
-rw-r--r--dbaccess/source/ui/uno/dbinteraction.hxx168
-rw-r--r--dbaccess/source/ui/uno/textconnectionsettings_uno.cxx268
-rw-r--r--dbaccess/source/ui/uno/unoDirectSql.cxx149
-rw-r--r--dbaccess/source/ui/uno/unoDirectSql.hxx61
-rw-r--r--dbaccess/source/ui/uno/unoadmin.cxx71
-rw-r--r--dbaccess/source/ui/uno/unosqlmessage.cxx144
597 files changed, 158750 insertions, 0 deletions
diff --git a/dbaccess/source/core/api/BookmarkSet.cxx b/dbaccess/source/core/api/BookmarkSet.cxx
new file mode 100644
index 000000000..75dfc24f5
--- /dev/null
+++ b/dbaccess/source/core/api/BookmarkSet.cxx
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "BookmarkSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <connectivity/dbexception.hxx>
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::osl;
+
+void OBookmarkSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+ m_xRowLocate.set(_xDriverSet,UNO_QUERY);
+}
+
+void OBookmarkSet::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ construct(_xDriverSet, m_sRowSetFilter);
+}
+
+Any OBookmarkSet::getBookmark()
+{
+ return m_xRowLocate->getBookmark();
+}
+
+bool OBookmarkSet::moveToBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->moveToBookmark(bookmark);
+}
+
+sal_Int32 OBookmarkSet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ return m_xRowLocate->compareBookmarks(_first,_second);
+}
+
+bool OBookmarkSet::hasOrderedBookmarks( )
+{
+ return m_xRowLocate->hasOrderedBookmarks();
+}
+
+sal_Int32 OBookmarkSet::hashBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->hashBookmark(bookmark);
+}
+
+void OBookmarkSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ Reference<XRowUpdate> xUpdRow(m_xRowLocate,UNO_QUERY);
+ if(!xUpdRow.is())
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XROWUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+
+ Reference<XResultSetUpdate> xUpd(m_xRowLocate,UNO_QUERY);
+ if(xUpd.is())
+ {
+ xUpd->moveToInsertRow();
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setSigned(m_aSignedFlags[i-1]);
+ updateColumn(i,xUpdRow,*aIter);
+ }
+ xUpd->insertRow();
+ (*_rInsertRow->begin()) = m_xRowLocate->getBookmark();
+ }
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XRESULTSETUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+}
+
+void OBookmarkSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ Reference<XRowUpdate> xUpdRow(m_xRowLocate,UNO_QUERY);
+ if(!xUpdRow.is())
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XROWUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOriginalRow->begin()+1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
+ {
+ aIter->setSigned(aOrgIter->isSigned());
+ updateColumn(i,xUpdRow,*aIter);
+ }
+
+
+ Reference<XResultSetUpdate> xUpd(m_xRowLocate,UNO_QUERY);
+ if(xUpd.is())
+ xUpd->updateRow();
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XRESULTSETUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+}
+
+void OBookmarkSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ Reference<XResultSetUpdate> xUpd(m_xRowLocate,UNO_QUERY);
+
+ xUpd->deleteRow();
+}
+
+void OBookmarkSet::updateColumn(sal_Int32 nPos, const Reference< XRowUpdate >& _xParameter, const ORowSetValue& _rValue)
+{
+ if(!(_rValue.isBound() && _rValue.isModified()))
+ return;
+
+ if(_rValue.isNull())
+ _xParameter->updateNull(nPos);
+ else
+ {
+
+ switch(_rValue.getTypeKind())
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIGINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ else
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _xParameter->updateBoolean(nPos,_rValue.getBool());
+ break;
+ case DataType::TINYINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateByte(nPos,_rValue.getInt8());
+ else
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ break;
+ case DataType::SMALLINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ else
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ break;
+ case DataType::INTEGER:
+ if ( _rValue.isSigned() )
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ else
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ break;
+ case DataType::FLOAT:
+ _xParameter->updateFloat(nPos,_rValue.getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ _xParameter->updateDouble(nPos,_rValue.getDouble());
+ break;
+ case DataType::DATE:
+ _xParameter->updateDate(nPos,_rValue.getDate());
+ break;
+ case DataType::TIME:
+ _xParameter->updateTime(nPos,_rValue.getTime());
+ break;
+ case DataType::TIMESTAMP:
+ _xParameter->updateTimestamp(nPos,_rValue.getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ _xParameter->updateBytes(nPos,_rValue.getSequence());
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ _xParameter->updateObject(nPos,_rValue.getAny());
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/BookmarkSet.hxx b/dbaccess/source/core/api/BookmarkSet.hxx
new file mode 100644
index 000000000..9863a80ec
--- /dev/null
+++ b/dbaccess/source/core/api/BookmarkSet.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+
+namespace dbaccess
+{
+ // this set is used when we have a bookmarkable set from the driver
+ class OBookmarkSet : public OCacheSet
+ {
+ css::uno::Reference< css::sdbcx::XRowLocate> m_xRowLocate;
+
+ void updateColumn(sal_Int32 nPos, const css::uno::Reference< css::sdbc::XRowUpdate >& _xParameter, const connectivity::ORowSetValue& _rValue);
+ public:
+ explicit OBookmarkSet(sal_Int32 i_nMaxRows) : OCacheSet(i_nMaxRows)
+ {}
+ virtual ~OBookmarkSet() override
+ {
+ m_xRowLocate = nullptr;
+ }
+
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual bool hasOrderedBookmarks( ) override;
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+ // css::sdbc::XResultSetUpdate
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CIndexes.cxx b/dbaccess/source/core/api/CIndexes.cxx
new file mode 100644
index 000000000..409d87728
--- /dev/null
+++ b/dbaccess/source/core/api/CIndexes.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CIndexes.hxx"
+
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace dbaccess;
+using namespace cppu;
+
+
+ObjectType OIndexes::createObject(const OUString& _rName)
+{
+ ObjectType xRet;
+ if ( m_xIndexes.is() && m_xIndexes->hasByName(_rName) )
+ xRet.set(m_xIndexes->getByName(_rName),UNO_QUERY);
+ else
+ xRet = OIndexesHelper::createObject(_rName);
+
+ return xRet;
+}
+
+Reference< XPropertySet > OIndexes::createDescriptor()
+{
+ Reference<XDataDescriptorFactory> xData( m_xIndexes,UNO_QUERY);
+ if(xData.is())
+ return xData->createDataDescriptor();
+ else
+ return OIndexesHelper::createDescriptor();
+}
+
+// XAppend
+ObjectType OIndexes::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ Reference<XAppend> xData( m_xIndexes,UNO_QUERY);
+ if ( !xData.is() )
+ return OIndexesHelper::appendObject( _rForName, descriptor );
+
+ xData->appendByDescriptor(descriptor);
+ return createObject( _rForName );
+}
+
+// XDrop
+void OIndexes::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ if ( m_xIndexes.is() )
+ {
+ Reference<XDrop> xData( m_xIndexes,UNO_QUERY);
+ if ( xData.is() )
+ xData->dropByName(_sElementName);
+ }
+ else
+ OIndexesHelper::dropObject(_nPos,_sElementName);
+}
+
+void OIndexes::disposing()
+{
+ if ( m_xIndexes.is() )
+ clear_NoDispose();
+ else
+ OIndexesHelper::disposing();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CIndexes.hxx b/dbaccess/source/core/api/CIndexes.hxx
new file mode 100644
index 000000000..f20da6cbe
--- /dev/null
+++ b/dbaccess/source/core/api/CIndexes.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/TIndexes.hxx>
+
+namespace dbaccess
+{
+ class OIndexes : public connectivity::OIndexesHelper
+ {
+ css::uno::Reference< css::container::XNameAccess > m_xIndexes;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ OIndexes(connectivity::OTableHelper* _pTable,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector,
+ const css::uno::Reference< css::container::XNameAccess >& _rxIndexes
+ ) : connectivity::OIndexesHelper(_pTable,_rMutex,_rVector)
+ ,m_xIndexes(_rxIndexes)
+ {}
+
+ virtual void disposing() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetColumn.cxx b/dbaccess/source/core/api/CRowSetColumn.cxx
new file mode 100644
index 000000000..98435b7c4
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetColumn.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include "CRowSetColumn.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+
+namespace dbaccess
+{
+
+ORowSetColumn::ORowSetColumn( const Reference < XResultSetMetaData >& _xMetaData,
+ const Reference < XRow >& _xRow, sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> &_getValue )
+ :ORowSetDataColumn( _xMetaData, _xRow, nullptr, _nPos, _rxDBMeta, _rDescription, i_sLabel, _getValue )
+{
+}
+
+::cppu::IPropertyArrayHelper* ORowSetColumn::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property> aDescriptor
+ {
+ { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_VALUE, PROPERTY_ID_VALUE, cppu::UnoType<Any>::get(), css::beans::PropertyAttribute::READONLY | css::beans::PropertyAttribute::BOUND}
+ };
+
+ Sequence< Property > aRegisteredProperties;
+ describeProperties( aRegisteredProperties );
+
+ return new ::cppu::OPropertyArrayHelper( ::comphelper::concatSequences( aDescriptor, aRegisteredProperties ), false );
+}
+
+::cppu::IPropertyArrayHelper& ORowSetColumn::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< ORowSetColumn >* >(this)->getArrayHelper();
+}
+
+void SAL_CALL ORowSetColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue )
+{
+ OSL_ENSURE( nHandle != PROPERTY_ID_VALUE, "ORowSetColumn::setFastPropertyValue_NoBroadcast: hmm? This property is marked as READONLY!" );
+ if ( nHandle != PROPERTY_ID_VALUE )
+ ORowSetDataColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetColumn.hxx b/dbaccess/source/core/api/CRowSetColumn.hxx
new file mode 100644
index 000000000..bc0ae7eed
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetColumn.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "RowSetRow.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include "CRowSetDataColumn.hxx"
+
+namespace dbaccess
+{
+ class ORowSetColumn;
+ class ORowSetColumn :public ORowSetDataColumn
+ ,public ::comphelper::OPropertyArrayUsageHelper< ORowSetColumn >
+
+ {
+ public:
+ ORowSetColumn( const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ const css::uno::Reference < css::sdbc::XRow >& _xRow,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> &_getValue);
+
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,const css::uno::Any& rValue ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetDataColumn.cxx b/dbaccess/source/core/api/CRowSetDataColumn.cxx
new file mode 100644
index 000000000..0dce91848
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetDataColumn.cxx
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "CRowSetDataColumn.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using namespace dbaccess;
+using namespace comphelper;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace cppu;
+using namespace osl;
+
+
+ORowSetDataColumn::ORowSetDataColumn( const Reference < XResultSetMetaData >& _xMetaData,
+ const Reference < XRow >& _xRow,
+ const Reference < XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ORowSetValue& (sal_Int32)> &_getValue)
+ :ODataColumn(_xMetaData,_xRow,_xRowUpdate,_nPos,_rxDBMeta)
+ ,m_pGetValue(_getValue)
+ ,m_sLabel(i_sLabel)
+ ,m_aDescription(_rDescription)
+{
+ OColumnSettings::registerProperties( *this );
+ registerProperty( PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, PropertyAttribute::READONLY, &m_aDescription, cppu::UnoType<decltype(m_aDescription)>::get() );
+}
+
+ORowSetDataColumn::~ORowSetDataColumn()
+{
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSetDataColumn::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property> aDescriptor
+ {
+ { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_VALUE, PROPERTY_ID_VALUE, cppu::UnoType<Any>::get(), css::beans::PropertyAttribute::BOUND }
+ };
+
+ Sequence< Property > aRegisteredProperties;
+ describeProperties( aRegisteredProperties );
+
+ return new ::cppu::OPropertyArrayHelper( ::comphelper::concatSequences( aDescriptor, aRegisteredProperties ), false );
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& ORowSetDataColumn::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< ORowSetDataColumn >* >(this)->getArrayHelper();
+}
+
+void SAL_CALL ORowSetDataColumn::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ if ( PROPERTY_ID_VALUE == nHandle )
+ {
+ try
+ {
+ rValue = m_pGetValue(m_nPos).makeAny();
+ }
+ catch(const SQLException &e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw WrappedTargetRuntimeException("Could not retrieve column value: " + e.Message,
+ *const_cast<ORowSetDataColumn*>(this),
+ anyEx);
+ }
+ }
+ else if ( PROPERTY_ID_LABEL == nHandle && !m_sLabel.isEmpty() )
+ rValue <<= m_sLabel;
+ else
+ ODataColumn::getFastPropertyValue( rValue, nHandle );
+}
+
+void SAL_CALL ORowSetDataColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue )
+{
+ switch( nHandle )
+ {
+ case PROPERTY_ID_VALUE:
+ updateObject(rValue);
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ {
+ bool bVal = false;
+ rValue >>= bVal;
+ m_isReadOnly = bVal;
+ }
+ break;
+ default:
+ ODataColumn::setFastPropertyValue_NoBroadcast( nHandle,rValue );
+ break;
+ }
+}
+
+sal_Bool SAL_CALL ORowSetDataColumn::convertFastPropertyValue( Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bModified = false;
+ switch( nHandle )
+ {
+ case PROPERTY_ID_VALUE:
+ {
+ rConvertedValue = rValue;
+ getFastPropertyValue(rOldValue, PROPERTY_ID_VALUE);
+ bModified = rConvertedValue != rOldValue;
+ }
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ {
+ rConvertedValue = rValue;
+ getFastPropertyValue(rOldValue, PROPERTY_ID_ISREADONLY);
+ bModified = rConvertedValue != rOldValue;
+ }
+ break;
+ default:
+ bModified = ODataColumn::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
+ break;
+ }
+
+ return bModified;
+}
+
+Sequence< sal_Int8 > ORowSetDataColumn::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void ORowSetDataColumn::fireValueChange(const ORowSetValue& _rOldValue)
+{
+ const ORowSetValue &value(m_pGetValue(m_nPos));
+ if ( value != _rOldValue)
+ {
+ sal_Int32 nHandle(PROPERTY_ID_VALUE);
+ m_aOldValue = _rOldValue.makeAny();
+ Any aNew = value.makeAny();
+
+ fire(&nHandle, &aNew, &m_aOldValue, 1, false );
+ }
+}
+
+ORowSetDataColumns::ORowSetDataColumns(
+ bool _bCase,
+ const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector
+ ) : connectivity::sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aColumns(_rColumns)
+{
+}
+
+ORowSetDataColumns::~ORowSetDataColumns()
+{
+}
+
+sdbcx::ObjectType ORowSetDataColumns::createObject(const OUString& _rName)
+{
+ connectivity::sdbcx::ObjectType xNamed;
+
+ ::comphelper::UStringMixEqual aCase(isCaseSensitive());
+ ::connectivity::OSQLColumns::Vector::const_iterator first = ::connectivity::find(m_aColumns->begin(),m_aColumns->end(),_rName,aCase);
+ if(first != m_aColumns->end())
+ xNamed = *first;
+
+ return xNamed;
+}
+
+void ORowSetDataColumns::disposing()
+{
+ ORowSetDataColumns_BASE::disposing();
+ m_aColumns = nullptr;
+}
+
+void ORowSetDataColumns::assign(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,const std::vector< OUString> &_rVector)
+{
+ m_aColumns = _rColumns;
+ reFill(_rVector);
+}
+
+void ORowSetDataColumns::impl_refresh()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetDataColumn.hxx b/dbaccess/source/core/api/CRowSetDataColumn.hxx
new file mode 100644
index 000000000..f0efcbf8d
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetDataColumn.hxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "datacolumn.hxx"
+#include "RowSetRow.hxx"
+#include <columnsettings.hxx>
+
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/proparrhlp.hxx>
+
+#include <functional>
+
+namespace dbaccess
+{
+ class ORowSetDataColumn;
+ typedef ::comphelper::OPropertyArrayUsageHelper<ORowSetDataColumn> ORowSetDataColumn_PROP;
+
+ class ORowSetDataColumn : public ODataColumn,
+ public OColumnSettings,
+ public ORowSetDataColumn_PROP
+ {
+ protected:
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> m_pGetValue;
+ css::uno::Any m_aOldValue;
+ OUString m_sLabel;
+ OUString m_aDescription; // description
+
+ virtual ~ORowSetDataColumn() override;
+ public:
+ ORowSetDataColumn(const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ const css::uno::Reference < css::sdbc::XRow >& _xRow,
+ const css::uno::Reference < css::sdbc::XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> &_getValue);
+
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue ) override;
+
+ void fireValueChange(const ::connectivity::ORowSetValue& _rOldValue);
+ protected:
+ using ODataColumn::getFastPropertyValue;
+ };
+
+ typedef connectivity::sdbcx::OCollection ORowSetDataColumns_BASE;
+ class ORowSetDataColumns : public ORowSetDataColumns_BASE
+ {
+ ::rtl::Reference< ::connectivity::OSQLColumns> m_aColumns;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ public:
+ ORowSetDataColumns(
+ bool _bCase,
+ const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector
+ );
+ virtual ~ORowSetDataColumns() override;
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+ void assign(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,const std::vector< OUString> &_rVector);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CacheSet.cxx b/dbaccess/source/core/api/CacheSet.cxx
new file mode 100644
index 000000000..9774877e6
--- /dev/null
+++ b/dbaccess/source/core/api/CacheSet.cxx
@@ -0,0 +1,580 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CacheSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+using namespace comphelper;
+
+using namespace dbaccess;
+using namespace dbtools;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::io;
+using namespace ::osl;
+
+
+OCacheSet::OCacheSet(sal_Int32 i_nMaxRows)
+ :m_nMaxRows(i_nMaxRows)
+ ,m_bInserted(false)
+ ,m_bUpdated(false)
+ ,m_bDeleted(false)
+{
+
+}
+
+OUString OCacheSet::getIdentifierQuoteString() const
+{
+ OUString sQuote;
+ if ( m_xConnection.is() )
+ if (auto xMeta = m_xConnection->getMetaData())
+ sQuote = xMeta->getIdentifierQuoteString();
+ return sQuote;
+}
+
+void OCacheSet::construct( const Reference< XResultSet>& _xDriverSet,const OUString &i_sRowSetFilter)
+{
+ OSL_ENSURE(_xDriverSet.is(),"Invalid resultSet");
+
+ m_sRowSetFilter = i_sRowSetFilter;
+
+ if(!_xDriverSet.is())
+ return;
+
+ m_xDriverSet = _xDriverSet;
+ m_xDriverRow.set(_xDriverSet,UNO_QUERY);
+ m_xSetMetaData = Reference<XResultSetMetaDataSupplier>(_xDriverSet,UNO_QUERY_THROW)->getMetaData();
+ if ( m_xSetMetaData.is() )
+ {
+ const sal_Int32 nCount = m_xSetMetaData->getColumnCount();
+ m_aNullable.resize(nCount);
+ m_aSignedFlags.resize(nCount);
+ m_aColumnTypes.resize(nCount);
+ auto pNullableIter = m_aNullable.begin();
+ auto pSignedIter = m_aSignedFlags.begin();
+ auto pColumnIter = m_aColumnTypes.begin();
+ for (sal_Int32 i=1; i <= nCount; ++i,++pSignedIter,++pColumnIter,++pNullableIter)
+ {
+ *pNullableIter = m_xSetMetaData->isNullable(i) != ColumnValue::NO_NULLS;
+ *pSignedIter = m_xSetMetaData->isSigned(i);
+ *pColumnIter = m_xSetMetaData->getColumnType(i);
+ }
+ }
+ Reference< XStatement> xStmt(m_xDriverSet->getStatement(),UNO_QUERY);
+ if(xStmt.is())
+ m_xConnection = xStmt->getConnection();
+ else
+ {
+ Reference< XPreparedStatement> xPrepStmt(m_xDriverSet->getStatement(),UNO_QUERY);
+ if ( xPrepStmt.is() )
+ m_xConnection = xPrepStmt->getConnection();
+ }
+}
+
+OCacheSet::~OCacheSet()
+{
+ try
+ {
+ m_xDriverSet = nullptr;
+ m_xDriverRow = nullptr;
+ m_xSetMetaData = nullptr;
+ m_xConnection = nullptr;
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "");
+ }
+ catch(...)
+ {
+ SAL_WARN("dbaccess", "Unknown Exception occurred");
+ }
+
+}
+
+void OCacheSet::fillTableName(const Reference<XPropertySet>& _xTable)
+{
+ OSL_ENSURE(_xTable.is(),"OCacheSet::fillTableName: PropertySet is empty!");
+ if(m_aComposedTableName.isEmpty() && _xTable.is() )
+ {
+ Reference<XDatabaseMetaData> xMeta(m_xConnection->getMetaData());
+ m_aComposedTableName = composeTableName(xMeta
+ ,comphelper::getString(_xTable->getPropertyValue(PROPERTY_CATALOGNAME))
+ ,comphelper::getString(_xTable->getPropertyValue(PROPERTY_SCHEMANAME))
+ ,comphelper::getString(_xTable->getPropertyValue(PROPERTY_NAME))
+ ,true
+ ,::dbtools::EComposeRule::InDataManipulation);
+ }
+}
+
+void OCacheSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("INSERT INTO " + m_aComposedTableName + " ( ");
+
+ // set values and column names
+ OUStringBuffer aValues(" VALUES ( ");
+ OUString aQuote = getIdentifierQuoteString();
+ sal_Int32 i = 1;
+ ORowVector< ORowSetValue >::Vector::const_iterator aIter = _rInsertRow->begin()+1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(; aIter != aEnd;++aIter)
+ {
+ aSql.append(::dbtools::quoteName( aQuote,m_xSetMetaData->getColumnName(i++)) + ",");
+ aValues.append("?,");
+ }
+
+ aSql[aSql.getLength() - 1] = ')';
+ aValues[aValues.getLength() - 1] = ')';
+
+ aSql.append(aValues);
+ // now create end execute the prepared statement
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ i = 1;
+ for(aIter = _rInsertRow->begin()+1; aIter != aEnd;++aIter,++i)
+ {
+ if(aIter->isNull())
+ xParameter->setNull(i,aIter->getTypeKind());
+ else
+ setParameter(i,xParameter,*aIter,m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ }
+
+ m_bInserted = xPrep->executeUpdate() > 0;
+ }
+
+ // TODO set the bookmark in the insert row
+}
+
+void OCacheSet::fillParameters( const ORowSetRow& _rRow
+ ,const connectivity::OSQLTable& _xTable
+ ,OUStringBuffer& _sCondition
+ ,OUStringBuffer& _sParameter
+ ,std::vector< sal_Int32>& _rOrgValues)
+{
+ // use keys and indexes for exact positioning
+ // first the keys
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xSet);
+ // second the indexes
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if(xIndexSup.is())
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ Reference<XPropertySet> xIndexColsSup;
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ if(xIndexes.is())
+ {
+ for(sal_Int32 j=0;j<xIndexes->getCount();++j)
+ {
+ xIndexColsSup.set(xIndexes->getByIndex(j),UNO_QUERY);
+ if( xIndexColsSup.is()
+ && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE))
+ && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX))
+ )
+ aAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY_THROW)->getColumns());
+ }
+ }
+
+ OUString aColumnName;
+
+ static const char aAnd[] = " AND ";
+
+ OUString aQuote = getIdentifierQuoteString();
+
+ sal_Int32 nCheckCount = 1; // index for the original values
+ sal_Int32 i = 1;
+
+ OUString sIsNull(" IS NULL");
+ OUString sParam(" = ?");
+ ORowVector< ORowSetValue >::Vector::const_iterator aIter = _rRow->begin()+1;
+ ORowVector< ORowSetValue >::Vector::const_iterator aEnd = _rRow->end();
+ for(; aIter != aEnd;++aIter,++nCheckCount,++i)
+ {
+ aColumnName = m_xSetMetaData->getColumnName(i);
+ if(xPrimaryKeyColumns.is() && xPrimaryKeyColumns->hasByName(aColumnName))
+ {
+ _sCondition.append(::dbtools::quoteName( aQuote,aColumnName));
+ if(aIter->isNull())
+ _sCondition.append(sIsNull);
+ else
+ _sCondition.append(sParam);
+ _sCondition.append(aAnd);
+ _rOrgValues.push_back(nCheckCount);
+
+ }
+ for (auto const& indexColumn : aAllIndexColumns)
+ {
+ if(indexColumn->hasByName(aColumnName))
+ {
+ _sCondition.append(::dbtools::quoteName( aQuote,aColumnName));
+ if(aIter->isNull())
+ _sCondition.append(sIsNull);
+ else
+ _sCondition.append(sParam);
+ _sCondition.append(aAnd);
+ _rOrgValues.push_back(nCheckCount);
+ break;
+ }
+ }
+ if(aIter->isModified())
+ {
+ _sParameter.append(::dbtools::quoteName( aQuote,aColumnName) + "?,");
+ }
+ }
+}
+
+void OCacheSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("UPDATE " + m_aComposedTableName + " SET ");
+ // list all columns that should be set
+
+ OUStringBuffer aCondition;
+ std::vector< sal_Int32> aOrgValues;
+ fillParameters(_rInsertRow,_xTable,aCondition,aSql,aOrgValues);
+ aSql[aSql.getLength() - 1] = ' ';
+ if ( !aCondition.isEmpty() )
+ {
+ aCondition.setLength(aCondition.getLength()-5);
+
+ aSql.append(" WHERE " + aCondition);
+ }
+ else
+ ::dbtools::throwSQLException(
+ DBA_RES( RID_STR_NO_UPDATE_MISSING_CONDITION ), StandardSQLState::GENERAL_ERROR, *this );
+
+ // now create end execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(ORowVector< ORowSetValue >::Vector::const_iterator aIter = _rInsertRow->begin()+1; aIter != aEnd;++aIter)
+ {
+ if(aIter->isModified())
+ {
+ setParameter(i,xParameter,*aIter,m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ ++i;
+ }
+ }
+ for (auto const& orgValue : aOrgValues)
+ {
+ setParameter(i,xParameter,(*_rOriginalRow)[orgValue],m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ ++i;
+ }
+
+ m_bUpdated = xPrep->executeUpdate() > 0;
+}
+
+void OCacheSet::deleteRow(const ORowSetRow& _rDeleteRow ,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("DELETE FROM " + m_aComposedTableName + " WHERE ");
+
+ // use keys and indexes for exact positioning
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if(xIndexSup.is())
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ // Reference<XColumnsSupplier>
+ Reference<XPropertySet> xIndexColsSup;
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ if(xIndexes.is())
+ {
+ for(sal_Int32 j=0;j<xIndexes->getCount();++j)
+ {
+ xIndexColsSup.set(xIndexes->getByIndex(j),UNO_QUERY);
+ if( xIndexColsSup.is()
+ && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE))
+ && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX))
+ )
+ aAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY_THROW)->getColumns());
+ }
+ }
+
+ OUStringBuffer aColumnName;
+ std::vector< sal_Int32> aOrgValues;
+ fillParameters(_rDeleteRow,_xTable,aSql,aColumnName,aOrgValues);
+
+ aSql.setLength(aSql.getLength()-5);
+
+ // now create and execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ sal_Int32 i = 1;
+ for (auto const& orgValue : aOrgValues)
+ {
+ setParameter(i,xParameter,(*_rDeleteRow)[orgValue],m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ ++i;
+ }
+
+ m_bDeleted = xPrep->executeUpdate() > 0;
+}
+
+void OCacheSet::setParameter(sal_Int32 nPos
+ ,const Reference< XParameters >& _xParameter
+ ,const ORowSetValue& _rValue
+ ,sal_Int32 _nType
+ ,sal_Int32 _nScale)
+{
+ sal_Int32 nType = ( _nType != DataType::OTHER ) ? _nType : _rValue.getTypeKind();
+ ::dbtools::setObjectWithInfo(_xParameter,nPos,_rValue,nType,_nScale);
+}
+
+void OCacheSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition)
+{
+ Any aBookmark = getBookmark();
+ if(!aBookmark.hasValue())
+ aBookmark <<= _nPosition;
+
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = _rRow->begin();
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aEnd = _rRow->end();
+ (*aIter) = aBookmark;
+ ++aIter;
+ for(sal_Int32 i=1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setSigned(m_aSignedFlags[i-1]);
+ aIter->fill(i, m_aColumnTypes[i-1], this);
+ }
+}
+
+sal_Bool SAL_CALL OCacheSet::wasNull( )
+{
+ return m_xDriverRow->wasNull();
+}
+
+OUString SAL_CALL OCacheSet::getString( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getString(columnIndex);
+}
+
+sal_Bool SAL_CALL OCacheSet::getBoolean( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBoolean(columnIndex);
+}
+
+sal_Int8 SAL_CALL OCacheSet::getByte( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getByte(columnIndex);
+}
+
+sal_Int16 SAL_CALL OCacheSet::getShort( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getShort(columnIndex);
+}
+
+sal_Int32 SAL_CALL OCacheSet::getInt( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getInt(columnIndex);
+}
+
+sal_Int64 SAL_CALL OCacheSet::getLong( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getLong(columnIndex);
+}
+
+float SAL_CALL OCacheSet::getFloat( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getFloat(columnIndex);
+}
+
+double SAL_CALL OCacheSet::getDouble( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getDouble(columnIndex);
+}
+
+Sequence< sal_Int8 > SAL_CALL OCacheSet::getBytes( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBytes(columnIndex);
+}
+
+css::util::Date SAL_CALL OCacheSet::getDate( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getDate(columnIndex);
+}
+
+css::util::Time SAL_CALL OCacheSet::getTime( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getTime(columnIndex);
+}
+
+css::util::DateTime SAL_CALL OCacheSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getTimestamp(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCacheSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCacheSet::getCharacterStream( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getCharacterStream(columnIndex);
+}
+
+Any SAL_CALL OCacheSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap )
+{
+ return m_xDriverRow->getObject(columnIndex,typeMap);
+}
+
+Reference< XRef > SAL_CALL OCacheSet::getRef( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getRef(columnIndex);
+}
+
+Reference< XBlob > SAL_CALL OCacheSet::getBlob( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBlob(columnIndex);
+}
+
+Reference< XClob > SAL_CALL OCacheSet::getClob( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getClob(columnIndex);
+}
+
+Reference< XArray > SAL_CALL OCacheSet::getArray( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getArray(columnIndex);
+}
+
+// XResultSet
+bool OCacheSet::next()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->next();
+}
+
+void OCacheSet::beforeFirst( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_xDriverSet->beforeFirst();
+}
+
+void OCacheSet::afterLast( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_xDriverSet->afterLast();
+}
+
+bool OCacheSet::first()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->first();
+}
+
+bool OCacheSet::last()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->last();
+}
+
+sal_Int32 OCacheSet::getRow( )
+{
+ return m_xDriverSet->getRow();
+}
+
+bool OCacheSet::absolute( sal_Int32 row )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->absolute(row);
+}
+
+bool OCacheSet::previous( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->previous();
+}
+
+void OCacheSet::refreshRow( )
+{
+ m_xDriverSet->refreshRow();
+}
+
+bool OCacheSet::rowUpdated( )
+{
+ return m_xDriverSet->rowUpdated();
+}
+
+bool OCacheSet::rowInserted( )
+{
+ return m_xDriverSet->rowInserted();
+}
+
+bool OCacheSet::rowDeleted( )
+{
+ return m_xDriverSet->rowDeleted();
+}
+
+bool OCacheSet::isResultSetChanged() const
+{
+ return false;
+}
+
+void OCacheSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& /*io_aInsertRow*/,ORowSetValueVector::Vector& /*io_aRow*/,std::vector<sal_Int32>& o_aChangedColumns)
+{
+ o_aChangedColumns.push_back(i_nColumnIndex);
+}
+
+bool OCacheSet::columnValuesUpdated(ORowSetValueVector::Vector& /*io_aCachedRow*/,const ORowSetValueVector::Vector& /*io_aRow*/)
+{
+ return false;
+}
+
+bool OCacheSet::updateColumnValues(const ORowSetValueVector::Vector& /*io_aCachedRow*/,ORowSetValueVector::Vector& /*io_aRow*/,const std::vector<sal_Int32>& /*i_aChangedColumns*/)
+{
+ return true;
+}
+
+void OCacheSet::fillMissingValues(ORowSetValueVector::Vector& /*io_aRow*/) const
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CacheSet.hxx b/dbaccess/source/core/api/CacheSet.hxx
new file mode 100644
index 000000000..1006b9662
--- /dev/null
+++ b/dbaccess/source/core/api/CacheSet.hxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "RowSetRow.hxx"
+#include <cppuhelper/implbase.hxx>
+
+#include <vector>
+
+namespace com::sun::star::sdbc{ class XParameters; }
+
+namespace dbaccess
+{
+ class OCacheSet : public ::cppu::WeakImplHelper< css::sdbc::XRow>
+ {
+ protected:
+ css::uno::Reference< css::sdbc::XResultSet> m_xDriverSet;
+ css::uno::Reference< css::sdbc::XRow> m_xDriverRow;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xSetMetaData;
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+
+ std::vector<bool> m_aNullable;
+ std::vector<bool> m_aSignedFlags;
+ std::vector<sal_Int32> m_aColumnTypes;
+ OUString m_aComposedTableName;
+ sal_Int32 m_nMaxRows;
+ bool m_bInserted;
+ bool m_bUpdated;
+ bool m_bDeleted;
+ OUString m_sRowSetFilter;
+
+ explicit OCacheSet(sal_Int32 i_nMaxRows);
+ virtual ~OCacheSet() override;
+
+ static void setParameter(sal_Int32 nPos
+ ,const css::uno::Reference< css::sdbc::XParameters >& _xParameter
+ ,const connectivity::ORowSetValue& _rValue
+ ,sal_Int32 _nType
+ ,sal_Int32 _nScale
+ );
+ void fillParameters( const ORowSetRow& _rRow
+ ,const connectivity::OSQLTable& _xTable
+ ,OUStringBuffer& _sCondition
+ ,OUStringBuffer& _sParameter
+ ,std::vector< sal_Int32>& _rOrgValues);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void fillTableName(const css::uno::Reference< css::beans::XPropertySet>& _xTable);
+
+ OUString getIdentifierQuoteString() const;
+ public:
+
+ // late constructor
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter);
+ virtual void fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition);
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // css::sdbc::XResultSet
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool next();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void beforeFirst( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void afterLast( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool first();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool last();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual sal_Int32 getRow( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool absolute( sal_Int32 row );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool previous( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void refreshRow( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool rowUpdated( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool rowInserted( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool rowDeleted( );
+ // css::sdbcx::XRowLocate
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any getBookmark() = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool hasOrderedBookmarks( ) = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) = 0;
+ // css::sdbc::XResultSetUpdate
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void updateRow( const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void deleteRow( const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& _xTable ) = 0;
+
+ virtual bool isResultSetChanged() const;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) = 0;
+ virtual void mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns);
+ virtual bool columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow);
+ virtual bool updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns);
+ virtual void fillMissingValues(ORowSetValueVector::Vector& io_aRow) const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/FilteredContainer.cxx b/dbaccess/source/core/api/FilteredContainer.cxx
new file mode 100644
index 000000000..a5cf0b156
--- /dev/null
+++ b/dbaccess/source/core/api/FilteredContainer.cxx
@@ -0,0 +1,459 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hxx>
+#include <FilteredContainer.hxx>
+#include <RefreshListener.hxx>
+#include <sdbcoretools.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <tools/wldcrd.hxx>
+#include <tools/diagnose_ex.h>
+#include <optional>
+#include <sal/log.hxx>
+
+namespace dbaccess
+{
+ using namespace dbtools;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::container;
+ using namespace ::osl;
+ using namespace ::comphelper;
+ using namespace ::cppu;
+ using namespace ::connectivity::sdbcx;
+
+/** creates a vector of WildCards and reduce the _rTableFilter of the length of WildCards
+*/
+static sal_Int32 createWildCardVector(Sequence< OUString >& _rTableFilter, std::vector< WildCard >& _rOut)
+{
+ // for wildcard search : remove all table filters which are a wildcard expression and build a WildCard
+ // for them
+ OUString* pTableFilters = _rTableFilter.getArray();
+ OUString* pEnd = pTableFilters + _rTableFilter.getLength();
+ sal_Int32 nShiftPos = 0;
+ for (sal_Int32 i=0; pEnd != pTableFilters; ++pTableFilters,++i)
+ {
+ if (pTableFilters->indexOf('%') != -1)
+ {
+ _rOut.emplace_back(pTableFilters->replace('%', '*'));
+ }
+ else
+ {
+ if (nShiftPos != i)
+ {
+ _rTableFilter.getArray()[nShiftPos] = _rTableFilter.getArray()[i];
+ }
+ ++nShiftPos;
+ }
+ }
+ // now aTableFilter contains nShiftPos non-wc-strings and aWCSearch all wc-strings
+ _rTableFilter.realloc(nShiftPos);
+ return nShiftPos;
+}
+
+ static bool lcl_isElementAllowed( const OUString& _rName,
+ const Sequence< OUString >& _rTableFilter,
+ const std::vector< WildCard >& _rWCSearch )
+ {
+ sal_Int32 nTableFilterLen = _rTableFilter.getLength();
+
+ const OUString* tableFilter = _rTableFilter.getConstArray();
+ const OUString* tableFilterEnd = _rTableFilter.getConstArray() + nTableFilterLen;
+ bool bFilterMatch = std::find( tableFilter, tableFilterEnd, _rName ) != tableFilterEnd;
+ // the table is allowed to "pass" if we had no filters at all or any of the non-wildcard filters matches
+ if (!bFilterMatch && !_rWCSearch.empty())
+ { // or if one of the wildcard expression matches
+ for (auto const& elem : _rWCSearch)
+ {
+ bFilterMatch = elem.Matches( _rName );
+ if (bFilterMatch)
+ break;
+ }
+ }
+
+ return bFilterMatch;
+ }
+
+ typedef ::std::optional< OUString > OptionalString;
+
+ namespace {
+
+ struct TableInfo
+ {
+ OptionalString sComposedName;
+ OptionalString sType;
+ OptionalString sCatalog;
+ OptionalString sSchema;
+ OptionalString sName;
+
+ explicit TableInfo( const OUString& _composedName )
+ : sComposedName( _composedName )
+ {
+ }
+
+ TableInfo( const OUString& _catalog, const OUString& _schema, const OUString& _name,
+ const OUString& _type )
+ :sType( _type )
+ ,sCatalog( _catalog )
+ ,sSchema( _schema )
+ ,sName( _name )
+ {
+ }
+ };
+
+ }
+
+ typedef std::vector< TableInfo > TableInfos;
+
+ static void lcl_ensureComposedName( TableInfo& _io_tableInfo, const Reference< XDatabaseMetaData >& _metaData )
+ {
+ if ( !_metaData.is() )
+ throw RuntimeException("lcl_ensureComposedName: _metaData cannot be null!");
+
+ if ( !_io_tableInfo.sComposedName )
+ {
+ OSL_ENSURE( !!_io_tableInfo.sCatalog && !!_io_tableInfo.sSchema && !!_io_tableInfo.sName, "lcl_ensureComposedName: How should I composed the name from nothing!?" );
+
+ _io_tableInfo.sComposedName = OptionalString(
+ composeTableName( _metaData, *_io_tableInfo.sCatalog, *_io_tableInfo.sSchema, *_io_tableInfo.sName,
+ false, ::dbtools::EComposeRule::InDataManipulation )
+ );
+ }
+ }
+
+ static void lcl_ensureType( TableInfo& _io_tableInfo, const Reference< XDatabaseMetaData >& _metaData, const Reference< XNameAccess >& _masterContainer )
+ {
+ if ( !!_io_tableInfo.sType )
+ return;
+
+ lcl_ensureComposedName( _io_tableInfo, _metaData );
+
+ if ( !_masterContainer.is() )
+ throw RuntimeException("lcl_ensureType: _masterContainer cannot be null!");
+
+ OUString sTypeName;
+ try
+ {
+ Reference< XPropertySet > xTable( _masterContainer->getByName( *_io_tableInfo.sComposedName ), UNO_QUERY_THROW );
+ OSL_VERIFY( xTable->getPropertyValue( PROPERTY_TYPE ) >>= sTypeName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ _io_tableInfo.sType = OptionalString( sTypeName );
+ }
+
+ static ::std::vector< OUString> lcl_filter( TableInfos&& _unfilteredTables,
+ const Sequence< OUString >& _tableFilter, const Sequence< OUString >& _tableTypeFilter,
+ const Reference< XDatabaseMetaData >& _metaData, const Reference< XNameAccess >& _masterContainer )
+ {
+ TableInfos aFilteredTables;
+
+ // first, filter for the table names
+ sal_Int32 nTableFilterCount = _tableFilter.getLength();
+ bool dontFilterTableNames = ( ( nTableFilterCount == 1 ) && _tableFilter[0] == "%" );
+ if( dontFilterTableNames )
+ {
+ aFilteredTables = std::move(_unfilteredTables);
+ }
+ else
+ {
+ // for wildcard search : remove all table filters which are a wildcard expression and build a WildCard
+ // for them
+ std::vector< WildCard > aWildCardTableFilter;
+ Sequence< OUString > aNonWildCardTableFilter = _tableFilter;
+ nTableFilterCount = createWildCardVector( aNonWildCardTableFilter, aWildCardTableFilter );
+
+ TableInfos aUnfilteredTables( std::move(_unfilteredTables) );
+ aUnfilteredTables.reserve( nTableFilterCount + ( aWildCardTableFilter.size() * 10 ) );
+
+ for (auto & unfilteredTable : aUnfilteredTables)
+ {
+ lcl_ensureComposedName(unfilteredTable, _metaData);
+
+ if ( lcl_isElementAllowed( *unfilteredTable.sComposedName, aNonWildCardTableFilter, aWildCardTableFilter ) )
+ aFilteredTables.push_back(unfilteredTable);
+ }
+ }
+
+ // second, filter for the table types
+ sal_Int32 nTableTypeFilterCount = _tableTypeFilter.getLength();
+ bool dontFilterTableTypes = ( ( nTableTypeFilterCount == 1 ) && _tableTypeFilter[0] == "%" );
+ dontFilterTableTypes = dontFilterTableTypes || ( nTableTypeFilterCount == 0 );
+ // (for TableTypeFilter, unlike TableFilter, "empty" means "do not filter at all")
+ if ( !dontFilterTableTypes )
+ {
+ TableInfos aUnfilteredTables;
+ aUnfilteredTables.swap( aFilteredTables );
+
+ const OUString* pTableTypeFilterBegin = _tableTypeFilter.getConstArray();
+ const OUString* pTableTypeFilterEnd = pTableTypeFilterBegin + _tableTypeFilter.getLength();
+
+ for (auto & unfilteredTable : aUnfilteredTables)
+ {
+ // ensure that we know the table type
+ lcl_ensureType( unfilteredTable, _metaData, _masterContainer );
+
+ if ( std::find( pTableTypeFilterBegin, pTableTypeFilterEnd, *unfilteredTable.sType ) != pTableTypeFilterEnd )
+ aFilteredTables.push_back(unfilteredTable);
+ }
+ }
+
+ ::std::vector< OUString> aReturn;
+ for (auto & filteredTable : aFilteredTables)
+ {
+ lcl_ensureComposedName(filteredTable, _metaData);
+ aReturn.push_back(*filteredTable.sComposedName);
+ }
+ return aReturn;
+ }
+
+ // OViewContainer
+ OFilteredContainer::OFilteredContainer(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const Reference< XConnection >& _xCon,
+ bool _bCase,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend)
+ :OCollection(_rParent,_bCase,_rMutex,std::vector< OUString>())
+ ,m_bConstructed(false)
+ ,m_pRefreshListener(_pRefreshListener)
+ ,m_nInAppend(_nInAppend)
+ ,m_xConnection(_xCon)
+ {
+ }
+
+ void OFilteredContainer::construct(const Reference< XNameAccess >& _rxMasterContainer,
+ const Sequence< OUString >& _rTableFilter,
+ const Sequence< OUString >& _rTableTypeFilter)
+ {
+ try
+ {
+ Reference<XConnection> xCon = m_xConnection;
+ if ( xCon.is() )
+ m_xMetaData = xCon->getMetaData();
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xMasterContainer = _rxMasterContainer;
+
+ if ( m_xMasterContainer.is() )
+ {
+ addMasterContainerListener();
+
+ TableInfos aUnfilteredTables;
+
+ Sequence< OUString > aNames = m_xMasterContainer->getElementNames();
+ const OUString* name = aNames.getConstArray();
+ const OUString* nameEnd = name + aNames.getLength();
+ for ( ; name != nameEnd; ++name )
+ aUnfilteredTables.emplace_back( *name );
+
+ reFill( lcl_filter( std::move(aUnfilteredTables),
+ _rTableFilter, _rTableTypeFilter, m_xMetaData, m_xMasterContainer ) );
+
+ m_bConstructed = true;
+ }
+ else
+ {
+ construct( _rTableFilter, _rTableTypeFilter );
+ }
+ }
+
+ void OFilteredContainer::construct(const Sequence< OUString >& _rTableFilter, const Sequence< OUString >& _rTableTypeFilter)
+ {
+ // build sorted versions of the filter sequences, so the visibility decision is faster
+ Sequence< OUString > aTableFilter(_rTableFilter);
+
+ // for wildcard search : remove all table filters which are a wildcard expression and build a WildCard
+ // for them
+ std::vector< WildCard > aWCSearch;
+ createWildCardVector(aTableFilter,aWCSearch);
+
+ try
+ {
+ Reference< XConnection > xCon( m_xConnection, UNO_SET_THROW );
+ m_xMetaData.set( xCon->getMetaData(), UNO_SET_THROW );
+
+ // create a table filter suitable for the XDatabaseMetaData::getTables call,
+ // taking into account both the externally-provided table type filter, and any
+ // table type restriction which is inherent to the container
+ Sequence< OUString > aTableTypeFilter;
+ OUString sInherentTableTypeRestriction( getTableTypeRestriction() );
+ if ( !sInherentTableTypeRestriction.isEmpty() )
+ {
+ if ( _rTableTypeFilter.hasElements() )
+ {
+ const OUString* tableType = _rTableTypeFilter.getConstArray();
+ const OUString* tableTypeEnd = tableType + _rTableTypeFilter.getLength();
+ for ( ; tableType != tableTypeEnd; ++tableType )
+ {
+ if ( *tableType == sInherentTableTypeRestriction )
+ break;
+ }
+ if ( tableType == tableTypeEnd )
+ { // the only table type which can be part of this container is not allowed
+ // by the externally provided table type filter.
+ m_bConstructed = true;
+ return;
+ }
+ }
+ aTableTypeFilter = { sInherentTableTypeRestriction };
+ }
+ else
+ {
+ // no container-inherent restriction for the table types
+ if ( !_rTableTypeFilter.hasElements() )
+ { // no externally-provided table type filter => use the default filter
+ getAllTableTypeFilter( aTableTypeFilter );
+ }
+ else
+ {
+ aTableTypeFilter = _rTableTypeFilter;
+ }
+ }
+
+ static constexpr OUStringLiteral sAll = u"%";
+ Reference< XResultSet > xTables = m_xMetaData->getTables( Any(), sAll, sAll, aTableTypeFilter );
+ Reference< XRow > xCurrentRow( xTables, UNO_QUERY_THROW );
+
+ TableInfos aUnfilteredTables;
+
+ OUString sCatalog, sSchema, sName, sType;
+ while ( xTables->next() )
+ {
+ sCatalog = xCurrentRow->getString(1);
+ sSchema = xCurrentRow->getString(2);
+ sName = xCurrentRow->getString(3);
+ sType = xCurrentRow->getString(4);
+
+ aUnfilteredTables.emplace_back( sCatalog, sSchema, sName, sType );
+ }
+
+ reFill( lcl_filter( std::move(aUnfilteredTables),
+ _rTableFilter, aTableTypeFilter, m_xMetaData, nullptr ) );
+
+ disposeComponent( xTables );
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ disposing();
+ return;
+ }
+
+ m_bConstructed = true;
+ }
+
+ void OFilteredContainer::disposing()
+ {
+ OCollection::disposing();
+
+ if ( m_xMasterContainer.is() )
+ removeMasterContainerListener();
+
+ m_xMasterContainer = nullptr;
+ m_xMetaData = nullptr;
+ m_pRefreshListener = nullptr;
+ m_bConstructed = false;
+ }
+
+ void OFilteredContainer::impl_refresh()
+ {
+ if ( m_pRefreshListener )
+ {
+ m_bConstructed = false;
+ Reference<XRefreshable> xRefresh(m_xMasterContainer,UNO_QUERY);
+ if ( xRefresh.is() )
+ xRefresh->refresh();
+ m_pRefreshListener->refresh(this);
+ }
+ }
+
+ OUString OFilteredContainer::getNameForObject(const ObjectType& _xObject)
+ {
+ OSL_ENSURE( _xObject.is(), "OFilteredContainer::getNameForObject: Object is NULL!" );
+ return ::dbtools::composeTableName( m_xMetaData, _xObject, ::dbtools::EComposeRule::InDataManipulation, false );
+ }
+
+ // multiple to obtain all tables from XDatabaseMetaData::getTables, via passing a particular
+ // table type filter:
+ // adhere to the standard, which requests to pass a NULL table type filter, if
+ // you want to retrieve all tables
+ #define FILTER_MODE_STANDARD 0
+ // only pass %, which is not allowed by the standard, but understood by some drivers
+ #define FILTER_MODE_WILDCARD 1
+ // only pass TABLE and VIEW
+ #define FILTER_MODE_FIXED 2
+ // do the thing which showed to be the safest way, understood by nearly all
+ // drivers, even the ones which do not understand the standard
+ #define FILTER_MODE_MIX_ALL 3
+
+ void OFilteredContainer::getAllTableTypeFilter( Sequence< OUString >& /* [out] */ _rFilter ) const
+ {
+ sal_Int32 nFilterMode = FILTER_MODE_MIX_ALL;
+ // for compatibility reasons, this is the default: we used this way before we
+ // introduced the TableTypeFilterMode setting
+
+ // obtain the data source we belong to, and the TableTypeFilterMode setting
+ Any aFilterModeSetting;
+ if ( getDataSourceSetting( getDataSource( Reference< XInterface >(m_rParent) ), "TableTypeFilterMode", aFilterModeSetting ) )
+ {
+ OSL_VERIFY( aFilterModeSetting >>= nFilterMode );
+ }
+
+ static const OUStringLiteral sAll( u"%" );
+ static const OUStringLiteral sView( u"VIEW" );
+ static const OUStringLiteral sTable( u"TABLE" );
+
+ switch ( nFilterMode )
+ {
+ default:
+ SAL_WARN("dbaccess", "OTableContainer::getAllTableTypeFilter: unknown TableTypeFilterMode!" );
+ [[fallthrough]];
+ case FILTER_MODE_MIX_ALL:
+ _rFilter = { sView, sTable, sAll };
+ break;
+ case FILTER_MODE_FIXED:
+ _rFilter = { sView, sTable };
+ break;
+ case FILTER_MODE_WILDCARD:
+ _rFilter = { sAll };
+ break;
+ case FILTER_MODE_STANDARD:
+ _rFilter.realloc( 0 );
+ break;
+ }
+ }
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/HelperCollections.cxx b/dbaccess/source/core/api/HelperCollections.cxx
new file mode 100644
index 000000000..dfc18badc
--- /dev/null
+++ b/dbaccess/source/core/api/HelperCollections.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "HelperCollections.hxx"
+
+#include <strings.hxx>
+
+#include <osl/diagnose.h>
+
+namespace dbaccess
+{
+ using namespace dbtools;
+ using namespace comphelper;
+ using namespace connectivity;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::script;
+ using namespace ::cppu;
+ using namespace ::osl;
+
+ OPrivateColumns::OPrivateColumns(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector,
+ bool _bUseAsIndex
+ ) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector,_bUseAsIndex)
+ ,m_aColumns(_rColumns)
+ {
+ }
+
+ std::unique_ptr<OPrivateColumns> OPrivateColumns::createWithIntrinsicNames( const ::rtl::Reference< ::connectivity::OSQLColumns >& _rColumns,
+ bool _bCase, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex )
+ {
+ std::vector< OUString > aNames; aNames.reserve( _rColumns->size() );
+
+ OUString sColumName;
+ for (auto const& column : *_rColumns)
+ {
+ Reference< XPropertySet > xColumn(column, UNO_SET_THROW);
+ xColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumName;
+ aNames.push_back( sColumName );
+ }
+ return std::unique_ptr<OPrivateColumns>(new OPrivateColumns( _rColumns, _bCase, _rParent, _rMutex, aNames, false ));
+ }
+
+ void OPrivateColumns::disposing()
+ {
+ m_aColumns = nullptr;
+ clear_NoDispose();
+ // we're not owner of the objects we're holding, instead the object we got in our ctor is
+ // So we're not allowed to dispose our elements.
+ OPrivateColumns_Base::disposing();
+ }
+
+ connectivity::sdbcx::ObjectType OPrivateColumns::createObject(const OUString& _rName)
+ {
+ if ( m_aColumns.is() )
+ {
+ ::connectivity::OSQLColumns::Vector::const_iterator aIter = find(m_aColumns->begin(),m_aColumns->end(),_rName,isCaseSensitive());
+ if(aIter == m_aColumns->end())
+ aIter = findRealName(m_aColumns->begin(),m_aColumns->end(),_rName,isCaseSensitive());
+
+ if(aIter != m_aColumns->end())
+ return connectivity::sdbcx::ObjectType(*aIter,UNO_QUERY);
+
+ OSL_FAIL("Column not found in collection!");
+ }
+ return nullptr;
+ }
+
+ connectivity::sdbcx::ObjectType OPrivateTables::createObject(const OUString& _rName)
+ {
+ if ( !m_aTables.empty() )
+ {
+ OSQLTables::iterator aIter = m_aTables.find(_rName);
+ OSL_ENSURE(aIter != m_aTables.end(),"Table not found!");
+ OSL_ENSURE(aIter->second.is(),"Table is null!");
+ return connectivity::sdbcx::ObjectType(m_aTables.find(_rName)->second,UNO_QUERY);
+ }
+ return nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/HelperCollections.hxx b/dbaccess/source/core/api/HelperCollections.hxx
new file mode 100644
index 000000000..ed89fc643
--- /dev/null
+++ b/dbaccess/source/core/api/HelperCollections.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <rtl/ref.hxx>
+
+namespace dbaccess
+{
+ using namespace dbtools;
+ using namespace comphelper;
+ using namespace connectivity;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::script;
+ using namespace ::cppu;
+ using namespace ::osl;
+
+ typedef connectivity::sdbcx::OCollection OPrivateColumns_Base;
+ class OPrivateColumns : public OPrivateColumns_Base
+ {
+ ::rtl::Reference< ::connectivity::OSQLColumns> m_aColumns;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override {}
+ virtual Reference< XPropertySet > createDescriptor() override
+ {
+ return nullptr;
+ }
+ public:
+ OPrivateColumns(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector,
+ bool _bUseAsIndex = false
+ );
+
+ /** creates a columns instance as above, but taking the names from the columns itself
+ */
+ static std::unique_ptr<OPrivateColumns> createWithIntrinsicNames(
+ const ::rtl::Reference< ::connectivity::OSQLColumns >& _rColumns,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex
+ );
+
+ virtual void disposing() override;
+ };
+ typedef connectivity::sdbcx::OCollection OPrivateTables_BASE;
+
+ // OPrivateTables
+ class OPrivateTables : public OPrivateTables_BASE
+ {
+ OSQLTables m_aTables;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override {}
+ virtual Reference< XPropertySet > createDescriptor() override
+ {
+ return nullptr;
+ }
+ public:
+ OPrivateTables( const OSQLTables& _rTables,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ std::vector< OUString> && _rVector
+ ) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aTables(std::move(_rTables))
+ {
+ }
+ virtual void disposing() override
+ {
+ clear_NoDispose();
+ // we're not owner of the objects we're holding, instead the object we got in our ctor is
+ // So we're not allowed to dispose our elements.
+ m_aTables.clear();
+ OPrivateTables_BASE::disposing();
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/KeySet.cxx b/dbaccess/source/core/api/KeySet.cxx
new file mode 100644
index 000000000..338d4d7f8
--- /dev/null
+++ b/dbaccess/source/core/api/KeySet.cxx
@@ -0,0 +1,1463 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <string_view>
+
+#include "KeySet.hxx"
+#include <sal/log.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <algorithm>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <composertools.hxx>
+#include "PrivateRow.hxx"
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star;
+using namespace ::cppu;
+using namespace ::osl;
+using std::vector;
+
+namespace
+{
+ void lcl_fillIndexColumns(const Reference<XIndexAccess>& _xIndexes, std::vector< Reference<XNameAccess> >& _rAllIndexColumns)
+ {
+ if ( !_xIndexes.is() )
+ return;
+
+ Reference<XPropertySet> xIndexColsSup;
+ sal_Int32 nCount = _xIndexes->getCount();
+ for(sal_Int32 j = 0 ; j < nCount ; ++j)
+ {
+ xIndexColsSup.set(_xIndexes->getByIndex(j),UNO_QUERY);
+ if( xIndexColsSup.is()
+ && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE))
+ && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX))
+ )
+ _rAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY_THROW)->getColumns());
+ }
+ }
+
+ template < typename T > void tryDispose( Reference<T> &r )
+ {
+ try
+ {
+ ::comphelper::disposeComponent(r);
+ }
+ catch(const Exception&)
+ {
+ r = nullptr;
+ }
+ catch(...)
+ {
+ SAL_WARN("dbaccess", "Unknown Exception occurred");
+ }
+ }
+}
+
+
+OKeySet::OKeySet(const connectivity::OSQLTable& _xTable,
+ const OUString& _rUpdateTableName, // this can be the alias or the full qualified name
+ const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount)
+ :OCacheSet(i_nMaxRows)
+ ,m_aParameterValueForCache(new ORowSetValueVector(_aParameterValueForCache))
+ ,m_xTable(_xTable)
+ ,m_xComposer(_xComposer)
+ ,m_sUpdateTableName(_rUpdateTableName)
+ ,m_rRowCount(o_nRowCount)
+ ,m_bRowCountFinal(false)
+{
+}
+
+OKeySet::~OKeySet()
+{
+ tryDispose(m_xSet);
+ // m_xStatement is necessarily one of those
+ for (auto & statement : m_vStatements)
+ {
+ tryDispose(statement.second);
+ }
+
+ m_xComposer = nullptr;
+
+}
+
+void OKeySet::initColumns()
+{
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ m_pKeyColumnNames.reset( new SelectColumnsMetaData(bCase) );
+ m_pColumnNames.reset( new SelectColumnsMetaData(bCase) );
+ m_pParameterNames.reset( new SelectColumnsMetaData(bCase) );
+ m_pForeignColumnNames.reset( new SelectColumnsMetaData(bCase) );
+}
+
+void OKeySet::findTableColumnsMatching_throw( const Any& i_aTable,
+ const OUString& i_rUpdateTableName,
+ const Reference<XDatabaseMetaData>& i_xMeta,
+ const Reference<XNameAccess>& i_xQueryColumns,
+ std::unique_ptr<SelectColumnsMetaData> const & o_pKeyColumnNames)
+{
+ // first ask the database itself for the best columns which can be used
+ Sequence< OUString> aBestColumnNames;
+ Reference<XNameAccess> xKeyColumns = getPrimaryKeyColumns_throw(i_aTable);
+ if ( xKeyColumns.is() )
+ aBestColumnNames = xKeyColumns->getElementNames();
+
+ const Reference<XColumnsSupplier> xTblColSup(i_aTable,UNO_QUERY_THROW);
+ const Reference<XNameAccess> xTblColumns = xTblColSup->getColumns();
+ // locate parameter in select columns
+ Reference<XParametersSupplier> xParaSup(m_xComposer,UNO_QUERY);
+ Reference<XIndexAccess> xQueryParameters = xParaSup->getParameters();
+ const sal_Int32 nParaCount = xQueryParameters->getCount();
+ Sequence< OUString> aParameterColumns(nParaCount);
+ auto aParameterColumnsRange = asNonConstRange(aParameterColumns);
+ for(sal_Int32 i = 0; i< nParaCount;++i)
+ {
+ Reference<XPropertySet> xPara(xQueryParameters->getByIndex(i),UNO_QUERY_THROW);
+ xPara->getPropertyValue(PROPERTY_REALNAME) >>= aParameterColumnsRange[i];
+ }
+
+ OUString sUpdateTableName( i_rUpdateTableName );
+ if ( sUpdateTableName.isEmpty() )
+ {
+ SAL_WARN("dbaccess", "OKeySet::findTableColumnsMatching_throw: This is a fallback only - it won't work when the table has an alias name." );
+ // If i_aTable originates from a query composer, and is a table which appears with an alias in the SELECT statement,
+ // then the below code will not produce correct results.
+ // For instance, imagine a "SELECT alias.col FROM table AS alias". Now i_aTable would be the table named
+ // "table", so our sUpdateTableName would be "table" as well - not the information about the "alias" is
+ // already lost here.
+ // now getColumnPositions would traverse the columns, and check which of them belong to the table denoted
+ // by sUpdateTableName. Since the latter is "table", but the columns only know that they belong to a table
+ // named "alias", there will be no matching - so getColumnPositions wouldn't find anything.
+
+ OUString sCatalog, sSchema, sTable;
+ Reference<XPropertySet> xTableProp( i_aTable, UNO_QUERY_THROW );
+ xTableProp->getPropertyValue( PROPERTY_CATALOGNAME )>>= sCatalog;
+ xTableProp->getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema;
+ xTableProp->getPropertyValue( PROPERTY_NAME ) >>= sTable;
+ sUpdateTableName = dbtools::composeTableName( i_xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+
+ ::dbaccess::getColumnPositions(i_xQueryColumns,aBestColumnNames,sUpdateTableName,(*o_pKeyColumnNames),true);
+ ::dbaccess::getColumnPositions(i_xQueryColumns,xTblColumns->getElementNames(),sUpdateTableName,(*m_pColumnNames),true);
+ ::dbaccess::getColumnPositions(i_xQueryColumns,aParameterColumns,sUpdateTableName,(*m_pParameterNames),true);
+
+ if ( o_pKeyColumnNames->empty() )
+ {
+ ::dbtools::throwGenericSQLException("Could not find any key column.", *this );
+ }
+
+ for (auto const& keyColumn : *o_pKeyColumnNames)
+ {
+ if ( !xTblColumns->hasByName( keyColumn.second.sRealName ) )
+ continue;
+
+ Reference<XPropertySet> xProp( xTblColumns->getByName( keyColumn.second.sRealName ), UNO_QUERY );
+ bool bAuto = false;
+ if ( ( xProp->getPropertyValue( PROPERTY_ISAUTOINCREMENT ) >>= bAuto ) && bAuto )
+ m_aAutoColumns.push_back( keyColumn.first );
+ }
+}
+
+namespace
+{
+ void appendOneKeyColumnClause( std::u16string_view tblName, const OUString &colName, const connectivity::ORowSetValue &_rValue, OUStringBuffer &o_buf )
+ {
+ OUString fullName;
+ if (tblName.empty())
+ fullName = colName;
+ else
+ fullName = OUString::Concat(tblName) + "." + colName;
+ if ( _rValue.isNull() )
+ {
+ o_buf.append(fullName + " IS NULL ");
+ }
+ else
+ {
+ o_buf.append(fullName + " = ? ");
+ }
+ }
+}
+
+void OKeySet::setOneKeyColumnParameter( sal_Int32 &nPos, const Reference< XParameters > &_xParameter, const connectivity::ORowSetValue &_rValue, sal_Int32 _nType, sal_Int32 _nScale )
+{
+ if ( _rValue.isNull() )
+ {
+ // Nothing to do, appendOneKeyColumnClause took care of it,
+ // the "IS NULL" is hardcoded in the query
+ }
+ else
+ {
+ setParameter( nPos++, _xParameter, _rValue, _nType, _nScale );
+ }
+}
+
+OUStringBuffer OKeySet::createKeyFilter()
+{
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->begin();
+
+ static const char aAnd[] = " AND ";
+ const OUString aQuote = getIdentifierQuoteString();
+ OUStringBuffer aFilter;
+ // create the where clause
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( ! aFilter.isEmpty() )
+ aFilter.append(aAnd);
+ appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta, keyColumnName.second.sTableName, ::dbtools::EComposeRule::InDataManipulation),
+ ::dbtools::quoteName(aQuote, keyColumnName.second.sRealName),
+ *aIter++,
+ aFilter);
+ }
+ for (auto const& foreignColumnName : * m_pForeignColumnNames)
+ {
+ if ( ! aFilter.isEmpty() )
+ aFilter.append(aAnd);
+ appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta, foreignColumnName.second.sTableName, ::dbtools::EComposeRule::InDataManipulation),
+ ::dbtools::quoteName(aQuote, foreignColumnName.second.sRealName),
+ *aIter++,
+ aFilter);
+ }
+ return aFilter;
+}
+
+void OKeySet::construct(const Reference< XResultSet>& _xDriverSet, const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+
+ initColumns();
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ Reference<XColumnsSupplier> xQueryColSup(m_xComposer, UNO_QUERY);
+ const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
+ findTableColumnsMatching_throw( Any(m_xTable), m_sUpdateTableName, xMeta, xQueryColumns, m_pKeyColumnNames );
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+ Reference<XTablesSupplier> xTabSup(xAnalyzer,uno::UNO_QUERY);
+ Reference<XNameAccess> xSelectTables = xTabSup->getTables();
+ const Sequence< OUString> aSeq = xSelectTables->getElementNames();
+ if ( aSeq.getLength() > 1 ) // special handling for join
+ {
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* const pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( *pIter != m_sUpdateTableName )
+ {
+ connectivity::OSQLTable xSelColSup(xSelectTables->getByName(*pIter),uno::UNO_QUERY);
+ Reference<XPropertySet> xProp(xSelColSup,uno::UNO_QUERY);
+ OUString sSelectTableName = ::dbtools::composeTableName( xMeta, xProp, ::dbtools::EComposeRule::InDataManipulation, false );
+
+ ::dbaccess::getColumnPositions(xQueryColumns, xSelColSup->getColumns()->getElementNames(), sSelectTableName, (*m_pForeignColumnNames), true);
+
+ // LEM: there used to be a break here; however, I see no reason to stop
+ // at first non-updateTable, so I removed it. (think of multiple joins...)
+ }
+ }
+ }
+
+ // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
+ // without extra variable to be set
+ OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
+ m_aKeyMap.emplace(0, keySetValue);
+ m_aKeyIter = m_aKeyMap.begin();
+}
+
+void OKeySet::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ OCacheSet::construct(_xDriverSet, m_sRowSetFilter);
+ m_bRowCountFinal = false;
+ m_aKeyMap.clear();
+ OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
+ m_aKeyMap.emplace(0,keySetValue);
+ m_aKeyIter = m_aKeyMap.begin();
+}
+
+void OKeySet::ensureStatement( )
+{
+ // do we already have a statement for the current combination of NULLness
+ // of key & foreign columns?
+ std::vector<bool> FilterColumnsNULL;
+ FilterColumnsNULL.reserve(m_aKeyIter->second.first->size());
+ for (auto const& elem : *m_aKeyIter->second.first)
+ FilterColumnsNULL.push_back(elem.isNull());
+ vStatements_t::const_iterator pNewStatement(m_vStatements.find(FilterColumnsNULL));
+ if(pNewStatement == m_vStatements.end())
+ {
+ // no: make a new one
+ makeNewStatement();
+ std::pair< vStatements_t::const_iterator, bool > insert_result
+ (m_vStatements.emplace( FilterColumnsNULL, m_xStatement));
+ (void) insert_result; // WaE: unused variable
+ assert(insert_result.second);
+ }
+ else
+ // yes: use it
+ m_xStatement = pNewStatement->second;
+}
+
+void OKeySet::makeNewStatement()
+{
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+
+ OUStringBuffer aFilter(createKeyFilter());
+ executeStatement(aFilter, xAnalyzer);
+}
+
+void OKeySet::executeStatement(OUStringBuffer& io_aFilter, Reference<XSingleSelectQueryComposer>& io_xAnalyzer)
+{
+ bool bFilterSet = !m_sRowSetFilter.isEmpty();
+ if ( bFilterSet )
+ {
+ FilterCreator aFilterCreator;
+ aFilterCreator.append( m_sRowSetFilter );
+ aFilterCreator.append( io_aFilter.makeStringAndClear() );
+ io_aFilter = aFilterCreator.getComposedAndClear();
+ }
+ io_xAnalyzer->setFilter(io_aFilter.makeStringAndClear());
+ if ( bFilterSet )
+ {
+ Sequence< Sequence< PropertyValue > > aFilter2 = io_xAnalyzer->getStructuredFilter();
+ const Sequence< PropertyValue >* pOr = aFilter2.getConstArray();
+ const Sequence< PropertyValue >* pOrEnd = pOr + aFilter2.getLength();
+ for(;pOr != pOrEnd;++pOr)
+ {
+ const PropertyValue* pAnd = pOr->getConstArray();
+ const PropertyValue* pAndEnd = pAnd + pOr->getLength();
+ for(;pAnd != pAndEnd;++pAnd)
+ {
+ OUString sValue;
+ if ( !(pAnd->Value >>= sValue) || !( sValue == "?" || sValue.startsWith( ":" ) ) )
+ { // we have a criteria which has to be taken into account for updates
+ m_aFilterColumns.push_back(pAnd->Name);
+ }
+ }
+ }
+ }
+ m_xStatement = m_xConnection->prepareStatement(io_xAnalyzer->getQueryWithSubstitution());
+ ::comphelper::disposeComponent(io_xAnalyzer);
+}
+
+void OKeySet::invalidateRow()
+{
+ m_xRow = nullptr;
+ ::comphelper::disposeComponent(m_xSet);
+}
+
+Any OKeySet::getBookmark()
+{
+ OSL_ENSURE(m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(),
+ "getBookmark is only possible when we stand on a valid row!");
+ return Any(m_aKeyIter->first);
+}
+
+bool OKeySet::moveToBookmark( const Any& bookmark )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aKeyIter = m_aKeyMap.find(::comphelper::getINT32(bookmark));
+ invalidateRow();
+ return m_aKeyIter != m_aKeyMap.end();
+}
+
+sal_Int32 OKeySet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ sal_Int32 nFirst = 0, nSecond = 0;
+ _first >>= nFirst;
+ _second >>= nSecond;
+
+ return (nFirst != nSecond) ? CompareBookmark::NOT_EQUAL : CompareBookmark::EQUAL;
+}
+
+bool OKeySet::hasOrderedBookmarks( )
+{
+ return true;
+}
+
+sal_Int32 OKeySet::hashBookmark( const Any& bookmark )
+{
+ return ::comphelper::getINT32(bookmark);
+}
+
+
+void OKeySet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql = "UPDATE " + m_aComposedTableName + " SET ";
+ // list all columns that should be set
+ constexpr OUStringLiteral aPara(u" = ?,");
+ OUString aQuote = getIdentifierQuoteString();
+ constexpr OUStringLiteral aAnd(u" AND ");
+ OUString sIsNull(" IS NULL");
+ OUString sParam(" = ?");
+
+ // use keys and indexes for exact positioning
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if ( xIndexSup.is() )
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ lcl_fillIndexColumns(xIndexes,aAllIndexColumns);
+
+ OUStringBuffer sKeyCondition,sIndexCondition;
+ std::vector<sal_Int32> aIndexColumnPositions;
+
+ const sal_Int32 nOldLength = aSql.getLength();
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ sKeyCondition.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rOriginalRow)[columnName.second.nPosition].isNull())
+ sKeyCondition.append(sIsNull);
+ else
+ sKeyCondition.append(sParam);
+ sKeyCondition.append(aAnd);
+ }
+ else
+ {
+ for (auto const& indexColumn : aAllIndexColumns)
+ {
+ if(indexColumn->hasByName(columnName.first))
+ {
+ sIndexCondition.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rOriginalRow)[columnName.second.nPosition].isNull())
+ sIndexCondition.append(sIsNull);
+ else
+ {
+ sIndexCondition.append(sParam);
+ aIndexColumnPositions.push_back(columnName.second.nPosition);
+ }
+ sIndexCondition.append(aAnd);
+ break;
+ }
+ }
+ }
+ if((*_rInsertRow)[columnName.second.nPosition].isModified())
+ {
+ aSql.append(::dbtools::quoteName( aQuote,columnName.second.sRealName) + aPara);
+ }
+ }
+
+ if( aSql.getLength() != nOldLength )
+ {
+ aSql.setLength(aSql.getLength()-1);
+ }
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ if(!sKeyCondition.isEmpty() || !sIndexCondition.isEmpty())
+ {
+ aSql.append(" WHERE ");
+ if(!sKeyCondition.isEmpty() && !sIndexCondition.isEmpty())
+ {
+ aSql.append(sKeyCondition + sIndexCondition);
+ }
+ else if(!sKeyCondition.isEmpty())
+ {
+ aSql.append(sKeyCondition);
+ }
+ else if(!sIndexCondition.isEmpty())
+ {
+ aSql.append(sIndexCondition);
+ }
+ aSql.setLength(aSql.getLength()-5); // remove the last AND
+ }
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ // now create end execute the prepared statement
+ executeUpdate(_rInsertRow ,_rOriginalRow,aSql.makeStringAndClear(),u"",aIndexColumnPositions);
+}
+
+void OKeySet::executeUpdate(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const OUString& i_sSQL,std::u16string_view i_sTableName,const std::vector<sal_Int32>& _aIndexColumnPositions)
+{
+ // now create end execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ bool bRefetch = true;
+ Reference<XRow> xRow;
+ sal_Int32 i = 1;
+ // first the set values
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( i_sTableName.empty() || columnName.second.sTableName == i_sTableName )
+ {
+ sal_Int32 nPos = columnName.second.nPosition;
+ if((*_rInsertRow)[nPos].isModified())
+ {
+ if ( bRefetch )
+ {
+ bRefetch = std::find(m_aFilterColumns.begin(),m_aFilterColumns.end(),columnName.second.sRealName) == m_aFilterColumns.end();
+ }
+ impl_convertValue_throw(_rInsertRow,columnName.second);
+ (*_rInsertRow)[nPos].setSigned((*_rOriginalRow)[nPos].isSigned());
+ setParameter(i++,xParameter,(*_rInsertRow)[nPos],columnName.second.nType,columnName.second.nScale);
+ }
+ }
+ }
+ // and then the values of the where condition
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( i_sTableName.empty() || keyColumnName.second.sTableName == i_sTableName )
+ {
+ setParameter(i++,xParameter,(*_rOriginalRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+ }
+ if ( !_aIndexColumnPositions.empty() )
+ {
+ // now we have to set the index values
+ auto aIter = m_pColumnNames->begin();
+ for (auto const& indexColumnPosition : _aIndexColumnPositions)
+ {
+ setParameter(i++,xParameter,(*_rOriginalRow)[indexColumnPosition],(*_rOriginalRow)[indexColumnPosition].getTypeKind(),aIter->second.nScale);
+ ++aIter;
+ }
+ }
+ const sal_Int32 nRowsUpdated = xPrep->executeUpdate();
+ m_bUpdated = nRowsUpdated > 0;
+ if(m_bUpdated)
+ {
+ const sal_Int32 nBookmark = ::comphelper::getINT32((*_rInsertRow)[0].getAny());
+ m_aKeyIter = m_aKeyMap.find(nBookmark);
+ m_aKeyIter->second.second.first = 2;
+ m_aKeyIter->second.second.second = xRow;
+ copyRowValue(_rInsertRow,m_aKeyIter->second.first,nBookmark);
+ tryRefetch(_rInsertRow,bRefetch);
+ }
+}
+
+void OKeySet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql( "INSERT INTO " + m_aComposedTableName + " ( ");
+
+ // set values and column names
+ OUStringBuffer aValues(" VALUES ( ");
+ OUString aQuote = getIdentifierQuoteString();
+
+ bool bRefetch = true;
+ bool bModified = false;
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if((*_rInsertRow)[columnName.second.nPosition].isModified())
+ {
+ if ( bRefetch )
+ {
+ bRefetch = std::find(m_aFilterColumns.begin(),m_aFilterColumns.end(),columnName.second.sRealName) == m_aFilterColumns.end();
+ }
+ aSql.append(::dbtools::quoteName( aQuote,columnName.second.sRealName) + ",");
+ aValues.append("?,");
+ bModified = true;
+ }
+ }
+ if ( !bModified )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ aSql[aSql.getLength() - 1] = ')';
+ aValues[aValues.getLength() - 1] = ')';
+ aSql.append(aValues);
+ // now create,fill and execute the prepared statement
+ executeInsert(_rInsertRow,aSql.makeStringAndClear(),u"",bRefetch);
+}
+
+void OKeySet::executeInsert( const ORowSetRow& _rInsertRow,const OUString& i_sSQL,std::u16string_view i_sTableName,bool bRefetch )
+{
+ // now create,fill and execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ sal_Int32 i = 1;
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( i_sTableName.empty() || columnName.second.sTableName == i_sTableName )
+ {
+ const sal_Int32 nPos = columnName.second.nPosition;
+ if((*_rInsertRow)[nPos].isModified())
+ {
+ if((*_rInsertRow)[nPos].isNull())
+ xParameter->setNull(i++,(*_rInsertRow)[nPos].getTypeKind());
+ else
+ {
+ impl_convertValue_throw(_rInsertRow,columnName.second);
+ (*_rInsertRow)[nPos].setSigned(m_aSignedFlags[nPos-1]);
+ setParameter(i++,xParameter,(*_rInsertRow)[nPos],columnName.second.nType,columnName.second.nScale);
+ }
+ }
+ }
+ }
+
+ m_bInserted = xPrep->executeUpdate() > 0;
+ bool bAutoValuesFetched = false;
+ if ( m_bInserted )
+ {
+ // first insert the default values into the insertrow
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( !(*_rInsertRow)[columnName.second.nPosition].isModified() )
+ {
+ if(columnName.second.bNullable && columnName.second.sDefaultValue.isEmpty())
+ {
+ (*_rInsertRow)[columnName.second.nPosition].setTypeKind(columnName.second.nType);
+ (*_rInsertRow)[columnName.second.nPosition].setNull();
+ }
+ else
+ {
+ (*_rInsertRow)[columnName.second.nPosition] = columnName.second.sDefaultValue;
+ (*_rInsertRow)[columnName.second.nPosition].setTypeKind(columnName.second.nType);
+ }
+ }
+ }
+ try
+ {
+ Reference< XGeneratedResultSet > xGRes(xPrep, UNO_QUERY);
+ if ( xGRes.is() )
+ {
+ Reference< XResultSet > xRes = xGRes->getGeneratedValues();
+ Reference< XRow > xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ {
+ Reference< XResultSetMetaDataSupplier > xMdSup(xRes,UNO_QUERY);
+ Reference< XResultSetMetaData > xMd = xMdSup->getMetaData();
+ sal_Int32 nColumnCount = xMd->getColumnCount();
+ std::vector< OUString >::const_iterator aAutoIter = m_aAutoColumns.begin();
+ std::vector< OUString >::const_iterator aAutoEnd = m_aAutoColumns.end();
+ for (sal_Int32 j = 1;aAutoIter != aAutoEnd && j <= nColumnCount; ++aAutoIter,++j)
+ {
+ SelectColumnsMetaData::const_iterator aFind = m_pKeyColumnNames->find(*aAutoIter);
+ if ( aFind != m_pKeyColumnNames->end() )
+ (*_rInsertRow)[aFind->second.nPosition].fill(j, aFind->second.nType, xRow);
+ }
+ bAutoValuesFetched = true;
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess", "Could not execute GeneratedKeys() stmt");
+ }
+ }
+
+ ::comphelper::disposeComponent(xPrep);
+
+ if ( i_sTableName.empty() && !bAutoValuesFetched && m_bInserted )
+ {
+ // first check if all key column values were set
+ const OUString sQuote = getIdentifierQuoteString();
+ OUStringBuffer sMaxStmt;
+ auto aEnd = m_pKeyColumnNames->end();
+ for (auto const& autoColumn : m_aAutoColumns)
+ {
+ // we will only fetch values which are keycolumns
+ SelectColumnsMetaData::const_iterator aFind = m_pKeyColumnNames->find(autoColumn);
+ if ( aFind != aEnd )
+ {
+ sMaxStmt.append(" MAX(" + ::dbtools::quoteName( sQuote,aFind->second.sRealName) + "),");
+ }
+ }
+
+ if(!sMaxStmt.isEmpty())
+ {
+ sMaxStmt[sMaxStmt.getLength()-1] = ' ';
+ OUString sStmt = "SELECT " + sMaxStmt + "FROM ";
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xConnection->getMetaData(),m_sUpdateTableName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ sStmt += ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ try
+ {
+ // now fetch the autoincrement values
+ Reference<XStatement> xStatement = m_xConnection->createStatement();
+ Reference<XResultSet> xRes = xStatement->executeQuery(sStmt);
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if(xRow.is() && xRes->next())
+ {
+ sal_Int32 j=1;
+ for (auto const& autoColumn : m_aAutoColumns)
+ {
+ // we will only fetch values which are keycolumns
+ SelectColumnsMetaData::const_iterator aFind = m_pKeyColumnNames->find(autoColumn);
+ if ( aFind != aEnd )
+ (*_rInsertRow)[aFind->second.nPosition].fill(j++, aFind->second.nType, xRow);
+ }
+ }
+ ::comphelper::disposeComponent(xStatement);
+ }
+ catch(SQLException&)
+ {
+ SAL_WARN("dbaccess", "Could not fetch with MAX() ");
+ }
+ }
+ }
+ if ( m_bInserted )
+ {
+ OKeySetMatrix::const_iterator aKeyIter = m_aKeyMap.end();
+ --aKeyIter;
+ ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >(m_pKeyColumnNames->size());
+ copyRowValue(_rInsertRow,aKeyRow,aKeyIter->first + 1);
+
+ m_aKeyIter = m_aKeyMap.emplace( aKeyIter->first + 1, OKeySetValue(aKeyRow,std::pair<sal_Int32,Reference<XRow> >(1,Reference<XRow>())) ).first;
+ // now we set the bookmark for this row
+ (*_rInsertRow)[0] = Any(static_cast<sal_Int32>(m_aKeyIter->first));
+ tryRefetch(_rInsertRow,bRefetch);
+ }
+}
+
+void OKeySet::tryRefetch(const ORowSetRow& _rInsertRow,bool bRefetch)
+{
+ if ( bRefetch )
+ {
+ try
+ {
+ bRefetch = doTryRefetch_throw();
+ }
+ catch(const Exception&)
+ {
+ bRefetch = false;
+ }
+ }
+ if ( !bRefetch )
+ {
+ m_aKeyIter->second.second.second = new OPrivateRow(std::vector(*_rInsertRow));
+ }
+}
+
+void OKeySet::copyRowValue(const ORowSetRow& _rInsertRow, ORowSetRow const & _rKeyRow, sal_Int32 i_nBookmark)
+{
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = _rKeyRow->begin();
+
+ // check the if the parameter values have been changed
+ OSL_ENSURE((m_aParameterValueForCache->size()-1) == m_pParameterNames->size(),"OKeySet::copyRowValue: Parameter values and names differ!");
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaValuesIter = m_aParameterValueForCache->begin() +1;
+
+ bool bChanged = false;
+ sal_Int32 i = 1;
+ for (auto const& parameterName : *m_pParameterNames)
+ {
+ ORowSetValue aValue(*aParaValuesIter);
+ aValue.setSigned(m_aSignedFlags[parameterName.second.nPosition-1]);
+ if ( (*_rInsertRow)[parameterName.second.nPosition] != aValue )
+ {
+ rtl::Reference aCopy(
+ new ORowSetValueVector(*m_aParameterValueForCache));
+ (*aCopy)[i] = (*_rInsertRow)[parameterName.second.nPosition];
+ m_aUpdatedParameter[i_nBookmark] = aCopy;
+ bChanged = true;
+ }
+ ++aParaValuesIter;
+ ++i;
+ }
+ if ( !bChanged )
+ {
+ m_aUpdatedParameter.erase(i_nBookmark);
+ }
+
+ // update the key values
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ impl_convertValue_throw(_rInsertRow,keyColumnName.second);
+ *aIter = (*_rInsertRow)[keyColumnName.second.nPosition];
+ aIter->setTypeKind(keyColumnName.second.nType);
+ ++aIter;
+ }
+}
+
+void OKeySet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("DELETE FROM " + m_aComposedTableName + " WHERE ");
+
+ // list all columns that should be set
+ OUString aQuote = getIdentifierQuoteString();
+ static const char aAnd[] = " AND ";
+
+ // use keys and indexes for exact positioning
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if ( xIndexSup.is() )
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ // Reference<XColumnsSupplier>
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ lcl_fillIndexColumns(xIndexes,aAllIndexColumns);
+
+ OUStringBuffer sIndexCondition;
+ std::vector<sal_Int32> aIndexColumnPositions;
+
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ aSql.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rDeleteRow)[columnName.second.nPosition].isNull())
+ {
+ SAL_WARN("dbaccess", "can a primary key be null");
+ aSql.append(" IS NULL");
+ }
+ else
+ aSql.append(" = ?");
+ aSql.append(aAnd);
+ }
+ else
+ {
+ for (auto const& indexColumn : aAllIndexColumns)
+ {
+ if(indexColumn->hasByName(columnName.first))
+ {
+ sIndexCondition.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rDeleteRow)[columnName.second.nPosition].isNull())
+ sIndexCondition.append(" IS NULL");
+ else
+ {
+ sIndexCondition.append(" = ?");
+ aIndexColumnPositions.push_back(columnName.second.nPosition);
+ }
+ sIndexCondition.append(aAnd);
+
+ break;
+ }
+ }
+ }
+ }
+ aSql.append(sIndexCondition);
+ aSql.setLength(aSql.getLength()-5);
+
+ // now create end execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+
+ // now we have to set the index values
+ auto aIter = m_pColumnNames->begin();
+ for (auto const& indexColumnPosition : aIndexColumnPositions)
+ {
+ setParameter(i++,xParameter,(*_rDeleteRow)[indexColumnPosition],(*_rDeleteRow)[indexColumnPosition].getTypeKind(),aIter->second.nScale);
+ ++aIter;
+ }
+
+ m_bDeleted = xPrep->executeUpdate() > 0;
+
+ if(m_bDeleted)
+ {
+ sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
+ if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
+ ++m_aKeyIter;
+ m_aKeyMap.erase(nBookmark);
+ m_bDeleted = true;
+ }
+}
+
+bool OKeySet::next()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+
+ if(isAfterLast())
+ return false;
+ ++m_aKeyIter;
+ if(!m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end())
+ {
+ // not yet all records fetched, but we reached the end of those we fetched
+ // try to fetch one more row
+ if (fetchRow())
+ {
+ OSL_ENSURE(!isAfterLast(), "fetchRow succeeded, but isAfterLast()");
+ return true;
+ }
+ else
+ {
+ // nope, we arrived at end of data
+ m_aKeyIter = m_aKeyMap.end();
+ OSL_ENSURE(isAfterLast(), "fetchRow failed, but not end of data");
+ }
+ }
+
+ invalidateRow();
+ return !isAfterLast();
+}
+
+bool OKeySet::isBeforeFirst( )
+{
+ return m_aKeyIter == m_aKeyMap.begin();
+}
+
+bool OKeySet::isAfterLast( )
+{
+ return m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end();
+}
+
+void OKeySet::beforeFirst( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aKeyIter = m_aKeyMap.begin();
+ invalidateRow();
+}
+
+void OKeySet::afterLast( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ fillAllRows();
+ m_aKeyIter = m_aKeyMap.end();
+ invalidateRow();
+}
+
+bool OKeySet::first()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aKeyIter = m_aKeyMap.begin();
+ ++m_aKeyIter;
+ if(m_aKeyIter == m_aKeyMap.end())
+ {
+ if (!fetchRow())
+ {
+ m_aKeyIter = m_aKeyMap.end();
+ return false;
+ }
+ }
+ else
+ invalidateRow();
+ return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
+}
+
+bool OKeySet::last( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ bool bFetchedRow = fillAllRows();
+
+ m_aKeyIter = m_aKeyMap.end();
+ --m_aKeyIter;
+ if ( !bFetchedRow )
+ {
+ invalidateRow();
+ }
+ return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
+}
+
+sal_Int32 OKeySet::getRow( )
+{
+ OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
+ OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
+
+ return std::distance(m_aKeyMap.begin(),m_aKeyIter);
+}
+
+bool OKeySet::absolute( sal_Int32 row )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ OSL_ENSURE(row,"absolute(0) isn't allowed!");
+ bool bFetchedRow = false;
+ if(row < 0)
+ {
+ if(!m_bRowCountFinal)
+ bFetchedRow = fillAllRows();
+
+ row = std::min(std::abs(row), static_cast<sal_Int32>(std::distance(m_aKeyMap.begin(), m_aKeyIter)));
+ m_aKeyIter = std::prev(m_aKeyIter, row);
+ }
+ else
+ {
+ if(row >= static_cast<sal_Int32>(m_aKeyMap.size()))
+ {
+ // we don't have this row
+ if(!m_bRowCountFinal)
+ {
+ // but there may still be rows to fetch.
+ bool bNext = true;
+ for(sal_Int32 i=m_aKeyMap.size()-1;i < row && bNext;++i)
+ bNext = fetchRow();
+ // it is guaranteed that the above loop has executed at least once,
+ // that is fetchRow called at least once.
+ if ( bNext )
+ {
+ bFetchedRow = true;
+ }
+ else
+ {
+ // reached end of data before desired row
+ m_aKeyIter = m_aKeyMap.end();
+ return false;
+ }
+ }
+ else
+ {
+ // no more rows to fetch -> fail
+ m_aKeyIter = m_aKeyMap.end();
+ return false;
+ }
+ }
+ else
+ {
+ m_aKeyIter = std::next(m_aKeyMap.begin(), row);
+ }
+ }
+ if ( !bFetchedRow )
+ {
+ invalidateRow();
+ }
+
+ return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
+}
+
+bool OKeySet::previous()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ if(m_aKeyIter != m_aKeyMap.begin())
+ {
+ --m_aKeyIter;
+ invalidateRow();
+ }
+ return m_aKeyIter != m_aKeyMap.begin();
+}
+
+bool OKeySet::doTryRefetch_throw()
+{
+ ensureStatement( );
+ // we just reassign the base members
+ Reference< XParameters > xParameter(m_xStatement,UNO_QUERY);
+ OSL_ENSURE(xParameter.is(),"No Parameter interface!");
+ xParameter->clearParameters();
+
+ sal_Int32 nPos=1;
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaIter;
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaEnd;
+ OUpdatedParameter::const_iterator aUpdateFind = m_aUpdatedParameter.find(m_aKeyIter->first);
+ if ( aUpdateFind == m_aUpdatedParameter.end() )
+ {
+ aParaIter = m_aParameterValueForCache->begin();
+ aParaEnd = m_aParameterValueForCache->end();
+ }
+ else
+ {
+ aParaIter = aUpdateFind->second->begin();
+ aParaEnd = aUpdateFind->second->end();
+ }
+
+ for(++aParaIter;aParaIter != aParaEnd;++aParaIter,++nPos)
+ {
+ ::dbtools::setObjectWithInfo( xParameter, nPos, aParaIter->makeAny(), aParaIter->getTypeKind() );
+ }
+
+ // now set the primary key column values
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->begin();
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ setOneKeyColumnParameter(nPos,xParameter,*aIter++,keyColumnName.second.nType,keyColumnName.second.nScale);
+ for (auto const& foreignColumnName : *m_pForeignColumnNames)
+ setOneKeyColumnParameter(nPos,xParameter,*aIter++,foreignColumnName.second.nType,foreignColumnName.second.nScale);
+
+ m_xSet = m_xStatement->executeQuery();
+ OSL_ENSURE(m_xSet.is(),"No resultset from statement!");
+ return m_xSet->next();
+}
+
+void OKeySet::refreshRow()
+{
+ invalidateRow();
+
+ if(isBeforeFirst() || isAfterLast())
+ return;
+
+ if ( m_aKeyIter->second.second.second.is() )
+ {
+ m_xRow = m_aKeyIter->second.second.second;
+ return;
+ }
+
+ bool bOK = doTryRefetch_throw();
+ if ( !bOK )
+ {
+ // This row has disappeared; remove it.
+ OKeySetMatrix::const_iterator aTemp = m_aKeyIter;
+ // use *next* row
+ ++m_aKeyIter;
+ m_aKeyMap.erase(aTemp);
+
+ // adjust RowCount for the row we have removed
+ if (m_rRowCount > 0)
+ --m_rRowCount;
+ else
+ SAL_WARN("dbaccess", "m_rRowCount got out of sync: non-empty m_aKeyMap, but m_rRowCount <= 0");
+
+ if (m_aKeyIter == m_aKeyMap.end())
+ {
+ ::comphelper::disposeComponent(m_xSet);
+ if (!isAfterLast())
+ {
+ // it was the last fetched row,
+ // but there may be another one to fetch
+ if (!fetchRow())
+ {
+ // nope, that really was the last
+ m_aKeyIter = m_aKeyMap.end();
+ OSL_ENSURE(isAfterLast(), "fetchRow() failed but not isAfterLast()!");
+ }
+ }
+ // Now, either fetchRow has set m_xRow or isAfterLast()
+ }
+ else
+ {
+ refreshRow();
+ }
+ }
+ else
+ {
+ m_xRow.set(m_xSet,UNO_QUERY);
+ OSL_ENSURE(m_xRow.is(),"No row from statement!");
+ }
+}
+
+bool OKeySet::fetchRow()
+{
+ // fetch the next row and append on the keyset
+ bool bRet = false;
+ if ( !m_bRowCountFinal && (!m_nMaxRows || sal_Int32(m_aKeyMap.size()) < m_nMaxRows) )
+ bRet = m_xDriverSet->next();
+ if ( bRet )
+ {
+ ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >((*m_pKeyColumnNames).size() + m_pForeignColumnNames->size());
+
+ ::comphelper::disposeComponent(m_xSet);
+ m_xRow.set(m_xDriverRow, UNO_SET_THROW);
+
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = aKeyRow->begin();
+ // copy key columns
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ const SelectColumnDescription& rColDesc = keyColumnName.second;
+ aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xRow);
+ ++aIter;
+ }
+ // copy missing columns from other tables
+ for (auto const& foreignColumnName : *m_pForeignColumnNames)
+ {
+ const SelectColumnDescription& rColDesc = foreignColumnName.second;
+ aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xRow);
+ ++aIter;
+ }
+ m_aKeyIter = m_aKeyMap.emplace( m_aKeyMap.rbegin()->first+1,OKeySetValue(aKeyRow,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>())) ).first;
+ }
+ else
+ m_bRowCountFinal = true;
+ return bRet;
+}
+
+bool OKeySet::fillAllRows()
+{
+ if(m_bRowCountFinal)
+ {
+ return false;
+ }
+ else
+ {
+ while(fetchRow())
+ ;
+ return true;
+ }
+}
+
+// XRow
+sal_Bool SAL_CALL OKeySet::wasNull( )
+{
+ if ( ! m_xRow.is() )
+ throwGenericSQLException("Must call getFOO() for some FOO before wasNull()", *this);
+
+ OSL_ENSURE(m_xRow.is(),"m_xRow is null! I've thrown, but function execution continued?");
+ return m_xRow->wasNull();
+}
+
+inline void OKeySet::ensureRowForData( )
+{
+ if (! m_xRow.is() )
+ refreshRow();
+ if (! m_xRow.is() )
+ throwSQLException("Failed to refetch row", "02000", *this, -2);
+
+ OSL_ENSURE(m_xRow.is(),"m_xRow is null! I've called throwSQLException but execution continued?");
+}
+
+OUString SAL_CALL OKeySet::getString( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getString(columnIndex);
+}
+
+sal_Bool SAL_CALL OKeySet::getBoolean( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBoolean(columnIndex);
+}
+
+sal_Int8 SAL_CALL OKeySet::getByte( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getByte(columnIndex);
+}
+
+sal_Int16 SAL_CALL OKeySet::getShort( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getShort(columnIndex);
+}
+
+sal_Int32 SAL_CALL OKeySet::getInt( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getInt(columnIndex);
+}
+
+sal_Int64 SAL_CALL OKeySet::getLong( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getLong(columnIndex);
+}
+
+float SAL_CALL OKeySet::getFloat( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getFloat(columnIndex);
+}
+
+double SAL_CALL OKeySet::getDouble( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getDouble(columnIndex);
+}
+
+Sequence< sal_Int8 > SAL_CALL OKeySet::getBytes( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBytes(columnIndex);
+}
+
+css::util::Date SAL_CALL OKeySet::getDate( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getDate(columnIndex);
+}
+
+css::util::Time SAL_CALL OKeySet::getTime( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getTime(columnIndex);
+}
+
+css::util::DateTime SAL_CALL OKeySet::getTimestamp( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getTimestamp(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OKeySet::getBinaryStream( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OKeySet::getCharacterStream( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getCharacterStream(columnIndex);
+}
+
+Any SAL_CALL OKeySet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap )
+{
+ ensureRowForData();
+ return m_xRow->getObject(columnIndex,typeMap);
+}
+
+Reference< XRef > SAL_CALL OKeySet::getRef( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getRef(columnIndex);
+}
+
+Reference< XBlob > SAL_CALL OKeySet::getBlob( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBlob(columnIndex);
+}
+
+Reference< XClob > SAL_CALL OKeySet::getClob( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getClob(columnIndex);
+}
+
+Reference< XArray > SAL_CALL OKeySet::getArray( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getArray(columnIndex);
+}
+
+bool OKeySet::rowUpdated( )
+{
+ return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second.first == 2;
+}
+
+bool OKeySet::rowInserted( )
+{
+ return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second.first == 1;
+}
+
+bool OKeySet::rowDeleted( )
+{
+ bool bDeleted = m_bDeleted;
+ m_bDeleted = false;
+ return bDeleted;
+}
+
+namespace dbaccess
+{
+
+void getColumnPositions(const Reference<XNameAccess>& _rxQueryColumns,
+ const css::uno::Sequence< OUString >& _aColumnNames,
+ std::u16string_view _rsUpdateTableName,
+ SelectColumnsMetaData& o_rColumnNames,
+ bool i_bAppendTableName)
+ {
+ // get the real name of the columns
+ Sequence< OUString> aSelNames(_rxQueryColumns->getElementNames());
+ const OUString* pSelIter = aSelNames.getConstArray();
+ const OUString* pSelEnd = pSelIter + aSelNames.getLength();
+
+ const OUString* pTblColumnIter = _aColumnNames.getConstArray();
+ const OUString* pTblColumnEnd = pTblColumnIter + _aColumnNames.getLength();
+
+ ::comphelper::UStringMixEqual bCase(o_rColumnNames.key_comp().isCaseSensitive());
+
+ for(sal_Int32 nPos = 1;pSelIter != pSelEnd;++pSelIter,++nPos)
+ {
+ Reference<XPropertySet> xQueryColumnProp(_rxQueryColumns->getByName(*pSelIter),UNO_QUERY_THROW);
+ OUString sRealName,sTableName;
+ OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
+ OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
+ xQueryColumnProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ xQueryColumnProp->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
+
+ for(;pTblColumnIter != pTblColumnEnd;++pTblColumnIter)
+ {
+ if(bCase(sRealName,*pTblColumnIter) && bCase(_rsUpdateTableName,sTableName) && o_rColumnNames.find(*pTblColumnIter) == o_rColumnNames.end())
+ {
+ sal_Int32 nType = 0;
+ xQueryColumnProp->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ sal_Int32 nScale = 0;
+ xQueryColumnProp->getPropertyValue(PROPERTY_SCALE) >>= nScale;
+ OUString sColumnDefault;
+ if ( xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE) )
+ xQueryColumnProp->getPropertyValue(PROPERTY_DEFAULTVALUE) >>= sColumnDefault;
+
+ sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
+ OSL_VERIFY( xQueryColumnProp->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
+
+ SelectColumnDescription aColDesc( nPos, nType, nScale, nNullable != sdbc::ColumnValue::NO_NULLS, sColumnDefault );
+ OUString sName;
+ if ( i_bAppendTableName )
+ {
+ sName = sTableName + "." + sRealName;
+ aColDesc.sRealName = sRealName;
+ aColDesc.sTableName = sTableName;
+ }
+ else
+ {
+ sName = sRealName;
+ }
+ o_rColumnNames[sName] = aColDesc;
+
+ break;
+ }
+ }
+ pTblColumnIter = _aColumnNames.getConstArray();
+ }
+ }
+}
+
+void OKeySet::impl_convertValue_throw(const ORowSetRow& _rInsertRow,const SelectColumnDescription& i_aMetaData)
+{
+ ORowSetValue& aValue((*_rInsertRow)[i_aMetaData.nPosition]);
+ switch(i_aMetaData.nType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ {
+ OUString sValue = aValue.getString();
+ sal_Int32 nIndex = sValue.indexOf('.');
+ if ( nIndex != -1 )
+ {
+ aValue = sValue.copy(0,std::min(sValue.getLength(),nIndex + (i_aMetaData.nScale > 0 ? i_aMetaData.nScale + 1 : 0)));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/KeySet.hxx b/dbaccess/source/core/api/KeySet.hxx
new file mode 100644
index 000000000..57889c774
--- /dev/null
+++ b/dbaccess/source/core/api/KeySet.hxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+
+#include <memory>
+#include <map>
+#include <vector>
+
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <comphelper/stl_types.hxx>
+
+namespace dbaccess
+{
+ struct SelectColumnDescription
+ {
+ OUString sRealName; // may be empty
+ OUString sTableName; // may be empty
+ OUString sDefaultValue;
+ sal_Int32 nPosition;
+ sal_Int32 nType;
+ sal_Int32 nScale;
+ bool bNullable;
+
+ SelectColumnDescription()
+ :nPosition( 0 )
+ ,nType( 0 )
+ ,nScale( 0 )
+ ,bNullable(false)
+ {
+ }
+
+ SelectColumnDescription( sal_Int32 _nPosition, sal_Int32 _nType, sal_Int32 _nScale,bool _bNullable, const OUString& _rDefaultValue )
+ :sDefaultValue( _rDefaultValue )
+ ,nPosition( _nPosition )
+ ,nType( _nType )
+ ,nScale( _nScale )
+ ,bNullable(_bNullable)
+ {
+ }
+ };
+ typedef std::map< OUString, SelectColumnDescription, ::comphelper::UStringMixLess > SelectColumnsMetaData;
+
+ // the elements of _rxQueryColumns must have the properties PROPERTY_REALNAME and PROPERTY_TABLENAME
+ void getColumnPositions(const css::uno::Reference< css::container::XNameAccess >& _rxQueryColumns,
+ const css::uno::Sequence< OUString >& _rColumnNames,
+ std::u16string_view _rsUpdateTableName,
+ SelectColumnsMetaData& o_rColumnNames /* out */,
+ bool i_bAppendTableName = false);
+
+ typedef std::pair<ORowSetRow,std::pair<sal_Int32,css::uno::Reference< css::sdbc::XRow> > > OKeySetValue;
+ typedef std::map<sal_Int32,OKeySetValue > OKeySetMatrix;
+ typedef std::map<sal_Int32, rtl::Reference<ORowSetValueVector> > OUpdatedParameter;
+ // is used when the source supports keys
+ class OKeySet : public OCacheSet
+ {
+ protected:
+ OKeySetMatrix m_aKeyMap;
+ OKeySetMatrix::iterator m_aKeyIter;
+
+ std::vector< OUString > m_aAutoColumns; // contains all columns which are autoincrement ones
+
+ OUpdatedParameter m_aUpdatedParameter; // contains all parameter which have been updated and are needed for refetching
+ rtl::Reference<ORowSetValueVector> m_aParameterValueForCache;
+ std::unique_ptr<SelectColumnsMetaData> m_pKeyColumnNames; // contains all key column names
+ std::unique_ptr<SelectColumnsMetaData> m_pColumnNames; // contains all column names
+ std::unique_ptr<SelectColumnsMetaData> m_pParameterNames; // contains all parameter names
+ std::unique_ptr<SelectColumnsMetaData> m_pForeignColumnNames; // contains all column names of the rest
+ connectivity::OSQLTable m_xTable; // reference to our table
+ // we need a different SQL (statement) for each different combination
+ // of NULLness of key & foreign columns;
+ // each subclause is either "colName = ?" or "colName IS NULL"
+ // (we avoid the standard "colName IS NOT DISTINCT FROM ?" because it is not widely supported)
+ typedef std::map< std::vector<bool>,
+ css::uno::Reference< css::sdbc::XPreparedStatement > >
+ vStatements_t;
+ vStatements_t m_vStatements;
+ css::uno::Reference< css::sdbc::XPreparedStatement> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSet> m_xSet;
+ css::uno::Reference< css::sdbc::XRow> m_xRow;
+ css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer > m_xComposer;
+ const OUString m_sUpdateTableName;
+ std::vector< OUString > m_aFilterColumns;
+ sal_Int32& m_rRowCount;
+
+ bool m_bRowCountFinal;
+
+ /** copies the values from the insert row into the key row
+ *
+ * \param _rInsertRow the row which was inserted
+ * \param _rKeyRow The current key row of the row set.
+ + \param i_nBookmark The bookmark is used to update the parameter
+ */
+ void copyRowValue(const ORowSetRow& _rInsertRow, ORowSetRow const & _rKeyRow, sal_Int32 i_nBookmark);
+
+ // returns true if it did any work
+ bool fillAllRows();
+ bool fetchRow();
+ void invalidateRow();
+
+ static void impl_convertValue_throw(const ORowSetRow& _rInsertRow,const SelectColumnDescription& i_aMetaData);
+ void initColumns();
+ void findTableColumnsMatching_throw( const css::uno::Any& i_aTable,
+ const OUString& i_rUpdateTableName,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData>& i_xMeta,
+ const css::uno::Reference< css::container::XNameAccess>& i_xQueryColumns,
+ std::unique_ptr<SelectColumnsMetaData> const & o_pKeyColumnNames);
+ void ensureStatement( );
+ virtual void makeNewStatement( );
+ static void setOneKeyColumnParameter( sal_Int32 &nPos,
+ const css::uno::Reference< css::sdbc::XParameters > &_xParameter,
+ const connectivity::ORowSetValue &_rValue,
+ sal_Int32 _nType,
+ sal_Int32 _nScale );
+ OUStringBuffer createKeyFilter( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool doTryRefetch_throw();
+ void tryRefetch(const ORowSetRow& _rInsertRow,bool bRefetch);
+ void executeUpdate(const ORowSetRow& _rInsertRow, const ORowSetRow& _rOriginalRow, const OUString& i_sSQL, std::u16string_view i_sTableName,const std::vector<sal_Int32>& _aIndexColumnPositions = std::vector<sal_Int32>());
+ void executeInsert( const ORowSetRow& _rInsertRow, const OUString& i_sSQL, std::u16string_view i_sTableName, bool bRefetch = false);
+ void executeStatement(OUStringBuffer& io_aFilter, css::uno::Reference< css::sdb::XSingleSelectQueryComposer>& io_xAnalyzer);
+
+ virtual ~OKeySet() override;
+ public:
+ OKeySet(const connectivity::OSQLTable& _xTable,
+ const OUString& _rUpdateTableName,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount);
+
+ // late ctor which can throw exceptions
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+
+ virtual bool rowUpdated( ) override;
+ virtual bool rowInserted( ) override;
+ virtual bool rowDeleted( ) override;
+ bool isBeforeFirst( );
+ bool isAfterLast( );
+
+ // css::sdbc::XResultSet
+ virtual bool next() override;
+ virtual void beforeFirst( ) override;
+ virtual void afterLast( ) override;
+ virtual bool first() override;
+ virtual bool last( ) override;
+ virtual sal_Int32 getRow( ) override;
+ virtual bool absolute( sal_Int32 row ) override;
+ virtual bool previous( ) override;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void ensureRowForData( );
+ virtual void refreshRow( ) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+
+ virtual bool hasOrderedBookmarks( ) override;
+
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/OptimisticSet.cxx b/dbaccess/source/core/api/OptimisticSet.cxx
new file mode 100644
index 000000000..d1d70955f
--- /dev/null
+++ b/dbaccess/source/core/api/OptimisticSet.cxx
@@ -0,0 +1,586 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include "OptimisticSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <map>
+#include <algorithm>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <composertools.hxx>
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star;
+using namespace ::cppu;
+using namespace ::osl;
+
+typedef std::map<OUString, OUStringBuffer> TSQLStatements;
+namespace
+{
+ void lcl_fillKeyCondition(const OUString& i_sTableName,std::u16string_view i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
+ {
+ OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
+ if ( !rKeyCondition.isEmpty() )
+ rKeyCondition.append(" AND ");
+ rKeyCondition.append(i_sQuotedColumnName);
+ if ( i_aValue.isNull() )
+ rKeyCondition.append(" IS NULL");
+ else
+ rKeyCondition.append(" = ?");
+ }
+}
+
+
+OptimisticSet::OptimisticSet(const Reference<XComponentContext>& _rContext,
+ const Reference< XConnection>& i_xConnection,
+ const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount)
+ :OKeySet(nullptr,OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
+ ,m_aSqlParser( _rContext )
+ ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY_THROW)->getTables(), m_aSqlParser )
+ ,m_bResultSetChanged(false)
+{
+}
+
+OptimisticSet::~OptimisticSet()
+{
+}
+
+void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+
+ initColumns();
+ m_sRowSetFilter = i_sRowSetFilter;
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
+ const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
+ const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
+ const Reference<XNameAccess> xTables = xTabSup->getTables();
+ const Sequence< OUString> aTableNames = xTables->getElementNames();
+ const OUString* pTableNameIter = aTableNames.getConstArray();
+ const OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
+ for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
+ {
+ std::unique_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase));
+ findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
+ m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
+ }
+
+ // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
+ // without extra variable to be set
+ OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
+ m_aKeyMap.emplace(0,keySetValue);
+ m_aKeyIter = m_aKeyMap.begin();
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ OUString sQuery = xSourceComposer->getQuery();
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+ // check for joins
+ OUString aErrorMsg;
+ std::unique_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
+ m_aSqlIterator.setParseTree( pStatementNode.get() );
+ m_aSqlIterator.traverseAll();
+ fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
+
+}
+
+void OptimisticSet::makeNewStatement( )
+{
+ OUStringBuffer aFilter = createKeyFilter();
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+
+ const OUString sComposerFilter = m_xComposer->getFilter();
+ if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
+ {
+ FilterCreator aFilterCreator;
+ if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
+ aFilterCreator.append( sComposerFilter );
+ aFilterCreator.append( m_sRowSetFilter );
+ aFilterCreator.append( aFilter.makeStringAndClear() );
+ aFilter = aFilterCreator.getComposedAndClear();
+ }
+ xAnalyzer->setFilter(aFilter.makeStringAndClear());
+ m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
+ ::comphelper::disposeComponent(xAnalyzer);
+}
+
+void OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ if ( m_aJoinedKeyColumns.empty() )
+ throw SQLException();
+ // list all columns that should be set
+ OUString aQuote = getIdentifierQuoteString();
+
+ std::map< OUString,bool > aResultSetChanged;
+ TSQLStatements aKeyConditions;
+ TSQLStatements aSql;
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ aResultSetChanged.try_emplace(columnName.second.sTableName, false);
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ aResultSetChanged[columnName.second.sTableName] = m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end();
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rOriginalRow)[columnName.second.nPosition],aKeyConditions);
+ }
+ if((*_rInsertRow)[columnName.second.nPosition].isModified())
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ throw SQLException();
+
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName + " = ?");
+ }
+ }
+
+ if( aSql.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ if( aKeyConditions.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUStringBuffer sSql("UPDATE " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
+ " SET " + elem.second);
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ sSql.append(" WHERE " + rCondition );
+
+ executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),elem.first);
+ }
+ }
+}
+
+void OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ TSQLStatements aSql;
+ TSQLStatements aParameter;
+ TSQLStatements aKeyConditions;
+ std::map< OUString,bool > aResultSetChanged;
+ OUString aQuote = getIdentifierQuoteString();
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ aResultSetChanged.try_emplace(columnName.second.sTableName, false);
+
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( (*_rInsertRow)[columnName.second.nPosition].isModified() )
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ {
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rInsertRow)[columnName.second.nPosition],aKeyConditions);
+ aResultSetChanged[columnName.second.sTableName] = true;
+ }
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName);
+ OUStringBuffer& rParam = aParameter[columnName.second.sTableName];
+ if ( !rParam.isEmpty() )
+ rParam.append(", ");
+ rParam.append("?");
+ }
+ }
+ if ( aParameter.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ OUString sSql("INSERT INTO " + sComposedTableName + " ( " + elem.second +
+ ") VALUES ( " + aParameter[elem.first] + " )");
+
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName +
+ " WHERE " + rCondition);
+
+ try
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ // and then the values of the where condition
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( keyColumnName.second.sTableName == elem.first )
+ {
+ setParameter(i++,xParameter,(*_rInsertRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+ }
+ Reference<XResultSet> xRes = xPrep->executeQuery();
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ {
+ m_bResultSetChanged = true;
+ continue;
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+
+ executeInsert(_rInsertRow,sSql,elem.first);
+ }
+ }
+}
+
+void OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ OUString aQuote = getIdentifierQuoteString();
+ TSQLStatements aKeyConditions;
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ // only delete rows which aren't the key in the join
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rDeleteRow)[columnName.second.nPosition],aKeyConditions);
+ }
+ }
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto & keyCondition : aKeyConditions)
+ {
+ OUStringBuffer& rCondition = keyCondition.second;
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,keyCondition.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
+ " WHERE " + rCondition );
+ executeDelete(_rDeleteRow, sSql, keyCondition.first);
+ }
+ }
+}
+
+void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,std::u16string_view i_sTableName)
+{
+ // now create and execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( keyColumnName.second.sTableName == i_sTableName )
+ setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+ m_bDeleted = xPrep->executeUpdate() > 0;
+
+ if(m_bDeleted)
+ {
+ sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
+ if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
+ ++m_aKeyIter;
+ m_aKeyMap.erase(nBookmark);
+ m_bDeleted = true;
+ }
+}
+
+void OptimisticSet::fillJoinedColumns_throw(const std::vector< TNodePair >& i_aJoinColumns)
+{
+ for (auto const& joinColumn : i_aJoinColumns)
+ {
+ OUString sColumnName,sTableName;
+ m_aSqlIterator.getColumnRange(joinColumn.first,sColumnName,sTableName);
+ OUString sLeft(sTableName + "." + sColumnName);
+ m_aSqlIterator.getColumnRange(joinColumn.second,sColumnName,sTableName);
+ OUString sRight(sTableName + "." + sColumnName);
+ fillJoinedColumns_throw(sLeft, sRight);
+ }
+}
+
+void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn)
+{
+ sal_Int32 nLeft = 0,nRight = 0;
+ SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
+ SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
+
+ bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
+ if ( bLeftKey )
+ {
+ nLeft = aLeftIter->second.nPosition;
+ }
+ else
+ {
+ aLeftIter = m_pColumnNames->find(i_sLeftColumn);
+ if ( aLeftIter != m_pColumnNames->end() )
+ nLeft = aLeftIter->second.nPosition;
+ }
+
+ bool bRightKey = aRightIter != m_pKeyColumnNames->end();
+ if ( bRightKey )
+ {
+ nRight = aRightIter->second.nPosition;
+ }
+ else
+ {
+ aRightIter = m_pColumnNames->find(i_sRightColumn);
+ if ( aRightIter != m_pColumnNames->end() )
+ nRight = aRightIter->second.nPosition;
+ }
+
+ if (bLeftKey)
+ m_aJoinedKeyColumns[nLeft] = nRight;
+ else
+ m_aJoinedColumns[nLeft] = nRight;
+ if (bRightKey)
+ m_aJoinedKeyColumns[nRight] = nLeft;
+ else
+ m_aJoinedColumns[nRight] = nLeft;
+}
+
+bool OptimisticSet::isResultSetChanged() const
+{
+ bool bOld = m_bResultSetChanged;
+ m_bResultSetChanged = false;
+ return bOld;
+}
+
+void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns)
+{
+ o_aChangedColumns.push_back(i_nColumnIndex);
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
+ io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
+ io_aRow[aJoinIter->second].setModified(true);
+ o_aChangedColumns.push_back(aJoinIter->second);
+ }
+}
+
+bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns)
+{
+ bool bRet = false;
+ for( const auto& aColIdx : i_aChangedColumns )
+ {
+ SelectColumnsMetaData::const_iterator aFind = std::find_if(
+ m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&aColIdx]( const SelectColumnsMetaData::value_type& aType )
+ { return aType.second.nPosition == aColIdx; } );
+ if ( aFind != m_pKeyColumnNames->end() )
+ {
+ const OUString sTableName = aFind->second.sTableName;
+ aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&sTableName]
+ ( const SelectColumnsMetaData::value_type& rCurr )
+ { return rCurr.second.sTableName == sTableName; } );
+ while( aFind != m_pKeyColumnNames->end() )
+ {
+ io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
+ if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
+ break;
+ ++aFind;
+ }
+ if ( aFind == m_pKeyColumnNames->end() )
+ {
+ bRet = true;
+ for( const auto& aCol : *m_pColumnNames )
+ {
+ if ( aCol.second.sTableName == sTableName )
+ {
+ io_aRow[aCol.second.nPosition] = io_aCachedRow[aCol.second.nPosition];
+ io_aRow[aCol.second.nPosition].setModified(true);
+ }
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
+{
+ bool bRet = false;
+ for( const auto& aCol : *m_pColumnNames )
+ {
+ sal_Int32 nPos = aCol.second.nPosition;
+ SelectColumnsMetaData::const_iterator aFind = std::find_if(
+ m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&nPos] ( const SelectColumnsMetaData::value_type& aType )
+ { return aType.second.nPosition == nPos; } );
+ if ( aFind != m_pKeyColumnNames->end() )
+ {
+ const OUString sTableName = aFind->second.sTableName;
+ aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&sTableName]
+ ( const SelectColumnsMetaData::value_type& rCurr )
+ { return rCurr.second.sTableName == sTableName; } );
+ while( aFind != m_pKeyColumnNames->end() )
+ {
+ o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
+ if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
+ break;
+ ++aFind;
+ }
+ if ( aFind == m_pKeyColumnNames->end() )
+ {
+ bRet = true;
+ for( const auto& aCol2 : *m_pColumnNames )
+ {
+ if ( aCol2.second.sTableName == sTableName )
+ {
+ o_aCachedRow[aCol2.second.nPosition] = i_aRow[aCol2.second.nPosition];
+ o_aCachedRow[aCol2.second.nPosition].setModified(true);
+ }
+ }
+ fillMissingValues(o_aCachedRow);
+ }
+ }
+ }
+ return bRet;
+}
+
+void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
+{
+ TSQLStatements aSql;
+ TSQLStatements aKeyConditions;
+ OUString aQuote = getIdentifierQuoteString();
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ {
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,io_aRow[columnName.second.nPosition],aKeyConditions);
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName);
+ }
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName + " WHERE " + rCondition);
+ rCondition.setLength(0);
+
+ try
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ // and then the values of the where condition
+ sal_Int32 i = 1;
+ for (auto const& keyColumn : *m_pKeyColumnNames)
+ {
+ if ( keyColumn.second.sTableName == elem.first )
+ {
+ setParameter(i++,xParameter,io_aRow[keyColumn.second.nPosition],keyColumn.second.nType,keyColumn.second.nScale);
+ }
+ }
+ Reference<XResultSet> xRes = xPrep->executeQuery();
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ {
+ i = 1;
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( columnName.second.sTableName == elem.first )
+ {
+ io_aRow[columnName.second.nPosition].fill(i++, columnName.second.nType, xRow);
+ io_aRow[columnName.second.nPosition].setModified(true);
+ }
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/OptimisticSet.hxx b/dbaccess/source/core/api/OptimisticSet.hxx
new file mode 100644
index 000000000..bf5e3a803
--- /dev/null
+++ b/dbaccess/source/core/api/OptimisticSet.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "KeySet.hxx"
+
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqliterator.hxx>
+
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+
+namespace dbaccess
+{
+ // is used when the source supports keys
+ class OptimisticSet : public OKeySet
+ {
+ ::connectivity::OSQLParser m_aSqlParser;
+ ::connectivity::OSQLParseTreeIterator m_aSqlIterator;
+
+ std::map<sal_Int32,sal_Int32> m_aJoinedColumns;
+ std::map<sal_Int32,sal_Int32> m_aJoinedKeyColumns;
+
+ mutable bool m_bResultSetChanged;
+
+ void executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,std::u16string_view i_sTableName);
+ void fillJoinedColumns_throw(const std::vector< ::connectivity::TNodePair>& i_aJoinColumns);
+ void fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn);
+ protected:
+ virtual void makeNewStatement( ) override;
+ virtual ~OptimisticSet() override;
+ public:
+ OptimisticSet(const css::uno::Reference< css::uno::XComponentContext>& _rContext,
+ const css::uno::Reference< css::sdbc::XConnection>& i_xConnection,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount);
+
+ // late ctor which can throw exceptions
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+
+ // CacheSet
+ virtual bool isResultSetChanged() const override;
+ virtual void mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns) override;
+ virtual bool columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow) override;
+ virtual bool updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns) override;
+ virtual void fillMissingValues(ORowSetValueVector::Vector& io_aRow) const override;
+
+ bool isReadOnly() const { return m_aJoinedKeyColumns.empty(); }
+ const std::map<sal_Int32,sal_Int32>& getJoinedKeyColumns() const { return m_aJoinedKeyColumns; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/PrivateRow.cxx b/dbaccess/source/core/api/PrivateRow.cxx
new file mode 100644
index 000000000..9bf270960
--- /dev/null
+++ b/dbaccess/source/core/api/PrivateRow.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PrivateRow.hxx"
+
+using namespace dbaccess;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star;
+
+sal_Bool SAL_CALL OPrivateRow::wasNull( )
+ {
+ return m_aRow[m_nPos].isNull();
+ }
+ OUString SAL_CALL OPrivateRow::getString( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getString();
+ }
+ sal_Bool SAL_CALL OPrivateRow::getBoolean( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getBool();
+ }
+ ::sal_Int8 SAL_CALL OPrivateRow::getByte( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getInt8();
+ }
+ ::sal_Int16 SAL_CALL OPrivateRow::getShort( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getInt16();
+ }
+ ::sal_Int32 SAL_CALL OPrivateRow::getInt( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getInt32();
+ }
+ ::sal_Int64 SAL_CALL OPrivateRow::getLong( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getLong();
+ }
+ float SAL_CALL OPrivateRow::getFloat( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getFloat();
+ }
+ double SAL_CALL OPrivateRow::getDouble( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getDouble();
+ }
+ Sequence< ::sal_Int8 > SAL_CALL OPrivateRow::getBytes( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getSequence();
+ }
+ css::util::Date SAL_CALL OPrivateRow::getDate( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getDate();
+ }
+ css::util::Time SAL_CALL OPrivateRow::getTime( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getTime();
+ }
+ css::util::DateTime SAL_CALL OPrivateRow::getTimestamp( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getDateTime();
+ }
+ Reference< css::io::XInputStream > SAL_CALL OPrivateRow::getBinaryStream( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< css::io::XInputStream >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< css::io::XInputStream > SAL_CALL OPrivateRow::getCharacterStream( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< css::io::XInputStream >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Any SAL_CALL OPrivateRow::getObject( ::sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].makeAny();
+ }
+ Reference< XRef > SAL_CALL OPrivateRow::getRef( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XRef >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< XBlob > SAL_CALL OPrivateRow::getBlob( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XBlob >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< XClob > SAL_CALL OPrivateRow::getClob( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XClob >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< XArray > SAL_CALL OPrivateRow::getArray( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XArray >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/PrivateRow.hxx b/dbaccess/source/core/api/PrivateRow.hxx
new file mode 100644
index 000000000..c5ce74f15
--- /dev/null
+++ b/dbaccess/source/core/api/PrivateRow.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include "RowSetRow.hxx"
+
+namespace dbaccess
+{
+ class OPrivateRow : public ::cppu::WeakImplHelper< css::sdbc::XRow>
+ {
+ ORowSetValueVector::Vector m_aRow;
+ sal_Int32 m_nPos;
+ public:
+ explicit OPrivateRow(ORowSetValueVector::Vector&& i_aRow) : m_aRow(std::move(i_aRow)),m_nPos(0)
+ {
+ }
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( ::sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int8 SAL_CALL getByte( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int16 SAL_CALL getShort( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int32 SAL_CALL getInt( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int64 SAL_CALL getLong( ::sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( ::sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getBytes( ::sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( ::sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( ::sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( ::sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( ::sal_Int32 columnIndex ) override;
+ };
+} // dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSet.cxx b/dbaccess/source/core/api/RowSet.cxx
new file mode 100644
index 000000000..28c392995
--- /dev/null
+++ b/dbaccess/source/core/api/RowSet.cxx
@@ -0,0 +1,2965 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <map>
+#include <utility>
+
+#include "RowSet.hxx"
+#include <stringconstants.hxx>
+#include <sdbcoretools.hxx>
+#include <SingleSelectQueryComposer.hxx>
+#include "CRowSetColumn.hxx"
+#include "CRowSetDataColumn.hxx"
+#include "RowSetCache.hxx"
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <tablecontainer.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/RowChangeAction.hpp>
+#include <com/sun/star/sdb/RowSetVetoException.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/seqstream.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/BlobHelper.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/safeint.hxx>
+#include <unotools/syslocale.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace utl;
+using namespace dbaccess;
+using namespace connectivity;
+using namespace comphelper;
+using namespace dbtools;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::util;
+using namespace ::cppu;
+using namespace ::osl;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ORowSet_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ORowSet(context));
+}
+
+namespace dbaccess
+{
+ORowSet::ORowSet( const Reference< css::uno::XComponentContext >& _rxContext )
+ :ORowSet_BASE1(m_aMutex)
+ ,ORowSetBase( _rxContext, ORowSet_BASE1::rBHelper, &m_aMutex )
+ ,m_aPrematureParamValues(new ORowSetValueVector)
+ ,m_aParameterValueForCache(new ORowSetValueVector)
+ ,m_aRowsetListeners(*m_pMutex)
+ ,m_aApproveListeners(*m_pMutex)
+ ,m_aRowsChangeListener(*m_pMutex)
+ ,m_sErrorString(ResourceManager::loadString(RID_STR_COMMAND_LEADING_TO_ERROR))
+ ,m_nFetchDirection(FetchDirection::FORWARD)
+ ,m_nFetchSize(50)
+ ,m_nMaxFieldSize(0)
+ ,m_nMaxRows(0)
+ ,m_nQueryTimeOut(0)
+ ,m_nCommandType(CommandType::COMMAND)
+ ,m_nTransactionIsolation(0)
+ ,m_nPrivileges(0)
+ ,m_nLastKnownRowCount(0)
+ ,m_nInAppend(0)
+ ,m_bInsertingRow(false)
+ ,m_bLastKnownRowCountFinal(false)
+ ,m_bUseEscapeProcessing(true)
+ ,m_bApplyFilter(false)
+ ,m_bCommandFacetsDirty( true )
+ ,m_bParametersDirty( true )
+ ,m_bModified(false)
+ ,m_bRebuildConnOnExecute(false)
+ ,m_bIsBookmarkable(true)
+ ,m_bNew(false)
+ ,m_bCanUpdateInsertedRows(true)
+ ,m_bOwnConnection(false)
+ ,m_bPropChangeNotifyEnabled(true)
+{
+ m_nResultSetType = ResultSetType::SCROLL_SENSITIVE;
+ m_nResultSetConcurrency = ResultSetConcurrency::UPDATABLE;
+ m_pMySelf = this;
+ m_aActiveConnection <<= m_xActiveConnection;
+
+ sal_Int32 const nRBT = PropertyAttribute::READONLY | PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT;
+ sal_Int32 const nRT = PropertyAttribute::READONLY | PropertyAttribute::TRANSIENT;
+ sal_Int32 const nBT = PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT;
+
+ m_aPrematureParamValues->resize( 0 );
+
+ // sdb.RowSet Properties
+ registerMayBeVoidProperty(PROPERTY_ACTIVE_CONNECTION,PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::MAYBEVOID|PropertyAttribute::TRANSIENT|PropertyAttribute::BOUND, &m_aActiveConnection, cppu::UnoType<XConnection>::get());
+ registerProperty(PROPERTY_DATASOURCENAME, PROPERTY_ID_DATASOURCENAME, PropertyAttribute::BOUND, &m_aDataSourceName, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, &m_aCommand, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_COMMAND_TYPE, PROPERTY_ID_COMMAND_TYPE, PropertyAttribute::BOUND, &m_nCommandType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_ACTIVECOMMAND, PROPERTY_ID_ACTIVECOMMAND, nRBT, &m_aActiveCommand, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_IGNORERESULT, PROPERTY_ID_IGNORERESULT, PropertyAttribute::BOUND, &m_bIgnoreResult, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND, &m_aFilter, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND, &m_aHavingClause, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND, &m_aGroupBy, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND, &m_bApplyFilter, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, &m_aOrder, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, nRT, &m_nPrivileges, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_ISMODIFIED, PROPERTY_ID_ISMODIFIED, nBT, &m_bModified, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_ISNEW, PROPERTY_ID_ISNEW, nRBT, &m_bNew, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_SINGLESELECTQUERYCOMPOSER,PROPERTY_ID_SINGLESELECTQUERYCOMPOSER, nRT, &m_xComposer, cppu::UnoType<XSingleSelectQueryComposer>::get());
+
+ // sdbcx.ResultSet Properties
+ registerProperty(PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, nRT, &m_bIsBookmarkable, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_CANUPDATEINSERTEDROWS,PROPERTY_ID_CANUPDATEINSERTEDROWS, nRT, &m_bCanUpdateInsertedRows, cppu::UnoType<bool>::get());
+ // sdbc.ResultSet Properties
+ registerProperty(PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::TRANSIENT, &m_nResultSetConcurrency,::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::TRANSIENT, &m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, PropertyAttribute::TRANSIENT, &m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, PropertyAttribute::TRANSIENT, &m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+
+ // sdbc.RowSet Properties
+ registerProperty(PROPERTY_URL, PROPERTY_ID_URL, 0, &m_aURL, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_TRANSACTIONISOLATION, PROPERTY_ID_TRANSACTIONISOLATION, PropertyAttribute::TRANSIENT, &m_nTransactionIsolation,::cppu::UnoType<sal_Int32>::get());
+ registerMayBeVoidProperty(PROPERTY_TYPEMAP, PROPERTY_ID_TYPEMAP, PropertyAttribute::MAYBEVOID|PropertyAttribute::TRANSIENT, &m_aTypeMap, cppu::UnoType<XNameAccess>::get());
+ registerProperty(PROPERTY_ESCAPE_PROCESSING,PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, &m_bUseEscapeProcessing,cppu::UnoType<bool>::get() );
+ registerProperty(PROPERTY_QUERYTIMEOUT, PROPERTY_ID_QUERYTIMEOUT, PropertyAttribute::TRANSIENT, &m_nQueryTimeOut, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_MAXFIELDSIZE, PROPERTY_ID_MAXFIELDSIZE, PropertyAttribute::TRANSIENT, &m_nMaxFieldSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_MAXROWS, PROPERTY_ID_MAXROWS, 0, &m_nMaxRows, ::cppu::UnoType<sal_Int32>::get() );
+ registerProperty(PROPERTY_USER, PROPERTY_ID_USER, PropertyAttribute::TRANSIENT, &m_aUser, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_PASSWORD, PROPERTY_ID_PASSWORD, PropertyAttribute::TRANSIENT, &m_aPassword, ::cppu::UnoType<OUString>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND, &m_aUpdateCatalogName, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND, &m_aUpdateSchemaName, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND, &m_aUpdateTableName, ::cppu::UnoType<OUString>::get());
+
+ // ???
+ registerProperty(PROPERTY_CHANGE_NOTIFICATION_ENABLED, PROPERTY_ID_PROPCHANGE_NOTIFY, PropertyAttribute::BOUND, &m_bPropChangeNotifyEnabled, cppu::UnoType<bool>::get());
+}
+
+ORowSet::~ORowSet()
+{
+ if ( !m_rBHelper.bDisposed && !m_rBHelper.bInDispose )
+ {
+ SAL_WARN("dbaccess", "Please check who doesn't dispose this component!");
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+void ORowSet::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const
+{
+ switch( _nHandle )
+ {
+ case PROPERTY_ID_COMMAND_TYPE:
+ _rDefault <<= CommandType::COMMAND;
+ break;
+ case PROPERTY_ID_IGNORERESULT:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_APPLYFILTER:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_ISMODIFIED:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ _rDefault <<= true;
+ break;
+ case PROPERTY_ID_CANUPDATEINSERTEDROWS:
+ _rDefault <<= true;
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ _rDefault <<= ResultSetType::SCROLL_INSENSITIVE;
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ _rDefault <<= ResultSetConcurrency::UPDATABLE;
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ _rDefault <<= FetchDirection::FORWARD;
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ _rDefault <<= static_cast<sal_Int32>(1);
+ break;
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ _rDefault <<= true;
+ break;
+ case PROPERTY_ID_MAXROWS:
+ _rDefault <<= sal_Int32( 0 );
+ break;
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_HAVING_CLAUSE:
+ case PROPERTY_ID_GROUP_BY:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_UPDATE_CATALOGNAME:
+ case PROPERTY_ID_UPDATE_SCHEMANAME:
+ case PROPERTY_ID_UPDATE_TABLENAME:
+ _rDefault <<= OUString();
+ break;
+ }
+}
+
+void SAL_CALL ORowSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISMODIFIED:
+ m_bModified = cppu::any2bool(rValue);
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ if( m_nResultSetType == ResultSetType::FORWARD_ONLY)
+ throw Exception("resultsettype is FORWARD_ONLY", nullptr);
+ [[fallthrough]];
+ default:
+ OPropertyStateContainer::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ }
+
+ if ( ( nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
+ || ( nHandle == PROPERTY_ID_DATASOURCENAME )
+ || ( nHandle == PROPERTY_ID_COMMAND )
+ || ( nHandle == PROPERTY_ID_COMMAND_TYPE )
+ || ( nHandle == PROPERTY_ID_IGNORERESULT )
+ || ( nHandle == PROPERTY_ID_FILTER )
+ || ( nHandle == PROPERTY_ID_HAVING_CLAUSE )
+ || ( nHandle == PROPERTY_ID_GROUP_BY )
+ || ( nHandle == PROPERTY_ID_APPLYFILTER )
+ || ( nHandle == PROPERTY_ID_ORDER )
+ || ( nHandle == PROPERTY_ID_URL )
+ || ( nHandle == PROPERTY_ID_USER )
+ )
+ {
+ m_bCommandFacetsDirty = true;
+ }
+
+
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ACTIVE_CONNECTION:
+ // the new connection
+ {
+ assert(m_aActiveConnection == rValue);
+ Reference< XConnection > xNewConnection(m_aActiveConnection,UNO_QUERY);
+ setActiveConnection(xNewConnection, false);
+ }
+
+ m_bOwnConnection = false;
+ m_bRebuildConnOnExecute = false;
+ break;
+
+ case PROPERTY_ID_DATASOURCENAME:
+ if(!m_xStatement.is())
+ {
+ Reference< XConnection > xNewConn;
+ Any aNewConn;
+ aNewConn <<= xNewConn;
+ setFastPropertyValue(PROPERTY_ID_ACTIVE_CONNECTION, aNewConn);
+ }
+ else
+ m_bRebuildConnOnExecute = true;
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ if(m_pCache)
+ {
+ m_pCache->setFetchSize(m_nFetchSize);
+ fireRowcount();
+ }
+ break;
+ case PROPERTY_ID_URL:
+ // is the connection-to-be-built determined by the url (which is the case if m_aDataSourceName is empty) ?
+ if (m_aDataSourceName.isEmpty())
+ {
+ // are we active at the moment ?
+ if (m_xStatement.is())
+ // yes -> the next execute needs to rebuild our connection because of this new property
+ m_bRebuildConnOnExecute = true;
+ else
+ { // no -> drop our active connection (if we have one) as it doesn't correspond to this new property value anymore
+ Reference< XConnection > xNewConn;
+ Any aNewConn;
+ aNewConn <<= xNewConn;
+ setFastPropertyValue(PROPERTY_ID_ACTIVE_CONNECTION, aNewConn);
+ }
+ }
+ m_bOwnConnection = true;
+ break;
+ case PROPERTY_ID_TYPEMAP:
+ m_xTypeMap.set(m_aTypeMap, css::uno::UNO_QUERY);
+ break;
+ case PROPERTY_ID_PROPCHANGE_NOTIFY:
+ m_bPropChangeNotifyEnabled = ::cppu::any2bool(rValue);
+ break;
+ default:
+ break;
+ }
+}
+
+void SAL_CALL ORowSet::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ if(m_pCache)
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISMODIFIED:
+ rValue <<= m_bModified;
+ break;
+ case PROPERTY_ID_ISNEW:
+ rValue <<= m_bNew;
+ break;
+ case PROPERTY_ID_PRIVILEGES:
+ rValue <<= m_pCache->m_nPrivileges;
+ break;
+ case PROPERTY_ID_ACTIVE_CONNECTION:
+ rValue <<= m_xActiveConnection;
+ break;
+ case PROPERTY_ID_TYPEMAP:
+ rValue <<= m_xTypeMap;
+ break;
+ default:
+ ORowSetBase::getFastPropertyValue(rValue,nHandle);
+ }
+ }
+ else
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ACTIVE_CONNECTION:
+ rValue <<= m_xActiveConnection;
+ break;
+ case PROPERTY_ID_TYPEMAP:
+ rValue <<= m_xTypeMap;
+ break;
+ case PROPERTY_ID_PROPCHANGE_NOTIFY:
+ rValue <<= m_bPropChangeNotifyEnabled;
+ break;
+ default:
+ ORowSetBase::getFastPropertyValue(rValue,nHandle);
+ }
+ }
+}
+
+// css::XTypeProvider
+Sequence< Type > SAL_CALL ORowSet::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get(),
+ ::comphelper::concatSequences(ORowSet_BASE1::getTypes(),ORowSetBase::getTypes()));
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > SAL_CALL ORowSet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::XInterface
+Any SAL_CALL ORowSet::queryInterface( const Type & rType )
+{
+ return ORowSet_BASE1::queryInterface( rType);
+}
+
+void SAL_CALL ORowSet::acquire() noexcept
+{
+ ORowSet_BASE1::acquire();
+}
+
+void SAL_CALL ORowSet::release() noexcept
+{
+ ORowSet_BASE1::release();
+}
+
+// css::XUnoTunnel
+sal_Int64 SAL_CALL ORowSet::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & ORowSet::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit s_Id;
+ return s_Id.getSeq();
+}
+
+// css::XAggregation
+Any SAL_CALL ORowSet::queryAggregation( const Type& rType )
+{
+ Any aRet(ORowSetBase::queryInterface(rType));
+ if (!aRet.hasValue())
+ aRet = ORowSet_BASE1::queryAggregation(rType);
+ return aRet;
+}
+
+// css::XServiceInfo
+OUString SAL_CALL ORowSet::getImplementationName()
+{
+ return "com.sun.star.comp.dba.ORowSet";
+}
+
+sal_Bool SAL_CALL ORowSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL ORowSet::getSupportedServiceNames()
+{
+ return { SERVICE_SDBC_RESULTSET, SERVICE_SDBC_ROWSET, SERVICE_SDBCX_RESULTSET,
+ SERVICE_SDB_RESULTSET, SERVICE_SDB_ROWSET };
+}
+
+// OComponentHelper
+void SAL_CALL ORowSet::disposing()
+{
+ OPropertyStateContainer::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+ EventObject aDisposeEvent;
+ aDisposeEvent.Source = static_cast< XComponent* >(this);
+ m_aRowsetListeners.disposeAndClear( aDisposeEvent );
+ m_aApproveListeners.disposeAndClear( aDisposeEvent );
+ m_aRowsChangeListener.disposeAndClear( aDisposeEvent );
+
+ freeResources( true );
+
+ // remove myself as dispose listener
+ Reference< XComponent > xComponent(m_xActiveConnection, UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference<XEventListener> xEvt;
+ query_aggregation(this,xEvt);
+ xComponent->removeEventListener(xEvt);
+ }
+
+ m_aActiveConnection = Any(); // the any contains a reference too
+ if(m_bOwnConnection)
+ ::comphelper::disposeComponent(m_xActiveConnection);
+ m_xActiveConnection = nullptr;
+
+
+ ORowSetBase::disposing();
+}
+
+void ORowSet::freeResources( bool _bComplete )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // free all clones
+ for (auto const& clone : m_aClones)
+ {
+ Reference< XComponent > xComp(clone.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_aClones.clear();
+
+ doCancelModification();
+
+ m_aBookmark = Any();
+ m_bBeforeFirst = true;
+ m_bAfterLast = false;
+ m_bNew = false;
+ m_bModified = false;
+ m_bIsInsertRow = false;
+ m_bLastKnownRowCountFinal = false;
+ m_nLastKnownRowCount = 0;
+
+ if ( !_bComplete )
+ return;
+
+ // the columns must be disposed before the querycomposer is disposed because
+ // their owner can be the composer
+ TDataColumns().swap(m_aDataColumns);// clear and resize capacity
+ std::vector<bool>().swap(m_aReadOnlyDataColumns);
+
+ m_xColumns = nullptr;
+ if ( m_pColumns )
+ m_pColumns->disposing();
+ // dispose the composer to avoid that everybody knows that the querycomposer is eol
+ try { ::comphelper::disposeComponent( m_xComposer ); }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ m_xComposer = nullptr;
+ }
+
+ // let our warnings container forget the reference to the (possibly disposed) old result set
+ m_aWarnings.setExternalWarnings( nullptr );
+
+ m_pCache.reset();
+
+ impl_resetTables_nothrow();
+
+ m_xStatement = nullptr;
+ m_xTypeMap = nullptr;
+
+ if ( m_aOldRow.is() )
+ m_aOldRow->clearRow();
+
+ impl_disposeParametersContainer_nothrow();
+
+ m_bCommandFacetsDirty = true;
+}
+
+void ORowSet::setActiveConnection( Reference< XConnection > const & _rxNewConn, bool _bFireEvent )
+{
+ if (_rxNewConn.get() == m_xActiveConnection.get())
+ // nothing to do
+ return;
+
+ // remove the event listener for the old connection
+ Reference< XComponent > xComponent(m_xActiveConnection, UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference<XEventListener> xListener;
+ query_aggregation(this, xListener);
+ xComponent->removeEventListener(xListener);
+ }
+
+ // if we owned the connection, remember it for later disposing
+ if(m_bOwnConnection)
+ m_xOldConnection = m_xActiveConnection;
+
+ // for firing the PropertyChangeEvent
+ sal_Int32 nHandle = PROPERTY_ID_ACTIVE_CONNECTION;
+ Any aOldConnection; aOldConnection <<= m_xActiveConnection;
+ Any aNewConnection; aNewConnection <<= _rxNewConn;
+
+ // set the new connection
+ m_xActiveConnection = _rxNewConn;
+ if (m_xActiveConnection.is())
+ m_aActiveConnection <<= m_xActiveConnection;
+ else
+ m_aActiveConnection.clear();
+
+ // fire the event
+ if (_bFireEvent)
+ fire(&nHandle, &aNewConnection, &aOldConnection, 1, false);
+
+ // register as event listener for the new connection
+ xComponent.set(m_xActiveConnection,UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference<XEventListener> xListener;
+ query_aggregation(this, xListener);
+ xComponent->addEventListener(xListener);
+ }
+}
+
+// css::XEventListener
+void SAL_CALL ORowSet::disposing( const css::lang::EventObject& Source )
+{
+ // close rowset because the connection is going to be deleted (someone told me :-)
+ Reference<XConnection> xCon(Source.Source,UNO_QUERY);
+ if(m_xActiveConnection == xCon)
+ {
+ close();
+ {
+ MutexGuard aGuard( m_aMutex );
+ Reference< XConnection > xXConnection;
+ setActiveConnection( xXConnection );
+ }
+ }
+}
+
+// XCloseable
+void SAL_CALL ORowSet::close( )
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ }
+ // additionals things to set
+ freeResources( true );
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& SAL_CALL ORowSet::getInfoHelper()
+{
+ return *::comphelper::OPropertyArrayUsageHelper<ORowSet>::getArrayHelper();
+}
+
+void ORowSet::updateValue(sal_Int32 columnIndex,const ORowSetValue& x)
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateValue(columnIndex,x,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+// XRowUpdate
+void SAL_CALL ORowSet::updateNull( sal_Int32 columnIndex )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateNull(columnIndex,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+void SAL_CALL ORowSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ updateValue(columnIndex, static_cast<bool>(x));
+}
+
+void SAL_CALL ORowSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ {
+ Sequence<sal_Int8> aSeq;
+ if(x.is())
+ x->readBytes(aSeq,length);
+ updateValue(columnIndex,aSeq);
+ }
+}
+
+void SAL_CALL ORowSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateCharacterStream(columnIndex,x,length,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+void SAL_CALL ORowSet::updateObject( sal_Int32 columnIndex, const Any& x )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ Any aNewValue = x;
+
+ if ( m_pColumns )
+ {
+ Reference<XPropertySet> xColumn(m_pColumns->getByIndex(columnIndex-1),UNO_QUERY);
+ sal_Int32 nColType = 0;
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nColType;
+ switch( nColType )
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ {
+ double nValue = 0;
+ if ( x >>= nValue )
+ {
+ if ( DataType::TIMESTAMP == nColType )
+ aNewValue <<= dbtools::DBTypeConversion::toDateTime( nValue );
+ else if ( DataType::DATE == nColType )
+ aNewValue <<= dbtools::DBTypeConversion::toDate( nValue );
+ else
+ aNewValue <<= dbtools::DBTypeConversion::toTime( nValue );
+ }
+ break;
+ }
+ }
+ }
+
+ if (!::dbtools::implUpdateObject(this, columnIndex, aNewValue))
+ { // there is no other updateXXX call which can handle the value in x
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateObject(columnIndex,aNewValue,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+ }
+}
+
+void SAL_CALL ORowSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateNumericObject(columnIndex,x,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+namespace
+{
+ class ProtectFlag
+ {
+ bool& m_rInsertingRow;
+ public:
+ explicit ProtectFlag(bool& rInsertingRow)
+ : m_rInsertingRow(rInsertingRow)
+ {
+ if (m_rInsertingRow)
+ {
+ throw std::runtime_error("recursion in insertRow");
+ }
+ m_rInsertingRow = true;
+ }
+ ~ProtectFlag()
+ {
+ m_rInsertingRow = false;
+ }
+ };
+}
+
+// XResultSetUpdate
+void SAL_CALL ORowSet::insertRow()
+{
+ ProtectFlag aFlagControl(m_bInsertingRow);
+
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ // insertRow is not allowed when
+ // standing not on the insert row nor
+ // when the row isn't modified
+ // or the concurrency is read only
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ if(!m_pCache || !m_bNew || !m_bModified || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY)
+ throwFunctionSequenceException(*this);
+
+ // remember old value for fire
+ bool bOld = m_bNew;
+
+ ORowSetRow aOldValues;
+ if ( !m_aCurrentRow.isNull() )
+ aOldValues = new ORowSetValueVector( *(*m_aCurrentRow));
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::INSERT,1,aChangedBookmarks);
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ std::vector< Any > aBookmarks;
+ bool bInserted = m_pCache->insertRow(aBookmarks);
+
+ // make sure that our row is set to the new inserted row before clearing the insert flags in the cache
+ m_pCache->resetInsertRow(bInserted);
+
+ // notification order
+ // - column values
+ setCurrentRow( false, true, aOldValues, aGuard ); // we don't move here
+
+ // read-only flag restored
+ impl_restoreDataColumnsWriteable_throw();
+
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ if ( !aBookmarks.empty() )
+ {
+ RowsChangeEvent aUpEvt(*this,RowChangeAction::UPDATE,aBookmarks.size(),comphelper::containerToSequence(aBookmarks));
+ notifyAllListenersRowChanged(aGuard,aUpEvt);
+ }
+
+ // - IsModified
+ if(!m_bModified)
+ fireProperty(PROPERTY_ID_ISMODIFIED,false,true);
+ OSL_ENSURE( !m_bModified, "ORowSet::insertRow: just updated, but _still_ modified?" );
+
+ // - IsNew
+ if(m_bNew != bOld)
+ fireProperty(PROPERTY_ID_ISNEW,m_bNew,bOld);
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+}
+
+void SAL_CALL ORowSet::updateRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ // not allowed when standing on insert row
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ if ( !m_pCache || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY || m_bNew || ((m_pCache->m_nPrivileges & Privilege::UPDATE ) != Privilege::UPDATE) )
+ throwFunctionSequenceException(*this);
+
+
+ if(!m_bModified)
+ return;
+
+ ORowSetRow aOldValues;
+ if ( !m_aCurrentRow.isNull() )
+ aOldValues = new ORowSetValueVector( *(*m_aCurrentRow) );
+
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::UPDATE,1,aChangedBookmarks);
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ std::vector< Any > aBookmarks;
+ m_pCache->updateRow(m_aCurrentRow.operator ->(),aBookmarks);
+ if ( !aBookmarks.empty() )
+ aEvt.Bookmarks = comphelper::containerToSequence(aBookmarks);
+ aEvt.Rows += aBookmarks.size();
+ m_aBookmark = m_pCache->getBookmark();
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() && (*m_pCache->m_aMatrixIter).is() )
+ {
+ if ( m_pCache->isResultSetChanged() )
+ {
+ impl_rebuild_throw(aGuard);
+ }
+ else
+ {
+ m_aOldRow->setRow(new ORowSetValueVector(*(*m_aCurrentRow)));
+
+ // notification order
+ // - column values
+ ORowSetBase::firePropertyChange(aOldValues);
+ }
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ // - IsModified
+ if(!m_bModified)
+ fireProperty(PROPERTY_ID_ISMODIFIED,false,true);
+ OSL_ENSURE( !m_bModified, "ORowSet::updateRow: just updated, but _still_ modified?" );
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ else if ( !m_bAfterLast ) // the update went wrong
+ {
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_UPDATE_FAILED ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+ }
+}
+
+void SAL_CALL ORowSet::deleteRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_DELETE_BEFORE_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+ if ( m_bNew )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_DELETE_INSERT_ROW ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+ if ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_RESULT_IS_READONLY ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+ if ( ( m_pCache->m_nPrivileges & Privilege::DELETE ) != Privilege::DELETE )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_DELETE_PRIVILEGE ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+ if ( rowDeleted() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_ROW_ALREADY_DELETED ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+
+ // this call position the cache indirect
+ Any aBookmarkToDelete( m_aBookmark );
+ positionCache( MOVE_NONE );
+ sal_Int32 nDeletePosition = m_pCache->getRow();
+
+ notifyRowSetAndClonesRowDelete( aBookmarkToDelete );
+
+ ORowSetRow aOldValues;
+ if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() && m_pCache->m_aMatrixIter->is() )
+ aOldValues = new ORowSetValueVector( *(*(m_pCache->m_aMatrixIter)) );
+
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::DELETE,1,aChangedBookmarks);
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ m_pCache->deleteRow();
+ notifyRowSetAndClonesRowDeleted( aBookmarkToDelete, nDeletePosition );
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ // notification order
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+}
+
+void ORowSet::implCancelRowUpdates( bool _bNotifyModified )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if ( m_bBeforeFirst || m_bAfterLast || rowDeleted() )
+ return; // nothing to do so return
+
+ checkCache();
+ // cancelRowUpdates is not allowed when:
+ // - standing on the insert row
+ // - the concurrency is read only
+ // - the current row is deleted
+ if ( m_bNew || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ throwFunctionSequenceException(*this);
+
+ positionCache( MOVE_NONE );
+
+ ORowSetRow aOldValues;
+ if ( !m_bModified && _bNotifyModified && !m_aCurrentRow.isNull() )
+ aOldValues = new ORowSetValueVector( *(*m_aCurrentRow) );
+
+ m_pCache->cancelRowUpdates();
+
+ m_aBookmark = m_pCache->getBookmark();
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+
+ // notification order
+ // IsModified
+ if( !m_bModified && _bNotifyModified )
+ {
+ // - column values
+ ORowSetBase::firePropertyChange(aOldValues);
+ fireProperty(PROPERTY_ID_ISMODIFIED,false,true);
+ }
+}
+
+void SAL_CALL ORowSet::cancelRowUpdates( )
+{
+ implCancelRowUpdates( true );
+}
+
+void SAL_CALL ORowSet::addRowSetListener( const Reference< XRowSetListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ if(listener.is())
+ m_aRowsetListeners.addInterface(listener);
+}
+
+void SAL_CALL ORowSet::removeRowSetListener( const Reference< XRowSetListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ if(listener.is())
+ m_aRowsetListeners.removeInterface(listener);
+}
+
+void ORowSet::notifyAllListeners(::osl::ResettableMutexGuard& _rGuard)
+{
+ EventObject aEvt(*m_pMySelf);
+ _rGuard.clear();
+ m_aRowsetListeners.notifyEach( &XRowSetListener::rowSetChanged, aEvt );
+ _rGuard.reset();
+}
+
+void ORowSet::notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard)
+{
+ EventObject aEvt(*m_pMySelf);
+ _rGuard.clear();
+ m_aRowsetListeners.notifyEach( &XRowSetListener::cursorMoved, aEvt );
+ _rGuard.reset();
+}
+
+void ORowSet::notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard, const RowsChangeEvent& aEvt)
+{
+ _rGuard.clear();
+ m_aRowsetListeners.notifyEach( &XRowSetListener::rowChanged, static_cast<EventObject>(aEvt) );
+ m_aRowsChangeListener.notifyEach( &XRowsChangeListener::rowsChanged, aEvt );
+ _rGuard.reset();
+}
+
+bool ORowSet::notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard)
+{
+ EventObject aEvt(*m_pMySelf);
+ std::vector< Reference< css::sdb::XRowSetApproveListener > > aListenerSeq = m_aApproveListeners.getElements();
+ _rGuard.clear();
+ bool bCheck = std::all_of(aListenerSeq.rbegin(), aListenerSeq.rend(),
+ [&aEvt](Reference<css::sdb::XRowSetApproveListener>& rxItem) {
+ try
+ {
+ return static_cast<bool>(rxItem->approveCursorMove(aEvt));
+ }
+ catch( RuntimeException& )
+ {
+ return true;
+ }
+ });
+ _rGuard.reset();
+ return bCheck;
+}
+
+void ORowSet::notifyAllListenersRowBeforeChange(::osl::ResettableMutexGuard& _rGuard,const RowChangeEvent &aEvt)
+{
+ std::vector< Reference< css::sdb::XRowSetApproveListener > > aListenerSeq = m_aApproveListeners.getElements();
+ _rGuard.clear();
+ bool bCheck = std::all_of(aListenerSeq.rbegin(), aListenerSeq.rend(),
+ [&aEvt](Reference<css::sdb::XRowSetApproveListener>& rxItem) {
+ try
+ {
+ return static_cast<bool>(rxItem->approveRowChange(aEvt));
+ }
+ catch( RuntimeException& )
+ {
+ return true;
+ }
+ });
+ _rGuard.reset();
+
+ if ( !bCheck )
+ m_aErrors.raiseTypedException( sdb::ErrorCondition::ROW_SET_OPERATION_VETOED, *this, ::cppu::UnoType< RowSetVetoException >::get() );
+}
+
+void ORowSet::fireRowcount()
+{
+ sal_Int32 nCurrentRowCount( impl_getRowCount() );
+ bool bCurrentRowCountFinal( m_pCache->m_bRowCountFinal );
+
+ if ( m_nLastKnownRowCount != nCurrentRowCount )
+ {
+ sal_Int32 nHandle = PROPERTY_ID_ROWCOUNT;
+ Any aNew,aOld;
+ aNew <<= nCurrentRowCount; aOld <<= m_nLastKnownRowCount;
+ fire(&nHandle,&aNew,&aOld,1,false);
+ m_nLastKnownRowCount = nCurrentRowCount;
+ }
+ if ( !m_bLastKnownRowCountFinal && ( m_bLastKnownRowCountFinal != bCurrentRowCountFinal ) )
+ {
+ sal_Int32 nHandle = PROPERTY_ID_ISROWCOUNTFINAL;
+ Any aNew,aOld;
+ aNew <<= bCurrentRowCountFinal;
+ aOld <<= m_bLastKnownRowCountFinal;
+ fire(&nHandle,&aNew,&aOld,1,false);
+ m_bLastKnownRowCountFinal = bCurrentRowCountFinal;
+ }
+}
+
+void SAL_CALL ORowSet::moveToInsertRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+ if ( ( m_pCache->m_nPrivileges & Privilege::INSERT ) != Privilege::INSERT )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_INSERT_PRIVILEGE ), StandardSQLState::GENERAL_ERROR, *this );
+
+ if ( !notifyAllListenersCursorBeforeMove( aGuard ) )
+ return;
+
+ // remember old value for fire
+ ORowSetRow aOldValues;
+ if ( rowDeleted() )
+ {
+ positionCache( MOVE_FORWARD );
+ m_pCache->next();
+ setCurrentRow( true, false, aOldValues, aGuard);
+ }
+ else
+ positionCache( MOVE_NONE );
+
+ // check before because the resultset could be empty
+ if ( !m_bBeforeFirst
+ && !m_bAfterLast
+ && m_pCache->m_aMatrixIter != m_pCache->getEnd()
+ && m_pCache->m_aMatrixIter->is()
+ )
+ aOldValues = new ORowSetValueVector( *(*(m_pCache->m_aMatrixIter)) );
+
+ const bool bNewState = m_bNew;
+ const bool bModState = m_bModified;
+
+ m_pCache->moveToInsertRow();
+ m_aCurrentRow = m_pCache->m_aInsertRow;
+ m_bIsInsertRow = true;
+
+ // set read-only flag to false
+ impl_setDataColumnsWriteable_throw();
+
+ // notification order
+ // - column values
+ ORowSetBase::firePropertyChange(aOldValues);
+
+ // - cursorMoved
+ notifyAllListenersCursorMoved(aGuard);
+
+ // - IsModified
+ if ( bModState != m_bModified )
+ fireProperty( PROPERTY_ID_ISMODIFIED, m_bModified, bModState );
+
+ // - IsNew
+ if ( bNewState != m_bNew )
+ fireProperty( PROPERTY_ID_ISNEW, m_bNew, bNewState );
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+}
+
+void ORowSet::impl_setDataColumnsWriteable_throw()
+{
+ impl_restoreDataColumnsWriteable_throw();
+ m_aReadOnlyDataColumns.resize(m_aDataColumns.size(),false);
+ std::vector<bool, std::allocator<bool> >::iterator aReadIter = m_aReadOnlyDataColumns.begin();
+ for (auto const& dataColumn : m_aDataColumns)
+ {
+ bool bReadOnly = false;
+ dataColumn->getPropertyValue(PROPERTY_ISREADONLY) >>= bReadOnly;
+ *aReadIter = bReadOnly;
+
+ dataColumn->setPropertyValue(PROPERTY_ISREADONLY,Any(false));
+ ++aReadIter;
+ }
+}
+
+void ORowSet::impl_restoreDataColumnsWriteable_throw()
+{
+ assert(m_aDataColumns.size() == m_aReadOnlyDataColumns.size() || m_aReadOnlyDataColumns.size() == 0 );
+ TDataColumns::const_iterator aIter = m_aDataColumns.begin();
+ for (bool readOnlyDataColumn : m_aReadOnlyDataColumns)
+ {
+ (*aIter)->setPropertyValue(PROPERTY_ISREADONLY, Any(readOnlyDataColumn) );
+ ++aIter;
+ }
+ m_aReadOnlyDataColumns.clear();
+}
+
+void SAL_CALL ORowSet::moveToCurrentRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ if ( !m_pCache->m_bNew && !m_bModified )
+ // nothing to do if we're not on the insertion row, and not modified otherwise
+ return;
+
+ if ( rowDeleted() )
+ // this would perhaps even justify a RuntimeException...
+ // if the current row is deleted, then no write access to this row should be possible. So,
+ // m_bModified should be true. Also, as soon as somebody calls moveToInsertRow,
+ // our current row should not be deleted anymore. So, we should not have survived the above
+ // check "if ( !m_pCache->m_bNew && !m_bModified )"
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_ROW_ALREADY_DELETED ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+
+ if ( !notifyAllListenersCursorBeforeMove( aGuard ) )
+ return;
+
+ positionCache( MOVE_NONE_REFRESH );
+
+ ORowSetNotifier aNotifier( this );
+
+ // notification order
+ // - cursorMoved
+ notifyAllListenersCursorMoved(aGuard);
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+}
+
+// XRow
+sal_Bool SAL_CALL ORowSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ return ( m_pCache && isInsertRow() ) ? (**m_pCache->m_aInsertRow)[m_nLastColumnIndex].isNull() : ORowSetBase::wasNull();
+}
+
+const ORowSetValue& ORowSet::getInsertValue(sal_Int32 columnIndex)
+{
+ checkCache();
+
+ if ( m_pCache && isInsertRow() )
+ {
+ m_nLastColumnIndex = columnIndex;
+ return (**m_pCache->m_aInsertRow)[m_nLastColumnIndex];
+ }
+ return getValue(columnIndex);
+}
+
+OUString SAL_CALL ORowSet::getString( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getString();
+}
+
+sal_Bool SAL_CALL ORowSet::getBoolean( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getBool();
+}
+
+sal_Int8 SAL_CALL ORowSet::getByte( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getInt8();
+}
+
+sal_Int16 SAL_CALL ORowSet::getShort( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getInt16();
+}
+
+sal_Int32 SAL_CALL ORowSet::getInt( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getInt32();
+}
+
+sal_Int64 SAL_CALL ORowSet::getLong( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getLong();
+}
+
+float SAL_CALL ORowSet::getFloat( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getFloat();
+}
+
+double SAL_CALL ORowSet::getDouble( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getDouble();
+}
+
+Sequence< sal_Int8 > SAL_CALL ORowSet::getBytes( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getSequence();
+}
+
+css::util::Date SAL_CALL ORowSet::getDate( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getDate();
+}
+
+css::util::Time SAL_CALL ORowSet::getTime( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getTime();
+}
+
+css::util::DateTime SAL_CALL ORowSet::getTimestamp( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getDateTime();
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if ( m_pCache && isInsertRow() )
+ {
+ checkCache();
+ m_nLastColumnIndex = columnIndex;
+ return new ::comphelper::SequenceInputStream((**m_pCache->m_aInsertRow)[m_nLastColumnIndex].getSequence());
+ }
+
+ return ORowSetBase::getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSet::getCharacterStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if(m_pCache && isInsertRow() )
+ {
+ checkCache();
+ m_nLastColumnIndex = columnIndex;
+ return new ::comphelper::SequenceInputStream((**m_pCache->m_aInsertRow)[m_nLastColumnIndex].getSequence());
+ }
+
+ return ORowSetBase::getCharacterStream(columnIndex);
+}
+
+Any SAL_CALL ORowSet::getObject( sal_Int32 columnIndex, const Reference< XNameAccess >& /*typeMap*/ )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).makeAny();
+}
+
+Reference< XRef > SAL_CALL ORowSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ return Reference< XRef >();
+}
+
+Reference< XBlob > SAL_CALL ORowSet::getBlob( sal_Int32 columnIndex )
+{
+ if ( m_pCache && isInsertRow() )
+ {
+ checkCache();
+ m_nLastColumnIndex = columnIndex;
+ return new ::connectivity::BlobHelper((**m_pCache->m_aInsertRow)[m_nLastColumnIndex].getSequence());
+ }
+ return ORowSetBase::getBlob(columnIndex);
+}
+
+Reference< XClob > SAL_CALL ORowSet::getClob( sal_Int32 columnIndex )
+{
+ return Reference< XClob >(getInsertValue(columnIndex).makeAny(),UNO_QUERY);
+}
+
+Reference< XArray > SAL_CALL ORowSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ return Reference< XArray >();
+}
+
+void SAL_CALL ORowSet::executeWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
+{
+ if (!_rxHandler.is())
+ execute();
+
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ // tell everybody that we will change the result set
+ approveExecution();
+
+ ResettableMutexGuard aGuard( m_aMutex );
+
+ try
+ {
+ freeResources( m_bCommandFacetsDirty );
+
+ // calc the connection to be used
+ if (m_xActiveConnection.is() && m_bRebuildConnOnExecute)
+ {
+ // there was a setProperty(ActiveConnection), but a setProperty(DataSource) _after_ that, too
+ Reference< XConnection > xXConnection;
+ setActiveConnection( xXConnection );
+ }
+ calcConnection( _rxHandler );
+ m_bRebuildConnOnExecute = false;
+
+ Reference< XSingleSelectQueryComposer > xComposer = getCurrentSettingsComposer( this, m_aContext, nullptr );
+ Reference<XParametersSupplier> xParameters(xComposer, UNO_QUERY);
+
+ Reference<XIndexAccess> xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference<XIndexAccess>();
+ const sal_Int32 nParamCount = xParamsAsIndicies.is() ? xParamsAsIndicies->getCount() : 0;
+ if ( m_aParametersSet.size() < o3tl::make_unsigned(nParamCount) )
+ m_aParametersSet.resize( nParamCount ,false);
+
+ ::dbtools::askForParameters( xComposer, this, m_xActiveConnection, _rxHandler,m_aParametersSet );
+ }
+ // ensure that only the allowed exceptions leave this block
+ catch(SQLException&)
+ {
+ throw;
+ }
+ catch(RuntimeException&)
+ {
+ throw;
+ }
+ catch(Exception const &)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "ORowSet::executeWithCompletion: caught an unexpected exception type while filling in the parameters");
+ }
+
+ // we're done with the parameters, now for the real execution
+
+ // do the real execute
+ execute_NoApprove_NoNewConn(aGuard);
+}
+
+Reference< XIndexAccess > SAL_CALL ORowSet::getParameters( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ if ( m_bCommandFacetsDirty )
+ // need to rebuild the parameters, since some property which contributes to the
+ // complete command, and thus the parameters, changed
+ impl_disposeParametersContainer_nothrow();
+
+ if ( !m_pParameters && !m_aCommand.isEmpty() )
+ {
+ try
+ {
+ OUString sNotInterestedIn;
+ impl_initComposer_throw( sNotInterestedIn );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ // our caller could change our parameters at any time
+ m_bParametersDirty = true;
+
+ return m_pParameters;
+}
+
+void ORowSet::approveExecution()
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ EventObject aEvt(*this);
+
+ OInterfaceIteratorHelper3 aApproveIter( m_aApproveListeners );
+ while ( aApproveIter.hasMoreElements() )
+ {
+ Reference< XRowSetApproveListener > xListener( aApproveIter.next() );
+ try
+ {
+ if ( !xListener->approveRowSetChange( aEvt ) )
+ throw RowSetVetoException();
+ }
+ catch ( const DisposedException& e )
+ {
+ if ( e.Context == xListener )
+ aApproveIter.remove();
+ }
+ catch ( const RuntimeException& ) { throw; }
+ catch ( const RowSetVetoException& ) { throw; }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+// XRowSet
+void SAL_CALL ORowSet::execute( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ // tell everybody that we will change the result set
+ approveExecution();
+
+ ResettableMutexGuard aGuard( m_aMutex );
+ freeResources( m_bCommandFacetsDirty );
+
+ // calc the connection to be used
+ if (m_xActiveConnection.is() && m_bRebuildConnOnExecute) {
+ // there was a setProperty(ActiveConnection), but a setProperty(DataSource) _after_ that, too
+ Reference< XConnection> xXConnection;
+ setActiveConnection( xXConnection );
+ }
+
+ calcConnection(nullptr);
+ m_bRebuildConnOnExecute = false;
+
+ // do the real execute
+ execute_NoApprove_NoNewConn(aGuard);
+}
+
+void ORowSet::setStatementResultSetType( const Reference< XPropertySet >& _rxStatement, sal_Int32 _nDesiredResultSetType, sal_Int32 _nDesiredResultSetConcurrency )
+{
+ OSL_ENSURE( _rxStatement.is(), "ORowSet::setStatementResultSetType: invalid statement - this will crash!" );
+
+ sal_Int32 nResultSetType( _nDesiredResultSetType );
+ sal_Int32 nResultSetConcurrency( _nDesiredResultSetConcurrency );
+
+ // there *might* be a data source setting which tells use to be more defensive with those settings
+ // #i15113#
+ bool bRespectDriverRST = false;
+ Any aSetting;
+ if ( getDataSourceSetting( ::dbaccess::getDataSource( m_xActiveConnection ), "RespectDriverResultSetType", aSetting ) )
+ {
+ OSL_VERIFY( aSetting >>= bRespectDriverRST );
+ }
+
+ if ( bRespectDriverRST )
+ {
+ // try type/concurrency settings with decreasing usefulness, and rely on what the connection claims
+ // to support
+ Reference< XDatabaseMetaData > xMeta( m_xActiveConnection->getMetaData() );
+
+ sal_Int32 nCharacteristics[5][2] =
+ { { ResultSetType::SCROLL_SENSITIVE, ResultSetConcurrency::UPDATABLE },
+ { ResultSetType::SCROLL_INSENSITIVE, ResultSetConcurrency::UPDATABLE },
+ { ResultSetType::SCROLL_SENSITIVE, ResultSetConcurrency::READ_ONLY },
+ { ResultSetType::SCROLL_INSENSITIVE, ResultSetConcurrency::READ_ONLY },
+ { ResultSetType::FORWARD_ONLY, ResultSetConcurrency::READ_ONLY }
+ };
+ sal_Int32 i=0;
+ if ( m_xActiveConnection->getMetaData()->isReadOnly() )
+ i = 2; // if the database is read-only we only should use read-only concurrency
+
+ for ( ; i<5; ++i )
+ {
+ nResultSetType = nCharacteristics[i][0];
+ nResultSetConcurrency = nCharacteristics[i][1];
+
+ // don't try type/concurrency pairs which are more featured than what our caller requested
+ if ( nResultSetType > _nDesiredResultSetType )
+ continue;
+ if ( nResultSetConcurrency > _nDesiredResultSetConcurrency )
+ continue;
+
+ if ( xMeta.is() && xMeta->supportsResultSetConcurrency( nResultSetType, nResultSetConcurrency ) )
+ break;
+ }
+ }
+
+ _rxStatement->setPropertyValue( PROPERTY_RESULTSETTYPE, Any( nResultSetType ) );
+ _rxStatement->setPropertyValue( PROPERTY_RESULTSETCONCURRENCY, Any( nResultSetConcurrency ) );
+}
+
+void ORowSet::impl_ensureStatement_throw()
+{
+ OUString sCommandToExecute;
+ if(m_bCommandFacetsDirty)
+ {
+ impl_initComposer_throw( sCommandToExecute );
+ }
+ else
+ {
+ sCommandToExecute = m_bUseEscapeProcessing ? m_xComposer->getQueryWithSubstitution() : m_aActiveCommand;
+ }
+
+ try
+ {
+ m_xStatement = m_xActiveConnection->prepareStatement( sCommandToExecute );
+ if ( !m_xStatement.is() )
+ {
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_INTERNAL_ERROR ), StandardSQLState::GENERAL_ERROR, *this );
+ }
+
+ Reference< XPropertySet > xStatementProps( m_xStatement, UNO_QUERY_THROW );
+ // set the result set type and concurrency
+ try
+ {
+ xStatementProps->setPropertyValue( PROPERTY_USEBOOKMARKS, Any( true ) );
+ xStatementProps->setPropertyValue( PROPERTY_MAXROWS, Any( m_nMaxRows ) );
+
+ setStatementResultSetType( xStatementProps, m_nResultSetType, m_nResultSetConcurrency );
+ }
+ catch ( const Exception& )
+ {
+ // this exception doesn't matter here because when we catch an exception
+ // then the driver doesn't support this feature
+ }
+ }
+ catch (SQLException& rException)
+ {
+ css::sdbc::SQLException* pLastExceptionInChain = SQLExceptionInfo::getLastException(&rException);
+ assert(pLastExceptionInChain && "will at least be &rException");
+
+ // append information about what we were actually going to execute
+ OUString sInfo(m_sErrorString.replaceFirst("$command$", sCommandToExecute));
+ css::uno::Any aAppend = SQLExceptionInfo::createException(SQLExceptionInfo::TYPE::SQLContext, sInfo, OUString(), 0);
+ pLastExceptionInChain->NextException = aAppend;
+
+ // propagate
+ throw;
+ }
+}
+
+Reference< XResultSet > ORowSet::impl_prepareAndExecute_throw()
+{
+ impl_ensureStatement_throw();
+
+ m_aParameterValueForCache->resize(1);
+ Reference< XParameters > xParam( m_xStatement, UNO_QUERY_THROW );
+ size_t nParamCount( m_pParameters.is() ? m_pParameters->size() : m_aPrematureParamValues->size() );
+ for ( size_t i=1; i<=nParamCount; ++i )
+ {
+ ORowSetValue& rParamValue( getParameterStorage( static_cast<sal_Int32>(i) ) );
+ ::dbtools::setObjectWithInfo( xParam, i, rParamValue.makeAny(), rParamValue.getTypeKind() );
+ m_aParameterValueForCache->push_back(rParamValue);
+ }
+ m_bParametersDirty = false;
+
+ Reference< XResultSet > xResultSet(m_xStatement->executeQuery());
+
+ OUString aComposedUpdateTableName;
+ if ( !m_aUpdateTableName.isEmpty() )
+ aComposedUpdateTableName = composeTableName( m_xActiveConnection->getMetaData(), m_aUpdateCatalogName, m_aUpdateSchemaName, m_aUpdateTableName, false, ::dbtools::EComposeRule::InDataManipulation );
+
+ SAL_INFO("dbaccess", "ORowSet::impl_prepareAndExecute_throw: creating cache" );
+ m_pCache =
+ std::make_shared<ORowSetCache>(xResultSet, m_xComposer.get(), m_aContext, aComposedUpdateTableName,
+ m_bModified, m_bNew, *m_aParameterValueForCache, m_aFilter, m_nMaxRows);
+ if ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ {
+ m_nPrivileges = Privilege::SELECT;
+ m_pCache->m_nPrivileges = Privilege::SELECT;
+ }
+ m_pCache->setFetchSize(m_nFetchSize);
+ m_aCurrentRow = m_pCache->createIterator(this);
+ m_bIsInsertRow = false;
+ m_aOldRow = m_pCache->registerOldRow();
+
+ return xResultSet;
+}
+
+void ORowSet::impl_initializeColumnSettings_nothrow( const Reference< XPropertySet >& _rxTemplateColumn, const Reference< XPropertySet >& _rxRowSetColumn )
+{
+ OSL_ENSURE( _rxTemplateColumn.is() && _rxRowSetColumn.is(),
+ "ORowSet::impl_initializeColumnSettings_nothrow: this will crash!" );
+
+ bool bHaveAnyColumnSetting = false;
+ try
+ {
+ Reference< XPropertySetInfo > xInfo( _rxTemplateColumn->getPropertySetInfo(), UNO_SET_THROW );
+
+ // a number of properties is plain copied
+ const OUString aPropertyNames[] = {
+ OUString(PROPERTY_ALIGN), OUString(PROPERTY_RELATIVEPOSITION), OUString(PROPERTY_WIDTH), OUString(PROPERTY_HIDDEN), OUString(PROPERTY_CONTROLMODEL),
+ OUString(PROPERTY_HELPTEXT), OUString(PROPERTY_CONTROLDEFAULT)
+ };
+ for (const auto & aPropertyName : aPropertyNames)
+ {
+ if ( xInfo->hasPropertyByName( aPropertyName ) )
+ {
+ _rxRowSetColumn->setPropertyValue( aPropertyName, _rxTemplateColumn->getPropertyValue( aPropertyName ) );
+ bHaveAnyColumnSetting = true;
+ }
+ }
+
+ // the format key is slightly more complex
+ sal_Int32 nFormatKey = 0;
+ if( xInfo->hasPropertyByName( PROPERTY_NUMBERFORMAT ) )
+ {
+ _rxTemplateColumn->getPropertyValue( PROPERTY_NUMBERFORMAT ) >>= nFormatKey;
+ bHaveAnyColumnSetting = true;
+ }
+ if ( !nFormatKey && m_xNumberFormatTypes.is() )
+ nFormatKey = ::dbtools::getDefaultNumberFormat( _rxTemplateColumn, m_xNumberFormatTypes, SvtSysLocale().GetLanguageTag().getLocale() );
+ _rxRowSetColumn->setPropertyValue( PROPERTY_NUMBERFORMAT, Any( nFormatKey ) );
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ return;
+ }
+
+ if ( bHaveAnyColumnSetting )
+ return;
+
+ // the template column could not provide *any* setting. Okay, probably it's a parser column, which
+ // does not offer those. However, perhaps the template column refers to a table column, which we
+ // can use as new template column
+ try
+ {
+ Reference< XPropertySetInfo > xInfo( _rxTemplateColumn->getPropertySetInfo(), UNO_SET_THROW );
+ if ( !xInfo->hasPropertyByName( PROPERTY_TABLENAME ) )
+ // no chance
+ return;
+
+ OUString sTableName;
+ OSL_VERIFY( _rxTemplateColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName );
+
+ Reference< XNameAccess > xTables( impl_getTables_throw(), UNO_SET_THROW );
+ if ( !xTables->hasByName( sTableName ) )
+ // no chance
+ return;
+
+ Reference< XColumnsSupplier > xTableColSup( xTables->getByName( sTableName ), UNO_QUERY_THROW );
+ Reference< XNameAccess > xTableCols( xTableColSup->getColumns(), UNO_SET_THROW );
+
+ OUString sTableColumnName;
+
+ // get the "Name" or (preferred) "RealName" property of the column
+ OUString sNamePropertyName( PROPERTY_NAME );
+ if ( xInfo->hasPropertyByName( PROPERTY_REALNAME ) )
+ sNamePropertyName = PROPERTY_REALNAME;
+ OSL_VERIFY( _rxTemplateColumn->getPropertyValue( sNamePropertyName ) >>= sTableColumnName );
+
+ if ( !xTableCols->hasByName( sTableColumnName ) )
+ return;
+
+ Reference< XPropertySet > xTableColumn( xTableCols->getByName( sTableColumnName ), UNO_QUERY_THROW );
+ impl_initializeColumnSettings_nothrow( xTableColumn, _rxRowSetColumn );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ORowSet::execute_NoApprove_NoNewConn(ResettableMutexGuard& _rClearForNotification)
+{
+ // now we can dispose our old connection
+ ::comphelper::disposeComponent(m_xOldConnection);
+ m_xOldConnection = nullptr;
+
+ // do we need a new statement
+ if ( m_bCommandFacetsDirty )
+ {
+ m_xStatement = nullptr;
+ m_xComposer = nullptr;
+
+ Reference< XResultSet > xResultSet( impl_prepareAndExecute_throw() );
+
+ // let our warnings container forget the reference to the (possibly disposed) old result set
+ m_aWarnings.setExternalWarnings( nullptr );
+ // clear all current warnings
+ m_aWarnings.clearWarnings();
+ // let the warnings container know about the new "external warnings"
+ m_aWarnings.setExternalWarnings( Reference< XWarningsSupplier >( xResultSet, UNO_QUERY ) );
+
+ // get the locale
+ Locale aLocale = SvtSysLocale().GetLanguageTag().getLocale();
+
+ // get the numberformatTypes
+ OSL_ENSURE(m_xActiveConnection.is(),"No ActiveConnection");
+ Reference< XNumberFormatsSupplier> xNumberFormat = ::dbtools::getNumberFormats(m_xActiveConnection);
+ if ( xNumberFormat.is() )
+ m_xNumberFormatTypes.set(xNumberFormat->getNumberFormats(),UNO_QUERY);
+
+ ::rtl::Reference< ::connectivity::OSQLColumns> aColumns = new ::connectivity::OSQLColumns();
+ std::vector< OUString> aNames;
+ OUString aDescription;
+
+ const std::map<sal_Int32,sal_Int32>& rKeyColumns = m_pCache->getKeyColumns();
+ if(!m_xColumns.is())
+ {
+ SAL_INFO("dbaccess", "ORowSet::execute_NoApprove_NoNewConn::creating columns" );
+ // use the meta data
+ Reference<XResultSetMetaDataSupplier> xMetaSup(m_xStatement,UNO_QUERY);
+ try
+ {
+ Reference<XResultSetMetaData> xMetaData = xMetaSup->getMetaData();
+ if ( xMetaData.is() )
+ {
+ sal_Int32 nCount = xMetaData->getColumnCount();
+ m_aDataColumns.reserve(nCount+1);
+ aColumns->reserve(nCount+1);
+ std::map< OUString, int > aColumnMap;
+ for (sal_Int32 i = 0 ; i < nCount; ++i)
+ {
+ // retrieve the name of the column
+ OUString sName = xMetaData->getColumnName(i + 1);
+ // check for duplicate entries
+ if(aColumnMap.find(sName) != aColumnMap.end())
+ {
+ OUString sAlias(sName);
+ sal_Int32 searchIndex=1;
+ while(aColumnMap.find(sAlias) != aColumnMap.end())
+ {
+ sAlias = sName + OUString::number(searchIndex++);
+ }
+ sName = sAlias;
+ }
+ rtl::Reference<ORowSetDataColumn> pColumn = new ORowSetDataColumn( getMetaData(),
+ this,
+ this,
+ i+1,
+ m_xActiveConnection->getMetaData(),
+ aDescription,
+ OUString(),
+ [this] (sal_Int32 const column) -> ORowSetValue const& {
+ return this->getInsertValue(column);
+ });
+ aColumnMap.insert(std::make_pair(sName,0));
+ aColumns->emplace_back(pColumn);
+ pColumn->setName(sName);
+ aNames.push_back(sName);
+ m_aDataColumns.push_back(pColumn.get());
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,Any(rKeyColumns.find(i+1) != rKeyColumns.end()));
+
+ try
+ {
+ sal_Int32 nFormatKey = 0;
+ if(m_xNumberFormatTypes.is())
+ nFormatKey = ::dbtools::getDefaultNumberFormat(pColumn,m_xNumberFormatTypes,aLocale);
+
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_NUMBERFORMAT,Any(nFormatKey));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_RELATIVEPOSITION,Any(sal_Int32(i+1)));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_WIDTH,Any(sal_Int32(227)));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ALIGN,Any(sal_Int32(0)));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_HIDDEN, css::uno::Any(false));
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ }
+ }
+ catch (SQLException&)
+ {
+ }
+ }
+ else
+ {
+ // create the rowset columns
+ Reference< XResultSetMetaData > xMeta( getMetaData(), UNO_SET_THROW );
+ sal_Int32 nCount = xMeta->getColumnCount();
+ m_aDataColumns.reserve(nCount+1);
+ aColumns->reserve(nCount+1);
+ std::set< Reference< XPropertySet > > aAllColumns;
+
+ for(sal_Int32 i=1; i <= nCount ;++i)
+ {
+ OUString sName = xMeta->getColumnName(i);
+ OUString sColumnLabel = xMeta->getColumnLabel(i);
+
+ // retrieve the column number |i|
+ Reference<XPropertySet> xColumn;
+ {
+ bool bReFetchName = false;
+ if (m_xColumns->hasByName(sColumnLabel))
+ m_xColumns->getByName(sColumnLabel) >>= xColumn;
+ if (!xColumn.is() && m_xColumns->hasByName(sName))
+ m_xColumns->getByName(sName) >>= xColumn;
+
+ // check if column already in the list we need another
+ if ( aAllColumns.find( xColumn ) != aAllColumns.end() )
+ {
+ xColumn = nullptr;
+ bReFetchName = true;
+ sColumnLabel.clear();
+ }
+ if(!xColumn.is())
+ {
+ // no column found so we could look at the position i
+ Reference<XIndexAccess> xIndexAccess(m_xColumns,UNO_QUERY);
+ if(xIndexAccess.is() && i <= xIndexAccess->getCount())
+ {
+ xIndexAccess->getByIndex(i-1) >>= xColumn;
+ }
+ else
+ {
+ Sequence< OUString> aSeq = m_xColumns->getElementNames();
+ if( i <= aSeq.getLength())
+ {
+ m_xColumns->getByName(aSeq.getConstArray()[i-1]) >>= xColumn;
+ }
+ }
+ }
+ if(bReFetchName && xColumn.is())
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ aAllColumns.insert( xColumn );
+ }
+
+ // create a RowSetDataColumn
+ {
+ Reference<XPropertySetInfo> xInfo = xColumn.is() ? xColumn->getPropertySetInfo() : Reference<XPropertySetInfo>();
+ if(xInfo.is() && xInfo->hasPropertyByName(PROPERTY_DESCRIPTION))
+ aDescription = comphelper::getString(xColumn->getPropertyValue(PROPERTY_DESCRIPTION));
+
+ OUString sParseLabel;
+ if ( xColumn.is() )
+ {
+ xColumn->getPropertyValue(PROPERTY_LABEL) >>= sParseLabel;
+ }
+ rtl::Reference<ORowSetDataColumn> pColumn = new ORowSetDataColumn( getMetaData(),
+ this,
+ this,
+ i,
+ m_xActiveConnection->getMetaData(),
+ aDescription,
+ sParseLabel,
+ [this] (sal_Int32 const column) -> ORowSetValue const& {
+ return this->getInsertValue(column);
+ });
+ aColumns->emplace_back(pColumn);
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,Any(rKeyColumns.find(i) != rKeyColumns.end()));
+
+ if(sColumnLabel.isEmpty())
+ {
+ if(xColumn.is())
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sColumnLabel;
+ else
+ sColumnLabel = DBA_RES( RID_STR_EXPRESSION1 );
+ }
+ pColumn->setName(sColumnLabel);
+ aNames.push_back(sColumnLabel);
+ m_aDataColumns.push_back(pColumn.get());
+
+ if ( xColumn.is() )
+ impl_initializeColumnSettings_nothrow( xColumn, pColumn );
+ }
+ }
+ }
+ // now create the columns we need
+ if(m_pColumns)
+ m_pColumns->assign(aColumns,aNames);
+ else
+ {
+ Reference<XDatabaseMetaData> xMeta = m_xActiveConnection->getMetaData();
+ m_pColumns.reset( new ORowSetDataColumns(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ aColumns,*this,m_aColumnsMutex,aNames) );
+ }
+ }
+ else // !m_bCommandFacetsDirty
+ {
+ Reference< XResultSet > xResultSet;
+ if(m_bParametersDirty)
+ {
+ xResultSet = impl_prepareAndExecute_throw();
+ }
+ else
+ {
+ xResultSet = m_xStatement->executeQuery();
+ m_pCache->reset(xResultSet);
+ }
+ // let our warnings container forget the reference to the (possibly disposed) old result set
+ m_aWarnings.setExternalWarnings( nullptr );
+ // clear all current warnings
+ m_aWarnings.clearWarnings();
+ // let the warnings container know about the new "external warnings"
+ m_aWarnings.setExternalWarnings( Reference< XWarningsSupplier >( xResultSet, UNO_QUERY ) );
+ }
+ checkCache();
+ // notify the rowset listeners
+ notifyAllListeners(_rClearForNotification);
+}
+
+// XRowSetApproveBroadcaster
+void SAL_CALL ORowSet::addRowSetApproveListener( const Reference< XRowSetApproveListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aApproveListeners.addInterface(listener);
+}
+
+void SAL_CALL ORowSet::removeRowSetApproveListener( const Reference< XRowSetApproveListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aApproveListeners.removeInterface(listener);
+}
+
+// XRowsChangeBroadcaster
+void SAL_CALL ORowSet::addRowsChangeListener( const Reference< XRowsChangeListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aRowsChangeListener.addInterface(listener);
+}
+
+void SAL_CALL ORowSet::removeRowsChangeListener( const Reference< XRowsChangeListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aRowsChangeListener.removeInterface(listener);
+}
+
+// XResultSetAccess
+Reference< XResultSet > SAL_CALL ORowSet::createResultSet( )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ if(m_xStatement.is())
+ {
+ rtl::Reference<ORowSetClone> pClone = new ORowSetClone( m_aContext, *this, m_pMutex );
+ m_aClones.emplace_back(css::uno::Reference< css::uno::XWeak >(pClone));
+ return pClone;
+ }
+ return Reference< XResultSet >();
+}
+
+// css::util::XCancellable
+void SAL_CALL ORowSet::cancel( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+}
+
+// css::sdbcx::XDeleteRows
+Sequence< sal_Int32 > SAL_CALL ORowSet::deleteRows( const Sequence< Any >& rows )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ if(!m_pCache || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY)
+ throwFunctionSequenceException(*this);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::DELETE,rows.getLength(),aChangedBookmarks);
+ // notify the rowset listeners
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ Sequence< sal_Int32 > aResults( rows.getLength() );
+ const Any* row = rows.getConstArray();
+ const Any* rowEnd = rows.getConstArray() + rows.getLength();
+ sal_Int32* result = aResults.getArray();
+ for ( ; row != rowEnd; ++row, ++result )
+ {
+ *result = 0;
+ if ( !m_pCache->moveToBookmark( *row ) )
+ continue;
+ sal_Int32 nDeletePosition = m_pCache->getRow();
+
+ // first notify the clones so that they can save their position
+ notifyRowSetAndClonesRowDelete( *row );
+
+ // now delete the row
+ if ( !m_pCache->deleteRow() )
+ continue;
+ *result = 1;
+ // now notify that we have deleted
+ notifyRowSetAndClonesRowDeleted( *row, nDeletePosition );
+ }
+ aEvt.Rows = aResults.getLength();
+
+ // we have to check if we stand on the insert row and if so we have to reset it
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+ // notification order
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+
+ return aResults;
+}
+
+void ORowSet::notifyRowSetAndClonesRowDelete( const Any& _rBookmark )
+{
+ // notify ourself
+ onDeleteRow( _rBookmark );
+ // notify the clones
+ for (auto const& elem : m_aClones)
+ {
+ auto pClone = comphelper::getFromUnoTunnel<ORowSetClone>(elem.get());
+ if(pClone)
+ pClone->onDeleteRow( _rBookmark );
+ }
+}
+
+void ORowSet::notifyRowSetAndClonesRowDeleted( const Any& _rBookmark, sal_Int32 _nPos )
+{
+ // notify ourself
+ onDeletedRow( _rBookmark, _nPos );
+ // notify the clones
+ for (auto const& clone : m_aClones)
+ {
+ auto pClone = comphelper::getFromUnoTunnel<ORowSetClone>(clone.get());
+ if(pClone)
+ pClone->onDeletedRow( _rBookmark, _nPos );
+ }
+}
+
+Reference< XConnection > ORowSet::calcConnection(const Reference< XInteractionHandler >& _rxHandler)
+{
+ MutexGuard aGuard(m_aMutex);
+ if (!m_xActiveConnection.is())
+ {
+ Reference< XConnection > xNewConn;
+ if ( !m_aDataSourceName.isEmpty() )
+ {
+ Reference< XDatabaseContext > xDatabaseContext( DatabaseContext::create(m_aContext) );
+ try
+ {
+ Reference< XDataSource > xDataSource( xDatabaseContext->getByName( m_aDataSourceName ), UNO_QUERY_THROW );
+
+ // try connecting with the interaction handler
+ Reference< XCompletedConnection > xComplConn( xDataSource, UNO_QUERY );
+ if ( _rxHandler.is() && xComplConn.is() )
+ {
+ xNewConn = xComplConn->connectWithCompletion( _rxHandler );
+ }
+ else
+ {
+ xNewConn = xDataSource->getConnection( m_aUser, m_aPassword );
+ }
+ }
+ catch ( const SQLException& )
+ {
+ throw;
+ }
+ catch ( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ OUString sMessage = ResourceManager::loadString( RID_NO_SUCH_DATA_SOURCE,
+ "$name$", m_aDataSourceName, "$error$", extractExceptionMessage( m_aContext, aError ) );
+ ::dbtools::throwGenericSQLException( sMessage, *this, aError );
+ }
+ }
+ setActiveConnection(xNewConn);
+ m_bOwnConnection = true;
+ }
+ return m_xActiveConnection;
+}
+
+Reference< XNameAccess > ORowSet::impl_getTables_throw()
+{
+ Reference< XNameAccess > xTables;
+
+ Reference< XTablesSupplier > xTablesAccess( m_xActiveConnection, UNO_QUERY );
+ if ( xTablesAccess.is() )
+ {
+ xTables.set( xTablesAccess->getTables(), UNO_SET_THROW );
+ }
+ else if ( m_xTables )
+ {
+ xTables = m_xTables.get();
+ }
+ else
+ {
+ if ( !m_xActiveConnection.is() )
+ throw SQLException(DBA_RES(RID_STR_CONNECTION_INVALID),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ bool bCase = true;
+ try
+ {
+ Reference<XDatabaseMetaData> xMeta = m_xActiveConnection->getMetaData();
+ bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xTables.reset(new OTableContainer(*this,m_aMutex,m_xActiveConnection,bCase,nullptr,nullptr,m_nInAppend));
+ xTables = m_xTables.get();
+ Sequence<OUString> aTableFilter { "%" };
+ m_xTables->construct(aTableFilter,Sequence< OUString>());
+ }
+
+ return xTables;
+}
+
+void ORowSet::impl_resetTables_nothrow()
+{
+ if ( !m_xTables )
+ return;
+
+ try
+ {
+ m_xTables->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xTables.reset();
+}
+
+void ORowSet::impl_initComposer_throw( OUString& _out_rCommandToExecute )
+{
+ bool bUseEscapeProcessing = impl_buildActiveCommand_throw( );
+ _out_rCommandToExecute = m_aActiveCommand;
+ if ( !bUseEscapeProcessing )
+ return;
+
+ if (m_bCommandFacetsDirty)
+ m_xComposer = nullptr;
+
+ Reference< XMultiServiceFactory > xFactory( m_xActiveConnection, UNO_QUERY );
+ if ( !m_xComposer.is() && xFactory.is() )
+ {
+ try
+ {
+ m_xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+ }
+ catch (const Exception& ) { m_xComposer = nullptr; }
+ }
+ if ( !m_xComposer.is() )
+ m_xComposer = new OSingleSelectQueryComposer( impl_getTables_throw(), m_xActiveConnection, m_aContext );
+
+ m_xComposer->setCommand( m_aCommand,m_nCommandType );
+ m_aActiveCommand = m_xComposer->getQuery();
+
+ m_xComposer->setFilter( m_bApplyFilter ? m_aFilter : OUString() );
+ m_xComposer->setHavingClause( m_bApplyFilter ? m_aHavingClause : OUString() );
+
+ if ( m_bIgnoreResult )
+ { // append a "0=1" filter
+ // don't simply overwrite an existent filter, this would lead to problems if this existent
+ // filter contains parameters (since a keyset may add parameters itself)
+ m_xComposer->setElementaryQuery( m_xComposer->getQuery( ) );
+ m_xComposer->setFilter( "0 = 1" );
+ }
+
+ m_xComposer->setOrder( m_aOrder );
+ m_xComposer->setGroup( m_aGroupBy );
+
+ if ( !m_xColumns.is() )
+ {
+ Reference< XColumnsSupplier > xCols( m_xComposer, UNO_QUERY_THROW );
+ m_xColumns = xCols->getColumns();
+ }
+
+ impl_initParametersContainer_nothrow();
+
+ _out_rCommandToExecute = m_xComposer->getQueryWithSubstitution();
+
+ m_bCommandFacetsDirty = false;
+}
+
+bool ORowSet::impl_buildActiveCommand_throw()
+{
+ // create the sql command
+ // from a table name or get the command out of a query (not a view)
+ // the last use the command as it is
+ bool bDoEscapeProcessing = m_bUseEscapeProcessing;
+
+ m_aActiveCommand.clear();
+ OUString sCommand;
+
+ if ( m_aCommand.isEmpty() )
+ return bDoEscapeProcessing;
+
+ switch (m_nCommandType)
+ {
+ case CommandType::TABLE:
+ {
+ impl_resetTables_nothrow();
+ if ( bDoEscapeProcessing )
+ {
+ Reference< XNameAccess > xTables( impl_getTables_throw() );
+ if ( xTables->hasByName(m_aCommand) )
+ {
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_TABLE_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", m_aCommand ),*this);
+ }
+ }
+ else
+ {
+ sCommand = "SELECT * FROM ";
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents( m_xActiveConnection->getMetaData(), m_aCommand, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
+ sCommand += ::dbtools::composeTableNameForSelect( m_xActiveConnection, sCatalog, sSchema, sTable );
+ }
+ }
+ break;
+
+ case CommandType::QUERY:
+ {
+ Reference< XQueriesSupplier > xQueriesAccess(m_xActiveConnection, UNO_QUERY);
+ if (!xQueriesAccess.is())
+ throw SQLException(DBA_RES(RID_STR_NO_XQUERIESSUPPLIER),*this,OUString(),0,Any());
+ Reference< css::container::XNameAccess > xQueries(xQueriesAccess->getQueries());
+ if (xQueries->hasByName(m_aCommand))
+ {
+ Reference< XPropertySet > xQuery(xQueries->getByName(m_aCommand),UNO_QUERY);
+ OSL_ENSURE(xQuery.is(),"ORowSet::impl_buildActiveCommand_throw: Query is NULL!");
+ if ( xQuery.is() )
+ {
+ xQuery->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
+ xQuery->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bDoEscapeProcessing;
+ if ( bDoEscapeProcessing != m_bUseEscapeProcessing )
+ {
+ bool bOldValue = m_bUseEscapeProcessing;
+ m_bUseEscapeProcessing = bDoEscapeProcessing;
+ fireProperty(PROPERTY_ID_ESCAPE_PROCESSING,bOldValue,bDoEscapeProcessing);
+ }
+
+ OUString aCatalog,aSchema,aTable;
+ xQuery->getPropertyValue(PROPERTY_UPDATE_CATALOGNAME) >>= aCatalog;
+ xQuery->getPropertyValue(PROPERTY_UPDATE_SCHEMANAME) >>= aSchema;
+ xQuery->getPropertyValue(PROPERTY_UPDATE_TABLENAME) >>= aTable;
+ if(!aTable.isEmpty())
+ m_aUpdateTableName = composeTableName( m_xActiveConnection->getMetaData(), aCatalog, aSchema, aTable, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_QUERY_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", m_aCommand ),*this);
+ }
+ }
+ break;
+
+ default:
+ sCommand = m_aCommand;
+ break;
+ }
+
+ m_aActiveCommand = sCommand;
+
+ if ( m_aActiveCommand.isEmpty() && !bDoEscapeProcessing )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_SQL_COMMAND ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+
+ return bDoEscapeProcessing;
+}
+
+void ORowSet::impl_initParametersContainer_nothrow()
+{
+ OSL_PRECOND( !m_pParameters.is(), "ORowSet::impl_initParametersContainer_nothrow: already initialized the parameters!" );
+
+ m_pParameters = new param::ParameterWrapperContainer( m_xComposer );
+ // copy the premature parameters into the final ones
+ size_t nParamCount( std::min( m_pParameters->size(), m_aPrematureParamValues->size() ) );
+ for ( size_t i=0; i<nParamCount; ++i )
+ {
+ (*m_pParameters)[i] = (*m_aPrematureParamValues)[i];
+ }
+}
+
+void ORowSet::impl_disposeParametersContainer_nothrow()
+{
+ if ( !m_pParameters.is() )
+ return;
+
+ // copy the actual values to our "premature" ones, to preserve them for later use
+ size_t nParamCount( m_pParameters->size() );
+ m_aPrematureParamValues->resize( nParamCount );
+ for ( size_t i=0; i<nParamCount; ++i )
+ {
+ (*m_aPrematureParamValues)[i] = (*m_pParameters)[i];
+ }
+
+ m_pParameters->dispose();
+ m_pParameters = nullptr;
+}
+
+ORowSetValue& ORowSet::getParameterStorage(sal_Int32 parameterIndex)
+{
+ ::connectivity::checkDisposed( ORowSet_BASE1::rBHelper.bDisposed );
+ if ( parameterIndex < 1 )
+ throwInvalidIndexException( *this );
+
+ if ( m_aParametersSet.size() < o3tl::make_unsigned(parameterIndex) )
+ m_aParametersSet.resize( parameterIndex ,false);
+ m_aParametersSet[parameterIndex - 1] = true;
+
+ if ( m_pParameters.is() )
+ {
+ if ( m_bCommandFacetsDirty )
+ // need to rebuild the parameters, since some property which contributes to the
+ // complete command, and thus the parameters, changed
+ impl_disposeParametersContainer_nothrow();
+ if ( m_pParameters.is() )
+ {
+ if ( o3tl::make_unsigned(parameterIndex) > m_pParameters->size() )
+ throwInvalidIndexException( *this );
+ return (*m_pParameters)[ parameterIndex - 1 ];
+ }
+ }
+
+ if ( m_aPrematureParamValues->size() < o3tl::make_unsigned(parameterIndex) )
+ m_aPrematureParamValues->resize( parameterIndex );
+ return (*m_aPrematureParamValues)[ parameterIndex - 1 ];
+}
+
+// XParameters
+void SAL_CALL ORowSet::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ getParameterStorage( parameterIndex ).setNull();
+ m_bParametersDirty = true;
+}
+
+void SAL_CALL ORowSet::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
+{
+ setNull( parameterIndex, sqlType );
+}
+
+void ORowSet::setParameter(sal_Int32 parameterIndex, const ORowSetValue& x)
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ getParameterStorage( parameterIndex ) = x;
+ m_bParametersDirty = true;
+}
+
+void SAL_CALL ORowSet::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ setParameter(parameterIndex, static_cast<bool>(x));
+}
+
+void SAL_CALL ORowSet::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setFloat( sal_Int32 parameterIndex, float x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setDouble( sal_Int32 parameterIndex, double x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setDate( sal_Int32 parameterIndex, const css::util::Date& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ ORowSetValue& rParamValue( getParameterStorage( parameterIndex ) );
+
+ try
+ {
+ Sequence <sal_Int8> aData;
+ x->readBytes(aData, length);
+ rParamValue = aData;
+ m_bParametersDirty = true;
+ x->closeInput();
+ }
+ catch( Exception const & )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw SQLException("ORowSet::setBinaryStream", *this, "S1000", 0,anyEx);
+ }
+}
+
+void SAL_CALL ORowSet::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ ORowSetValue& rParamValue( getParameterStorage( parameterIndex ) );
+ try
+ {
+ Sequence <sal_Int8> aData;
+ OUString aDataStr;
+ // the data is given as character data and the length defines the character length
+ sal_Int32 nSize = x->readBytes(aData, length * sizeof(sal_Unicode));
+ if (nSize / sizeof(sal_Unicode))
+ aDataStr = OUString(reinterpret_cast<sal_Unicode const *>(aData.getConstArray()), nSize / sizeof(sal_Unicode));
+ m_bParametersDirty = true;
+ rParamValue = aDataStr;
+ rParamValue.setTypeKind( DataType::LONGVARCHAR );
+ x->closeInput();
+ }
+ catch( Exception const & )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw SQLException("ORowSet::setCharacterStream", *this, "S1000", 0, anyEx);
+ }
+}
+
+void SAL_CALL ORowSet::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if ( !::dbtools::implSetObject( this, parameterIndex, x ) )
+ { // there is no other setXXX call which can handle the value in x
+ throw SQLException();
+ }
+ m_bParametersDirty = true;
+}
+
+void SAL_CALL ORowSet::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 /*scale*/ )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ ORowSetValue& rParamValue( getParameterStorage( parameterIndex ) );
+ setObject( parameterIndex, x );
+ rParamValue.setTypeKind( targetSqlType );
+}
+
+void SAL_CALL ORowSet::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setRef", *this );
+}
+
+void SAL_CALL ORowSet::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this );
+}
+
+void SAL_CALL ORowSet::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setClob", *this );
+}
+
+void SAL_CALL ORowSet::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setArray", *this );
+}
+
+void SAL_CALL ORowSet::clearParameters( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ size_t nParamCount( m_pParameters.is() ? m_pParameters->size() : m_aPrematureParamValues->size() );
+ for ( size_t i=1; i<=nParamCount; ++i )
+ getParameterStorage( static_cast<sal_Int32>(i) ).setNull();
+ m_aParametersSet.clear();
+}
+
+Any SAL_CALL ORowSet::getWarnings( )
+{
+ return m_aWarnings.getWarnings();
+}
+
+void SAL_CALL ORowSet::clearWarnings( )
+{
+ m_aWarnings.clearWarnings();
+}
+
+void ORowSet::doCancelModification( )
+{
+ if ( isModification() )
+ {
+ // read-only flag restored
+ impl_restoreDataColumnsWriteable_throw();
+ m_pCache->cancelRowModification();
+ }
+ m_bModified = false;
+ m_bIsInsertRow = false;
+}
+
+bool ORowSet::isModification( )
+{
+ return isNew();
+}
+
+bool ORowSet::isModified( )
+{
+ return m_bModified;
+}
+
+bool ORowSet::isNew( )
+{
+ return m_bNew;
+}
+
+bool ORowSet::isPropertyChangeNotificationEnabled() const
+{
+ return m_bPropChangeNotifyEnabled;
+}
+
+void ORowSet::checkUpdateIterator()
+{
+ if(!m_bIsInsertRow)
+ {
+ m_pCache->setUpdateIterator(m_aCurrentRow);
+ m_aCurrentRow = m_pCache->m_aInsertRow;
+ m_bIsInsertRow = true;
+ }
+}
+
+void ORowSet::checkUpdateConditions(sal_Int32 columnIndex)
+{
+ checkCache();
+ if ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY)
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_RESULT_IS_READONLY ), StandardSQLState::GENERAL_ERROR, *this );
+
+ if ( rowDeleted() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_ROW_ALREADY_DELETED ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+
+ if ( m_aCurrentRow.isNull() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_INVALID_CURSOR_STATE ), StandardSQLState::INVALID_CURSOR_STATE, *this );
+
+ if ( columnIndex <= 0 || (*m_aCurrentRow)->size() <= o3tl::make_unsigned(columnIndex) )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_INVALID_INDEX ), StandardSQLState::INVALID_DESCRIPTOR_INDEX, *this );
+}
+
+void SAL_CALL ORowSet::refreshRow( )
+{
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ // notification order:
+ if ( m_bModified && m_pCache )
+ implCancelRowUpdates( false ); // do _not_ notify the IsModify - will do this ourself below
+
+ // - column values
+ ORowSetBase::refreshRow();
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+}
+
+void ORowSet::impl_rebuild_throw(::osl::ResettableMutexGuard& _rGuard)
+{
+ Reference< XResultSet > xResultSet(m_xStatement->executeQuery());
+ m_pCache->reset(xResultSet);
+ m_aWarnings.setExternalWarnings( Reference< XWarningsSupplier >( xResultSet, UNO_QUERY ) );
+ notifyAllListeners(_rGuard);
+}
+
+// ***********************************************************
+// ORowSetClone
+// ***********************************************************
+
+ORowSetClone::ORowSetClone( const Reference<XComponentContext>& _rContext, ORowSet& rParent, ::osl::Mutex* _pMutex )
+ :OSubComponent(m_aMutex, rParent)
+ ,ORowSetBase( _rContext, OComponentHelper::rBHelper, _pMutex )
+ ,m_pParent(&rParent)
+ ,m_nFetchDirection(rParent.m_nFetchDirection)
+ ,m_nFetchSize(rParent.m_nFetchSize)
+ ,m_bIsBookmarkable(true)
+{
+
+ m_nResultSetType = rParent.m_nResultSetType;
+ m_nResultSetConcurrency = ResultSetConcurrency::READ_ONLY;
+ m_pMySelf = this;
+ m_bClone = true;
+ m_bBeforeFirst = rParent.m_bBeforeFirst;
+ m_bAfterLast = rParent.m_bAfterLast;
+ m_pCache = rParent.m_pCache;
+ m_aBookmark = rParent.m_aBookmark;
+ m_aCurrentRow = m_pCache->createIterator(this);
+ m_xNumberFormatTypes = rParent.m_xNumberFormatTypes;
+
+ m_aOldRow = m_pCache->registerOldRow();
+
+ ::rtl::Reference< ::connectivity::OSQLColumns> aColumns = new ::connectivity::OSQLColumns();
+ std::vector< OUString> aNames;
+
+ OUString aDescription;
+ Locale aLocale = SvtSysLocale().GetLanguageTag().getLocale();
+
+ if ( rParent.m_pColumns )
+ {
+ Sequence< OUString> aSeq = rParent.m_pColumns->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ aColumns->reserve(aSeq.getLength()+1);
+ for(sal_Int32 i=1;pIter != pEnd ;++pIter,++i)
+ {
+ Reference<XPropertySet> xColumn;
+ rParent.m_pColumns->getByName(*pIter) >>= xColumn;
+ if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_DESCRIPTION))
+ aDescription = comphelper::getString(xColumn->getPropertyValue(PROPERTY_DESCRIPTION));
+
+ OUString sParseLabel;
+ xColumn->getPropertyValue(PROPERTY_LABEL) >>= sParseLabel;
+ rtl::Reference<ORowSetColumn> pColumn = new ORowSetColumn( rParent.getMetaData(),
+ this,
+ i,
+ rParent.m_xActiveConnection->getMetaData(),
+ aDescription,
+ sParseLabel,
+ [this] (sal_Int32 const column) -> ORowSetValue const& {
+ return this->getValue(column);
+ });
+ aColumns->emplace_back(pColumn);
+ pColumn->setName(*pIter);
+ aNames.push_back(*pIter);
+ m_aDataColumns.push_back(pColumn.get());
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ALIGN,xColumn->getPropertyValue(PROPERTY_ALIGN));
+ sal_Int32 nFormatKey = 0;
+ xColumn->getPropertyValue(PROPERTY_NUMBERFORMAT) >>= nFormatKey;
+ if(!nFormatKey && xColumn.is() && m_xNumberFormatTypes.is())
+ nFormatKey = ::dbtools::getDefaultNumberFormat(xColumn,m_xNumberFormatTypes,aLocale);
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_NUMBERFORMAT,Any(nFormatKey));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_RELATIVEPOSITION,xColumn->getPropertyValue(PROPERTY_RELATIVEPOSITION));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_WIDTH,xColumn->getPropertyValue(PROPERTY_WIDTH));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_HIDDEN,xColumn->getPropertyValue(PROPERTY_HIDDEN));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_CONTROLMODEL,xColumn->getPropertyValue(PROPERTY_CONTROLMODEL));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_HELPTEXT,xColumn->getPropertyValue(PROPERTY_HELPTEXT));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_CONTROLDEFAULT,xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT));
+
+ }
+ }
+ Reference<XDatabaseMetaData> xMeta = rParent.m_xActiveConnection->getMetaData();
+ m_pColumns.reset( new ORowSetDataColumns(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ aColumns,*this,m_aMutex,aNames) );
+
+ sal_Int32 const nRT = PropertyAttribute::READONLY | PropertyAttribute::TRANSIENT;
+
+ // sdb.RowSet Properties
+ registerMayBeVoidProperty(PROPERTY_ACTIVE_CONNECTION,PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, &rParent.m_aActiveConnection, cppu::UnoType<XConnection>::get());
+ registerProperty(PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::READONLY, &m_nResultSetConcurrency,::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY, &m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, PropertyAttribute::TRANSIENT, &m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, PropertyAttribute::TRANSIENT, &m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, nRT, &m_bIsBookmarkable, cppu::UnoType<bool>::get());
+}
+
+ORowSetClone::~ORowSetClone()
+{
+}
+
+// css::XTypeProvider
+Sequence< Type > ORowSetClone::getTypes()
+{
+ return ::comphelper::concatSequences(OSubComponent::getTypes(),ORowSetBase::getTypes());
+}
+
+// css::XInterface
+Any ORowSetClone::queryInterface( const Type & rType )
+{
+ Any aRet = ORowSetBase::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OSubComponent::queryInterface(rType);
+ return aRet;
+}
+
+void ORowSetClone::acquire() noexcept
+{
+ OSubComponent::acquire();
+}
+
+void ORowSetClone::release() noexcept
+{
+ OSubComponent::release();
+}
+
+// XServiceInfo
+OUString ORowSetClone::getImplementationName( )
+{
+ return "com.sun.star.sdb.ORowSetClone";
+}
+
+sal_Bool ORowSetClone::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > ORowSetClone::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_RESULTSET, SERVICE_SDB_RESULTSET };
+}
+
+// OComponentHelper
+void ORowSetClone::disposing()
+{
+ MutexGuard aGuard( m_aMutex );
+ ORowSetBase::disposing();
+
+ m_pParent = nullptr;
+ m_pMutex = &m_aMutex; // this must be done here because someone could hold a ref to us and try to do something
+ OSubComponent::disposing();
+}
+
+// XCloseable
+void ORowSetClone::close()
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ if (OComponentHelper::rBHelper.bDisposed)
+ throw DisposedException();
+ }
+ dispose();
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSetClone::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& SAL_CALL ORowSetClone::getInfoHelper()
+{
+ return *::comphelper::OPropertyArrayUsageHelper<ORowSetClone>::getArrayHelper();
+}
+
+const Sequence< sal_Int8 > & ORowSetClone::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::XUnoTunnel
+sal_Int64 SAL_CALL ORowSetClone::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+void SAL_CALL ORowSetClone::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if ( nHandle == PROPERTY_ID_FETCHSIZE )
+ {
+ if ( m_pParent )
+ m_pParent->setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ }
+
+ OPropertyStateContainer::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+}
+
+void ORowSetClone::doCancelModification( )
+{
+}
+
+bool ORowSetClone::isModification( )
+{
+ return false;
+}
+
+bool ORowSetClone::isModified( )
+{
+ return false;
+}
+
+bool ORowSetClone::isNew( )
+{
+ return false;
+}
+
+void SAL_CALL ORowSetClone::execute( )
+{
+ throwFunctionNotSupportedSQLException( "RowSetClone::XRowSet::execute", *this );
+}
+
+void SAL_CALL ORowSetClone::addRowSetListener( const Reference< XRowSetListener >& )
+{
+ throwFunctionNotSupportedRuntimeException( "RowSetClone::XRowSet", *this );
+}
+
+void SAL_CALL ORowSetClone::removeRowSetListener( const Reference< XRowSetListener >& )
+{
+ throwFunctionNotSupportedRuntimeException( "RowSetClone::XRowSet", *this );
+}
+
+} // dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSet.hxx b/dbaccess/source/core/api/RowSet.hxx
new file mode 100644
index 000000000..afe49a923
--- /dev/null
+++ b/dbaccess/source/core/api/RowSet.hxx
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <apitools.hxx>
+#include "RowSetBase.hxx"
+
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/sdbc/XRowSetListener.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdb/XRowSetApproveBroadcaster.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdb/XCompletedExecution.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
+
+#include <cppuhelper/compbase12.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <connectivity/paramwrapper.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/warningscontainer.hxx>
+
+namespace dbaccess
+{
+ typedef ::cppu::WeakAggComponentImplHelper12 < css::sdb::XResultSetAccess
+ , css::sdb::XRowSetApproveBroadcaster
+ , css::sdb::XRowsChangeBroadcaster
+ , css::sdbcx::XDeleteRows
+ , css::sdbc::XParameters
+ , css::lang::XEventListener
+ , css::sdbc::XResultSetUpdate
+ , css::sdbc::XRowUpdate
+ , css::util::XCancellable
+ , css::sdb::XCompletedExecution
+ , css::sdb::XParametersSupplier
+ , css::sdbc::XWarningsSupplier
+ > ORowSet_BASE1;
+
+ class OTableContainer;
+ class ORowSet final : public cppu::BaseMutex
+ , public ORowSet_BASE1
+ , public ORowSetBase
+ , public ::comphelper::OPropertyArrayUsageHelper<ORowSet>
+ {
+ friend class ORowSetClone;
+
+ css::uno::Reference< css::sdbc::XConnection > m_xOldConnection;
+ css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection;
+ css::uno::Any m_aActiveConnection;
+ css::uno::Reference< css::container::XNameAccess > m_xTypeMap;
+ css::uno::Any m_aTypeMap;
+ css::uno::Reference< css::sdbc::XPreparedStatement > m_xStatement;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xComposer;
+ css::uno::Reference< css::container::XNameAccess > m_xColumns; // the columns from a table or query
+
+ connectivity::OWeakRefArray m_aClones;
+ /** our parameters as XPropertySet instances and ORowSetValue instances
+ */
+ ::dbtools::param::ParametersContainerRef m_pParameters;
+ /** our parameters values, used when we do not yet have a parameters container
+ (since we have not been executed, yet)
+ */
+ rtl::Reference<ORowSetValueVector> m_aPrematureParamValues;
+ rtl::Reference<ORowSetValueVector> m_aParameterValueForCache;
+ std::vector<bool> m_aParametersSet;
+ std::vector<bool> m_aReadOnlyDataColumns;
+
+ ::comphelper::OInterfaceContainerHelper3<css::sdbc::XRowSetListener> m_aRowsetListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::sdb::XRowSetApproveListener> m_aApproveListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::sdb::XRowsChangeListener> m_aRowsChangeListener;
+
+ ::dbtools::WarningsContainer m_aWarnings;
+
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OTableContainer> m_xTables;
+
+ OUString m_aCommand;
+ OUString m_aDataSourceName;
+ OUString m_aURL;
+ OUString m_aUser;
+ OUString m_aPassword;
+ OUString m_aFilter;
+ OUString m_aHavingClause;
+ OUString m_aGroupBy;
+ OUString m_aOrder;
+ OUString m_aActiveCommand;
+ OUString m_aUpdateCatalogName; // is set by a query
+ OUString m_aUpdateSchemaName; // is set by a query
+ OUString m_aUpdateTableName; // is set by a query
+ OUString m_sErrorString;
+
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nMaxFieldSize;
+ sal_Int32 m_nMaxRows;
+ sal_Int32 m_nQueryTimeOut;
+ sal_Int32 m_nCommandType;
+ sal_Int32 m_nTransactionIsolation;
+ sal_Int32 m_nPrivileges;
+ sal_Int32 m_nLastKnownRowCount;
+ std::atomic<std::size_t> m_nInAppend;
+ bool m_bInsertingRow;
+ bool m_bLastKnownRowCountFinal;
+ bool m_bUseEscapeProcessing ;
+ bool m_bApplyFilter ;
+ bool m_bCommandFacetsDirty; // any of the facets which define the active command is dirty
+ bool m_bParametersDirty; // parameters changed since execute
+ bool m_bModified ;
+ bool m_bRebuildConnOnExecute ;
+ bool m_bIsBookmarkable ;
+ bool m_bNew ;
+ bool m_bCanUpdateInsertedRows;
+ bool m_bOwnConnection;
+ bool m_bPropChangeNotifyEnabled;
+
+ /** builds m_aActiveCommand from our settings
+
+ @return
+ whether we should use escape processing before executing the actual command. This is determined
+ from our own EscapeProcessing property, and possibly overruled by the respective property
+ of a query we're based on.
+ */
+ bool impl_buildActiveCommand_throw();
+
+ /** initializes our query composer, and everything which has to do with it
+
+ If we don't use escape processing, then we don't have a composer, and everything
+ related to it. Nonetheless, _out_rCommandToExecute and the return value are properly
+ initialized.
+
+ @param _out_rCommandToExecute
+ The command which is to be executed, according to the current settings -
+ it is built from our active command plus our current filter/order criterions.
+
+ @precond
+ m_xActiveConnection points to a valid SDB-level connection
+
+ @throws css::sdb::SQLException
+ if a database-related error occurred
+
+ @throws css::uno::RuntimeException
+ if any of the components involved throws a css::uno::RuntimeException
+ */
+ void impl_initComposer_throw( OUString& _out_rCommandToExecute );
+
+ /** returns the table container of our active connection
+
+ If our connection is able to provide a tables container, this one is returned.
+ Else, if m_pTables is not <NULL/>, this one will returned.
+ Else, m_pTables will be constructed and returned.
+
+ @precond m_xActiveConnection is not <NULL/>
+ @throws css::sdbc::SQLException
+ if retrieving or constructing the tables container goes wrong
+
+ @see impl_resetTables_nothrow
+ */
+ css::uno::Reference< css::container::XNameAccess >
+ impl_getTables_throw();
+
+ /** cleans up m_pTables, and resets it to <NULL/>
+ */
+ void impl_resetTables_nothrow();
+
+ /** prepares and executes our command
+ */
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_prepareAndExecute_throw();
+ void impl_ensureStatement_throw();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > calcConnection(const css::uno::Reference< css::task::XInteractionHandler >& _rxHandler);
+ // free clones and ParseTree. Plus, if _bComplete is <TRUE/>, *all* other associated resources
+ void freeResources( bool _bComplete );
+
+ /// informs the clones (and ourself) that we are going to delete a record with a given bookmark
+ void notifyRowSetAndClonesRowDelete( const css::uno::Any& _rBookmark );
+
+ /// inform the clones (and ourself) that we have deleted a record with a given bookmark
+ void notifyRowSetAndClonesRowDeleted( const css::uno::Any& _rBookmark, sal_Int32 _nPos );
+
+ void checkUpdateIterator();
+ const connectivity::ORowSetValue& getInsertValue(sal_Int32 columnIndex);
+ void setParameter(sal_Int32 parameterIndex, const connectivity::ORowSetValue& x);
+ // resizes the parameter vector if necessary
+ ::connectivity::ORowSetValue& getParameterStorage( sal_Int32 parameterIndex );
+
+ void updateValue(sal_Int32 columnIndex,const connectivity::ORowSetValue& x);
+ void checkUpdateConditions(sal_Int32 columnIndex);
+ void impl_rebuild_throw(::osl::ResettableMutexGuard& _rGuard);
+ // set all data columns to writeable
+ void impl_setDataColumnsWriteable_throw();
+ // restore the old state of the data column read-only state
+ void impl_restoreDataColumnsWriteable_throw();
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue,sal_Int32 nHandle) const override;
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ virtual void fireRowcount() override;
+ void notifyAllListenersRowBeforeChange(::osl::ResettableMutexGuard& _rGuard,const css::sdb::RowChangeEvent &rEvt);
+ void notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard,const css::sdb::RowsChangeEvent& rEvt);
+ virtual bool notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard) override;
+ virtual void notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard) override;
+ // notify all that rowset changed
+ void notifyAllListeners(::osl::ResettableMutexGuard& _rGuard);
+
+ virtual void doCancelModification( ) override;
+ virtual bool isModification( ) override;
+ virtual bool isModified( ) override;
+ virtual bool isNew( ) override;
+ virtual bool isPropertyChangeNotificationEnabled() const override;
+
+ virtual ~ORowSet() override;
+
+ public:
+ explicit ORowSet(const css::uno::Reference<css::uno::XComponentContext>&);
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // css::uno::XAggregation
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& aType ) override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // css::sdbc::XResultSet
+ virtual void SAL_CALL refreshRow( ) override;
+
+ // XCompletedExecution
+ virtual void SAL_CALL executeWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler ) override;
+
+ // XParametersSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getParameters( ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // css::sdbc::XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute( ) override;
+ virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+ virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+
+ // css::sdb::XRowSetApproveBroadcaster
+ virtual void SAL_CALL addRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override;
+ virtual void SAL_CALL removeRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override;
+
+ // css::sdb::XRowsChangeBroadcaster
+ virtual void SAL_CALL addRowsChangeListener( const css::uno::Reference< css::sdb::XRowsChangeListener >& listener ) override;
+ virtual void SAL_CALL removeRowsChangeListener( const css::uno::Reference< css::sdb::XRowsChangeListener >& listener ) override;
+
+ // css::sdb::XResultSetAccess
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL createResultSet( ) override;
+
+ // css::util::XCancellable
+ virtual void SAL_CALL cancel( ) override;
+
+ // css::sdbcx::XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ /** implement the <method>execute</method>, without calling the approve listeners and without building a new
+ connection
+ @param _rClearForNotification mutex to clear before doing the final notifications
+ */
+ void execute_NoApprove_NoNewConn(::osl::ResettableMutexGuard& _rClearForNotification);
+
+ /** call the RowSetApproveListeners<p/>
+ @throws css::sdb::RowSetVetoException if one of the listeners vetoed
+ @throws css::uno::RuntimeException
+ */
+ void approveExecution();
+
+ /// set m_xActiveConnection, fire a PropertyChangeEvent if necessary, do the event listener handling etc
+ void setActiveConnection( css::uno::Reference< css::sdbc::XConnection > const & _rxNewConn, bool _bFireEvent = true );
+
+ void implCancelRowUpdates( bool _bNotifyModified );
+
+ /** sets the given result set type/concurrency at the given statement, while respecting
+ possibly related data source settings
+ */
+ void setStatementResultSetType(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxStatement,
+ sal_Int32 _nDesiredResultSetType,
+ sal_Int32 _nDesiredResultSetConcurrency
+ );
+
+ /** initializes a given RowSet column with the ColumnSettings (width, format, hidden, etc.) from a
+ template column.
+
+ If the template column supports any of the known column settings, they're plain copied. If not,
+ the template column is examined for a TableName and Name property, and the table column described
+ by those is used to find and copy the column settings.
+ */
+ void impl_initializeColumnSettings_nothrow(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxTemplateColumn,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxRowSetColumn
+ );
+
+ /** initializes our parameters container (m_pParameters) according to the parameter columns as
+ obtained from our composer
+ */
+ void impl_initParametersContainer_nothrow();
+ /** disposes our parameters container
+ */
+ void impl_disposeParametersContainer_nothrow();
+
+ using ORowSetBase::getFastPropertyValue;
+ using ORowSetBase::firePropertyChange;
+ using ORowSetBase::doCancelModification;
+ using ORowSetBase::isModification;
+ using ORowSetBase::isModified;
+ using ORowSetBase::isNew;
+ };
+
+
+ // ORowSetClone
+
+ class ORowSetClone : public cppu::BaseMutex
+ ,public OSubComponent
+ ,public ORowSetBase
+ ,public ::comphelper::OPropertyArrayUsageHelper < ORowSetClone >
+ {
+ ORowSet* m_pParent;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nFetchSize;
+ bool m_bIsBookmarkable;
+
+ protected:
+ // the clone can not insert anything
+ virtual void doCancelModification( ) override;
+ virtual bool isModification( ) override;
+ virtual bool isModified( ) override;
+ virtual bool isNew( ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ public:
+ ORowSetClone( const css::uno::Reference<css::uno::XComponentContext>& _rContext, ORowSet& rParent, ::osl::Mutex* _pMutex );
+ virtual ~ORowSetClone() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override
+ {
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+ }
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute( ) override;
+ virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+ virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ protected:
+ using ORowSetBase::doCancelModification;
+ using ORowSetBase::isModification;
+ using ORowSetBase::isModified;
+ using ORowSetBase::isNew;
+ using ORowSetBase::rowDeleted;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetBase.cxx b/dbaccess/source/core/api/RowSetBase.cxx
new file mode 100644
index 000000000..46e612271
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetBase.cxx
@@ -0,0 +1,1438 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "RowSetBase.hxx"
+#include "CRowSetDataColumn.hxx"
+#include <connectivity/sdbcx/VCollection.hxx>
+#include "RowSetCache.hxx"
+#include <stringconstants.hxx>
+#include <sal/log.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/seqstream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/safeint.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace comphelper;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::cppu;
+using namespace ::osl;
+
+namespace dbaccess
+{
+
+// OEmptyCollection
+class OEmptyCollection : public sdbcx::OCollection
+{
+protected:
+ virtual void impl_refresh() override;
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+public:
+ OEmptyCollection(::cppu::OWeakObject& _rParent,::osl::Mutex& _rMutex) : OCollection(_rParent, true, _rMutex, std::vector< OUString>()){}
+};
+
+void OEmptyCollection::impl_refresh()
+{
+}
+
+connectivity::sdbcx::ObjectType OEmptyCollection::createObject(const OUString& /*_rName*/)
+{
+ return connectivity::sdbcx::ObjectType();
+}
+
+// ORowSetBase
+
+ORowSetBase::ORowSetBase( const Reference<XComponentContext>& _rContext, ::cppu::OBroadcastHelper& _rBHelper, ::osl::Mutex* _pMutex )
+ :OPropertyStateContainer(_rBHelper)
+ ,m_pMutex(_pMutex)
+ ,m_pMySelf(nullptr)
+ ,m_rBHelper(_rBHelper)
+ ,m_aContext( _rContext )
+ ,m_nLastColumnIndex(-1)
+ ,m_nDeletedPosition(-1)
+ ,m_nResultSetType( ResultSetType::FORWARD_ONLY )
+ ,m_nResultSetConcurrency( ResultSetConcurrency::READ_ONLY )
+ ,m_bClone(false)
+ ,m_bIgnoreResult(false)
+ ,m_bBeforeFirst(true) // changed from sal_False
+ ,m_bAfterLast(false)
+ ,m_bIsInsertRow(false)
+{
+ sal_Int32 nRBT = PropertyAttribute::READONLY | PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT;
+
+ registerPropertyNoMember( PROPERTY_ROWCOUNT, PROPERTY_ID_ROWCOUNT, nRBT, cppu::UnoType<sal_Int32>::get(), css::uno::Any(sal_Int32(0)) );
+ registerPropertyNoMember( PROPERTY_ISROWCOUNTFINAL, PROPERTY_ID_ISROWCOUNTFINAL, nRBT, cppu::UnoType<bool>::get(), css::uno::Any(false) );
+}
+
+ORowSetBase::~ORowSetBase()
+{
+ if(m_pColumns)
+ {
+ TDataColumns().swap(m_aDataColumns);
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+ }
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > ORowSetBase::getTypes()
+{
+ return ::comphelper::concatSequences(ORowSetBase_BASE::getTypes(),OPropertyStateContainer::getTypes());
+}
+
+// css::uno::XInterface
+Any ORowSetBase::queryInterface( const Type & rType )
+{
+ Any aRet = ORowSetBase_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OPropertyStateContainer::queryInterface(rType);
+ return aRet;
+}
+
+void SAL_CALL ORowSetBase::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ if(m_pCache)
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ROWCOUNT:
+ rValue <<= impl_getRowCount();
+ break;
+ case PROPERTY_ID_ISROWCOUNTFINAL:
+ rValue <<= m_pCache->m_bRowCountFinal;
+ break;
+ default:
+ OPropertyStateContainer::getFastPropertyValue(rValue,nHandle);
+ }
+ }
+ else
+ OPropertyStateContainer::getFastPropertyValue(rValue,nHandle);
+}
+
+// OComponentHelper
+void SAL_CALL ORowSetBase::disposing()
+{
+ MutexGuard aGuard(*m_pMutex);
+
+ if ( m_pColumns )
+ {
+ TDataColumns().swap(m_aDataColumns);
+ m_pColumns->disposing();
+ }
+ if ( m_pCache )
+ {
+ m_pCache->deregisterOldRow(m_aOldRow);
+ m_pCache->deleteIterator(this);
+ }
+ m_pCache = nullptr;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSetBase::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& SAL_CALL ORowSetBase::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+// XRow
+sal_Bool SAL_CALL ORowSetBase::wasNull( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return !((m_nLastColumnIndex != -1) && !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is())
+ || (**m_aCurrentRow)[m_nLastColumnIndex].isNull();
+}
+
+const ORowSetValue& ORowSetBase::getValue(sal_Int32 columnIndex)
+{
+ checkCache();
+ return impl_getValue(columnIndex);
+}
+
+const ORowSetValue& ORowSetBase::impl_getValue(sal_Int32 columnIndex)
+{
+ if ( m_bBeforeFirst || m_bAfterLast )
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::getValue: Illegal call here (we're before first or after last)!");
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_CURSOR_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+ }
+
+ if ( impl_rowDeleted() )
+ {
+ return m_aEmptyValue;
+ }
+
+ bool bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ if ( !bValidCurrentRow )
+ {
+ // currentrow is null when the clone moves the window
+ positionCache( MOVE_NONE );
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"ORowSetBase::getValue: we don't stand on a valid row! Row is null.");
+
+ bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ }
+
+ if ( bValidCurrentRow )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ ORowSetMatrix::const_iterator aCacheEnd;
+ ORowSetMatrix::iterator aCurrentRow;
+ aCacheEnd = m_pCache->getEnd();
+ aCurrentRow = m_aCurrentRow;
+ ORowSetCacheMap::const_iterator aCacheIter = m_aCurrentRow.getIter();
+ ORowSetCacheIterator_Helper aHelper = aCacheIter->second;
+ ORowSetMatrix::const_iterator k = aHelper.aIterator;
+ for (; k != m_pCache->getEnd(); ++k)
+ {
+ ORowSetValueVector* pTemp = k->get();
+ OSL_ENSURE( pTemp != reinterpret_cast<void*>(0xfeeefeee),"HALT!" );
+ }
+ OSL_ENSURE(!m_aCurrentRow.isNull() && m_aCurrentRow < m_pCache->getEnd() && aCacheIter != m_pCache->m_aCacheIterators.end(),"Invalid iterator set for currentrow!");
+#endif
+ ORowSetRow rRow = *m_aCurrentRow;
+ bool bValidPosition = rRow.is() && o3tl::make_unsigned(columnIndex) < rRow->size();
+ if (!bValidPosition)
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::getValue: Invalid size of vector!");
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_CURSOR_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+ }
+ m_nLastColumnIndex = columnIndex;
+ return (*rRow)[m_nLastColumnIndex];
+ }
+
+ // we should normally never reach this
+ return m_aEmptyValue;
+}
+
+OUString SAL_CALL ORowSetBase::getString( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getString();
+}
+
+sal_Bool SAL_CALL ORowSetBase::getBoolean( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getBool();
+}
+
+sal_Int8 SAL_CALL ORowSetBase::getByte( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getInt8();
+}
+
+sal_Int16 SAL_CALL ORowSetBase::getShort( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getInt16();
+}
+
+sal_Int32 SAL_CALL ORowSetBase::getInt( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getInt32();
+}
+
+sal_Int64 SAL_CALL ORowSetBase::getLong( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getLong();
+}
+
+float SAL_CALL ORowSetBase::getFloat( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getFloat();
+}
+
+double SAL_CALL ORowSetBase::getDouble( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getDouble();
+}
+
+Sequence< sal_Int8 > SAL_CALL ORowSetBase::getBytes( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getSequence();
+}
+
+css::util::Date SAL_CALL ORowSetBase::getDate( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getDate();
+}
+
+css::util::Time SAL_CALL ORowSetBase::getTime( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getTime();
+}
+
+css::util::DateTime SAL_CALL ORowSetBase::getTimestamp( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getDateTime();
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSetBase::getBinaryStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::getBinaryStream: Illegal call here (we're before first or after last)!");
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_CURSOR_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+ }
+
+ if ( impl_rowDeleted() )
+ {
+ return nullptr;
+ }
+
+ bool bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ if ( !bValidCurrentRow )
+ {
+ positionCache( MOVE_NONE );
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"ORowSetBase::getBinaryStream: we don't stand on a valid row! Row is null.");
+
+ bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ }
+
+ if ( bValidCurrentRow )
+ {
+ m_nLastColumnIndex = columnIndex;
+ return new ::comphelper::SequenceInputStream((**m_aCurrentRow)[m_nLastColumnIndex].getSequence());
+ }
+
+ // we should normally never reach this
+ return Reference< css::io::XInputStream >();
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSetBase::getCharacterStream( sal_Int32 columnIndex )
+{
+ return getBinaryStream(columnIndex);
+}
+
+Any SAL_CALL ORowSetBase::getObject( sal_Int32 columnIndex, const Reference< XNameAccess >& /*typeMap*/ )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ return getValue(columnIndex).makeAny();
+}
+
+Reference< XRef > SAL_CALL ORowSetBase::getRef( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRef", *m_pMySelf );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL ORowSetBase::getBlob( sal_Int32 columnIndex )
+{
+ return Reference< XBlob >(getValue(columnIndex).makeAny(),UNO_QUERY);
+}
+
+Reference< XClob > SAL_CALL ORowSetBase::getClob( sal_Int32 columnIndex )
+{
+ return Reference< XClob >(getValue(columnIndex).makeAny(),UNO_QUERY);
+}
+
+Reference< XArray > SAL_CALL ORowSetBase::getArray( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getArray", *m_pMySelf );
+ return nullptr;
+}
+
+// css::sdbcx::XRowLocate
+Any SAL_CALL ORowSetBase::getBookmark( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::getBookmark() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_BOOKMARK_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+
+ if ( impl_rowDeleted() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_BOOKMARK_DELETED ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+
+ OSL_ENSURE( m_aBookmark.hasValue(), "ORowSetBase::getBookmark: bookmark has no value!" );
+ return m_aBookmark;
+}
+
+sal_Bool SAL_CALL ORowSetBase::moveToBookmark( const Any& bookmark )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::moveToBookmark(Any) Clone = " << m_bClone);
+ OSL_ENSURE(bookmark.hasValue(),"ORowSetBase::moveToBookmark bookmark has no value!");
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ if(!bookmark.hasValue() || m_nResultSetType == ResultSetType::FORWARD_ONLY)
+ {
+ if(bookmark.hasValue())
+ SAL_WARN("dbaccess", "MoveToBookmark is not possible when we are only forward");
+ else
+ SAL_WARN("dbaccess", "Bookmark is not valid");
+ throwFunctionSequenceException(*m_pMySelf);
+ }
+
+ checkCache();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bRet = m_pCache->moveToBookmark(bookmark);
+ doCancelModification( );
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ {
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::moveToBookmark(Any) = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::moveRelativeToBookmark(Any," << rows << ") Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ checkPositioningAllowed();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bRet = m_pCache->moveRelativeToBookmark(bookmark,rows);
+ doCancelModification( );
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ movementFailed();
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+
+ // RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::moveRelativeToBookmark(Any," << rows << ") = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Int32 SAL_CALL ORowSetBase::compareBookmarks( const Any& _first, const Any& _second )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return m_pCache->compareBookmarks(_first,_second);
+}
+
+sal_Bool SAL_CALL ORowSetBase::hasOrderedBookmarks( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return m_pCache->hasOrderedBookmarks();
+}
+
+sal_Int32 SAL_CALL ORowSetBase::hashBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return m_pCache->hashBookmark(bookmark);
+}
+
+// XResultSetMetaDataSupplier
+Reference< XResultSetMetaData > SAL_CALL ORowSetBase::getMetaData( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ Reference< XResultSetMetaData > xMeta;
+ if(m_pCache)
+ xMeta = m_pCache->getMetaData();
+
+ return xMeta;
+}
+
+// XColumnLocate
+sal_Int32 SAL_CALL ORowSetBase::findColumn( const OUString& columnName )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ // it is possible to save some time here when we remember the names - position relation in a map
+ return m_pColumns ? m_pColumns->findColumn(columnName) : sal_Int32(0);
+}
+
+// css::sdbcx::XColumnsSupplier
+Reference< XNameAccess > SAL_CALL ORowSetBase::getColumns( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ if(!m_pColumns)
+ {
+ if (!m_pEmptyCollection)
+ m_pEmptyCollection.reset( new OEmptyCollection(*m_pMySelf,m_aColumnsMutex) );
+ return m_pEmptyCollection.get();
+ }
+
+ return m_pColumns.get();
+}
+
+// XResultSet
+sal_Bool SAL_CALL ORowSetBase::next( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::next() Clone = " << m_bClone);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ positionCache( MOVE_FORWARD );
+ bool bAfterLast = m_pCache->isAfterLast();
+ bRet = m_pCache->next();
+ doCancelModification( );
+
+ // if we were afterLast before next() then we still are,
+ // i.e. bAfterLast implies m_pCache->isAfterLast()
+ if (bAfterLast)
+ assert(m_pCache->isAfterLast());
+ // so the only way bAfterLast != m_pCache->isAfterLast()
+ // would be that we just arrived there,
+ if (bAfterLast != m_pCache->isAfterLast())
+ {
+ assert(!bAfterLast);
+ assert(m_pCache->isAfterLast());
+ }
+ // in which case we *did* move the cursor
+ if ( bRet || bAfterLast != m_pCache->isAfterLast() )
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ OSL_ENSURE(!m_bBeforeFirst,"BeforeFirst is true. I don't know why?");
+ }
+ else
+ {
+ // moved after the last row
+ movementFailed();
+ OSL_ENSURE(m_bAfterLast,"AfterLast is false. I don't know why?");
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::next() = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::isBeforeFirst( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ SAL_INFO("dbaccess", "ORowSetBase::isBeforeFirst() = " << m_bBeforeFirst << " Clone = " << m_bClone);
+
+ return m_bBeforeFirst;
+}
+
+sal_Bool SAL_CALL ORowSetBase::isAfterLast( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ SAL_INFO("dbaccess", "ORowSetBase::isAfterLast() = " << m_bAfterLast << " Clone = " << m_bClone);
+
+ return m_bAfterLast;
+}
+
+bool ORowSetBase::isOnFirst()
+{
+ return isFirst();
+}
+
+sal_Bool SAL_CALL ORowSetBase::isFirst( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::isFirst() Clone = " << m_bClone);
+
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ return false;
+
+ if ( impl_rowDeleted() )
+ return ( m_nDeletedPosition == 1 );
+
+ positionCache( MOVE_NONE );
+ bool bIsFirst = m_pCache->isFirst();
+
+ SAL_INFO("dbaccess", "ORowSetBase::isFirst() = " << bIsFirst << " Clone = " << m_bClone);
+ return bIsFirst;
+}
+
+bool ORowSetBase::isOnLast()
+{
+ return isLast();
+}
+
+sal_Bool SAL_CALL ORowSetBase::isLast( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::isLast() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ return false;
+
+ if ( impl_rowDeleted() )
+ {
+ if ( !m_pCache->m_bRowCountFinal )
+ return false;
+ else
+ return ( m_nDeletedPosition == impl_getRowCount() );
+ }
+
+ positionCache( MOVE_NONE );
+ bool bIsLast = m_pCache->isLast();
+
+ SAL_INFO("dbaccess", "ORowSetBase::isLast() = " << bIsLast << " Clone = " << m_bClone);
+ return bIsLast;
+}
+
+void SAL_CALL ORowSetBase::beforeFirst( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::beforeFirst() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ checkPositioningAllowed();
+
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ if((bWasNew || !m_bBeforeFirst) && notifyAllListenersCursorBeforeMove(aGuard) )
+ {
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ if ( !m_bBeforeFirst )
+ {
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+ m_pCache->beforeFirst();
+ doCancelModification( );
+
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+
+ // - IsModified
+ // - Isnew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+
+ // to be done _after_ the notifications!
+ m_aOldRow->clearRow();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::beforeFirst() Clone = " << m_bClone);
+}
+
+void SAL_CALL ORowSetBase::afterLast( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::afterLast() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ if((bWasNew || !m_bAfterLast) && notifyAllListenersCursorBeforeMove(aGuard) )
+ {
+ // check if we are inserting a row
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ if(!m_bAfterLast)
+ {
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ m_pCache->afterLast();
+ doCancelModification( );
+
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+
+ // - IsModified
+ // - Isnew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::afterLast() Clone = " << m_bClone);
+}
+
+bool SAL_CALL ORowSetBase::move(std::function<bool(ORowSetBase *)> const & _aCheckFunctor,
+ std::function<bool(ORowSetCache *)> const & _aMovementFunctor)
+{
+ SAL_INFO("dbaccess", "ORowSetBase::move() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bool bMoved = ( bWasNew || !_aCheckFunctor(this) );
+
+ bRet = _aMovementFunctor(m_pCache.get());
+ doCancelModification( );
+
+ if ( bRet )
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( bMoved, true, aOldValues, aGuard );
+ }
+ else
+ { // first goes wrong so there is no row
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::move() = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::first( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::first() Clone = " << m_bClone);
+ auto ioF_tmp = std::mem_fn(&ORowSetBase::isOnFirst);
+ auto F_tmp = std::mem_fn(&ORowSetCache::first);
+ return move(ioF_tmp,F_tmp);
+}
+
+sal_Bool SAL_CALL ORowSetBase::last( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::last() Clone = " << m_bClone);
+ auto ioL_tmp = std::mem_fn(&ORowSetBase::isOnLast);
+ auto L_tmp = std::mem_fn(&ORowSetCache::last);
+ return move(ioL_tmp,L_tmp);
+}
+
+sal_Int32 SAL_CALL ORowSetBase::getRow( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::getRow() Clone = " << m_bClone);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ checkCache();
+ return impl_getRow();
+}
+
+sal_Int32 ORowSetBase::impl_getRow()
+{
+ sal_Int32 nPos = 0;
+ if ( m_bBeforeFirst )
+ nPos = 0;
+ else if ( m_bAfterLast )
+ nPos = impl_getRowCount() + 1;
+ else if ( impl_rowDeleted() )
+ nPos = m_nDeletedPosition;
+ else if ( !m_bClone && m_pCache->m_bNew )
+ nPos = 0;
+ else
+ {
+ positionCache( MOVE_NONE );
+ nPos = m_pCache->getRow();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::impl_getRow() = " << nPos << " Clone = " << m_bClone);
+ return nPos;
+}
+
+sal_Bool SAL_CALL ORowSetBase::absolute( sal_Int32 row )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::absolute(" << row << ") Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ bool bRet = ( row > 0 )
+ && notifyAllListenersCursorBeforeMove( aGuard );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bRet = m_pCache->absolute(row);
+ doCancelModification( );
+
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ { // absolute movement goes wrong we stand left or right side of the rows
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::absolute(" << row << ") = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::relative( sal_Int32 rows )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::relative(" << rows << ") Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ if(!rows)
+ return true; // in this case do nothing
+
+ checkPositioningAllowed();
+
+ bool bRet =
+ ( ( !m_bAfterLast || rows <= 0 )
+ && ( !m_bBeforeFirst || rows >= 0 )
+ && notifyAllListenersCursorBeforeMove( aGuard )
+ );
+
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ positionCache( rows > 0 ? MOVE_FORWARD : MOVE_BACKWARD );
+ bRet = m_pCache->relative(rows);
+ doCancelModification( );
+
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ {
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::relative(" << rows << ") = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::previous( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::previous() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ checkPositioningAllowed();
+
+ bool bRet = !m_bBeforeFirst
+ && notifyAllListenersCursorBeforeMove(aGuard);
+
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ positionCache( MOVE_BACKWARD );
+ bRet = m_pCache->previous();
+ doCancelModification( );
+
+ // if m_bBeforeFirst is false and bRet is false then we stood on the first row
+ if(!m_bBeforeFirst || bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::previous: inconsistency!" );
+ // we should never reach this place, as we should not get into this whole branch if m_bBeforeFirst
+ // was |true| from the beginning
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::previous() = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+void ORowSetBase::setCurrentRow( bool _bMoved, bool _bDoNotify, const ORowSetRow& _rOldValues, ::osl::ResettableMutexGuard& _rGuard )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::setCurrentRow() Clone = " << m_bClone);
+ m_bBeforeFirst = m_pCache->isBeforeFirst();
+ m_bAfterLast = m_pCache->isAfterLast();
+
+ if(!(m_bBeforeFirst || m_bAfterLast))
+ {
+ m_aBookmark = m_pCache->getBookmark();
+ OSL_ENSURE(m_aBookmark.hasValue(),"Bookmark has no value!");
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"CurrentRow is null!");
+ OSL_ENSURE(!m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd(),"Position of matrix iterator isn't valid!");
+ OSL_ENSURE(m_aCurrentRow->is(),"Currentrow isn't valid");
+ OSL_ENSURE(m_aBookmark.hasValue(),"Bookmark has no value!");
+
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"CurrentRow is nul after positionCache!");
+#if OSL_DEBUG_LEVEL > 0
+ ORowSetRow rRow = *m_aCurrentRow;
+ OSL_ENSURE(rRow.is() ,"Invalid size of vector!");
+#endif
+
+ // notification order
+ // - column values
+ if ( _bDoNotify )
+ firePropertyChange(_rOldValues);
+
+ }
+ else
+ {
+ m_aOldRow->clearRow();
+ m_aCurrentRow = m_pCache->getEnd();
+ m_aBookmark = Any();
+ }
+
+ // TODO: can this be done before the notifications?
+ if(!(m_bBeforeFirst || m_bAfterLast) && !m_aCurrentRow.isNull() && m_aCurrentRow->is() && m_aCurrentRow != m_pCache->getEnd())
+ m_aOldRow->setRow(new ORowSetValueVector( *(*m_aCurrentRow) ));
+
+ if ( _bMoved && _bDoNotify )
+ // - cursorMoved
+ notifyAllListenersCursorMoved( _rGuard );
+
+ SAL_INFO("dbaccess", "ORowSetBase::setCurrentRow() Clone = " << m_bClone);
+}
+
+void ORowSetBase::checkPositioningAllowed()
+{
+ if(!m_pCache || m_nResultSetType == ResultSetType::FORWARD_ONLY)
+ throwFunctionSequenceException(*m_pMySelf);
+}
+
+Reference< XInterface > ORowSetBase::getStatement()
+{
+ return nullptr;
+}
+
+void SAL_CALL ORowSetBase::refreshRow( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ if ( impl_rowDeleted() )
+ throwSQLException( "The current row is deleted", StandardSQLState::INVALID_CURSOR_STATE, Reference< XRowSet >( this ) );
+
+ if(!(m_bBeforeFirst || m_bAfterLast))
+ {
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+ positionCache( MOVE_NONE );
+ m_pCache->refreshRow();
+ firePropertyChange(aOldValues);
+ }
+}
+
+sal_Bool SAL_CALL ORowSetBase::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( impl_rowDeleted() )
+ return false;
+
+ return m_pCache->rowUpdated();
+}
+
+sal_Bool SAL_CALL ORowSetBase::rowInserted( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ checkCache();
+
+ if ( impl_rowDeleted() )
+ return false;
+
+ return m_pCache->rowInserted();
+}
+
+sal_Bool SAL_CALL ORowSetBase::rowDeleted( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return impl_rowDeleted();
+}
+
+bool ORowSetBase::impl_rowDeleted( )
+{
+ return !m_aBookmark.hasValue() && !m_bBeforeFirst && !m_bAfterLast;
+}
+
+// XWarningsSupplier
+Any SAL_CALL ORowSetBase::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ if ( m_pCache )
+ {
+ Reference< XWarningsSupplier > xWarnings( m_pCache->m_xSet.get(), UNO_QUERY );
+ if ( xWarnings.is() )
+ return xWarnings->getWarnings();
+ }
+
+ return Any();
+}
+
+void SAL_CALL ORowSetBase::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ if ( m_pCache )
+ {
+ Reference< XWarningsSupplier > xWarnings( m_pCache->m_xSet.get(), UNO_QUERY );
+ if ( xWarnings.is() )
+ xWarnings->clearWarnings();
+ }
+}
+
+void ORowSetBase::firePropertyChange(const ORowSetRow& _rOldRow)
+{
+ if (!isPropertyChangeNotificationEnabled())
+ return;
+
+ SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange" );
+ SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange() Clone = " << m_bClone);
+ OSL_ENSURE(m_pColumns,"Columns can not be NULL here!");
+ sal_Int32 i=0;
+ for (auto const& dataColumn : m_aDataColumns)
+ {
+ try
+ {
+ dataColumn->fireValueChange(_rOldRow.is() ? (*_rOldRow)[i+1] : ::connectivity::ORowSetValue());
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "firePropertyChange: Exception on column " << i);
+ }
+ ++i;
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange() Clone = " << m_bClone);
+}
+
+void ORowSetBase::firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rOldValue)
+{
+ OSL_ENSURE(_nPos < static_cast<sal_Int32>(m_aDataColumns.size()),"nPos is invalid!");
+ m_aDataColumns[_nPos]->fireValueChange(_rOldValue);
+}
+
+void ORowSetBase::fireRowcount()
+{
+}
+
+bool ORowSetBase::notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& /*_rGuard*/)
+{
+ return true;
+}
+
+void ORowSetBase::notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& /*_rGuard*/)
+{
+}
+
+bool ORowSetBase::isPropertyChangeNotificationEnabled() const
+{
+ return true;
+}
+
+void ORowSetBase::fireProperty( sal_Int32 _nProperty, bool _bNew, bool _bOld )
+{
+ Any aNew( _bNew );
+ Any aOld( _bOld );
+ fire( &_nProperty, &aNew, &aOld, 1, false );
+}
+
+void ORowSetBase::positionCache( CursorMoveDirection _ePrepareForDirection )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::positionCache() Clone = " << m_bClone);
+
+ bool bSuccess = false;
+ if ( m_aBookmark.hasValue() )
+ {
+ if (_ePrepareForDirection == MOVE_NONE_REFRESH ||
+ (m_pCache->isAfterLast() != bool(isAfterLast())) || ( m_pCache->isBeforeFirst() != bool(isBeforeFirst()) ) ||
+ m_pCache->compareBookmarks( m_aBookmark, m_pCache->getBookmark() ) != CompareBookmark::EQUAL )
+ bSuccess = m_pCache->moveToBookmark( m_aBookmark );
+ else
+ bSuccess = true;
+ }
+ else
+ {
+ if ( m_bBeforeFirst )
+ {
+ m_pCache->beforeFirst();
+ bSuccess = true;
+ }
+ else if ( m_bAfterLast )
+ {
+ m_pCache->afterLast();
+ bSuccess = true;
+ }
+ else
+ {
+ OSL_ENSURE( m_nDeletedPosition >= 1, "ORowSetBase::positionCache: no bookmark, and no valid 'deleted position'!" );
+ switch ( _ePrepareForDirection )
+ {
+ case MOVE_FORWARD:
+ if ( m_nDeletedPosition > 1 )
+ bSuccess = m_pCache->absolute( m_nDeletedPosition - 1 );
+ else
+ {
+ m_pCache->beforeFirst();
+ bSuccess = true;
+ }
+ break;
+
+ case MOVE_BACKWARD:
+ if ( m_pCache->m_bRowCountFinal && ( m_nDeletedPosition == impl_getRowCount() ) )
+ {
+ m_pCache->afterLast();
+ bSuccess = true;
+ }
+ else
+ bSuccess = m_pCache->absolute( m_nDeletedPosition );
+ break;
+
+ case MOVE_NONE:
+ case MOVE_NONE_REFRESH:
+ bSuccess = false; // will be asserted below
+ break;
+ }
+ }
+ }
+ OSL_ENSURE( bSuccess, "ORowSetBase::positionCache: failed!" );
+
+ SAL_INFO("dbaccess", "ORowSetBase::positionCache() Clone = " << m_bClone);
+}
+
+void ORowSetBase::checkCache()
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ if(!m_pCache)
+ throwFunctionSequenceException(*m_pMySelf);
+}
+
+void ORowSetBase::movementFailed()
+{
+ SAL_INFO("dbaccess", "ORowSetBase::movementFailed() Clone = " << m_bClone);
+ m_aOldRow->clearRow();
+ m_aCurrentRow = m_pCache->getEnd();
+ m_bBeforeFirst = m_pCache->isBeforeFirst();
+ m_bAfterLast = m_pCache->isAfterLast();
+ m_aBookmark = Any();
+ OSL_ENSURE(m_bBeforeFirst || m_bAfterLast,"BeforeFirst or AfterLast is wrong!");
+ SAL_INFO("dbaccess", "ORowSetBase::movementFailed() Clone = " << m_bClone);
+}
+
+ORowSetRow ORowSetBase::getOldRow(bool _bWasNew)
+{
+ OSL_ENSURE(m_aOldRow.is(),"RowSetRowHElper isn't valid!");
+ ORowSetRow aOldValues;
+ if ( !_bWasNew && m_aOldRow->getRow().is() )
+ aOldValues = new ORowSetValueVector( *(m_aOldRow->getRow())); // remember the old values
+ return aOldValues;
+}
+
+void ORowSetBase::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const
+{
+ _rDefault.clear();
+}
+
+void ORowSetBase::onDeleteRow( const Any& _rBookmark )
+{
+ if ( rowDeleted() )
+ // not interested in
+ return;
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ //OSL_ENSURE( m_aBookmark.hasValue(), "ORowSetBase::onDeleteRow: Bookmark isn't valid!" );
+ if ( compareBookmarks( _rBookmark, m_aBookmark ) == CompareBookmark::EQUAL )
+ {
+ positionCache( MOVE_NONE );
+ m_nDeletedPosition = m_pCache->getRow();
+ }
+}
+
+void ORowSetBase::onDeletedRow( const Any& _rBookmark, sal_Int32 _nPos )
+{
+ if ( rowDeleted() )
+ {
+ // if we're a clone, and on a deleted row, and the main RowSet deleted another
+ // row (only the main RowSet can, clones can't), which is *before* our
+ // deleted position, then we have to adjust this position
+ if ( m_bClone && ( _nPos < m_nDeletedPosition ) )
+ --m_nDeletedPosition;
+ return;
+ }
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if ( compareBookmarks( _rBookmark, m_aBookmark ) == CompareBookmark::EQUAL )
+ {
+ m_aOldRow->clearRow();
+ m_aCurrentRow = m_pCache->getEnd();
+ m_aBookmark = Any();
+ }
+}
+
+sal_Int32 ORowSetBase::impl_getRowCount() const
+{
+ sal_Int32 nRowCount( m_pCache->m_nRowCount );
+ if ( const_cast< ORowSetBase* >( this )->rowDeleted() && !m_pCache->m_bNew )
+ ++nRowCount;
+ return nRowCount;
+}
+
+struct ORowSetNotifierImpl
+{
+ std::vector<sal_Int32> aChangedColumns;
+ ORowSetValueVector::Vector aRow;
+};
+
+
+ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet )
+ :m_pRowSet( _pRowSet )
+ ,m_bWasNew( false )
+ ,m_bWasModified( false )
+{
+
+ OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This will crash." );
+
+ // remember the "inserted" and "modified" state for later firing
+ m_bWasNew = m_pRowSet->isNew( ORowSetBase::GrantNotifierAccess() );
+ m_bWasModified = m_pRowSet->isModified( ORowSetBase::GrantNotifierAccess() );
+
+ // if the row set is on the insert row, then we need to cancel this
+ if ( m_pRowSet->isModification( ORowSetBase::GrantNotifierAccess() ) )
+ m_pRowSet->doCancelModification( ORowSetBase::GrantNotifierAccess() );
+}
+
+ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet, ORowSetValueVector::Vector&& i_aRow )
+ :m_pImpl(new ORowSetNotifierImpl)
+ ,m_pRowSet( _pRowSet )
+ ,m_bWasNew( false )
+ ,m_bWasModified( false )
+{
+
+ OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This will crash." );
+ m_pImpl->aRow = std::move(i_aRow); // yes, create a copy to store the old values
+}
+
+ORowSetNotifier::~ORowSetNotifier( )
+{
+}
+
+void ORowSetNotifier::fire()
+{
+ // we're not interested in firing changes FALSE->TRUE, only TRUE->FALSE.
+ // (the former would be quite pathological, e.g. after a failed movement)
+
+ if ( m_bWasModified
+ && ( m_bWasModified != m_pRowSet->isModified( ORowSetBase::GrantNotifierAccess() ) )
+ )
+ m_pRowSet->fireProperty( PROPERTY_ID_ISMODIFIED, false, true, ORowSetBase::GrantNotifierAccess() );
+
+ if ( m_bWasNew
+ && ( m_bWasNew != m_pRowSet->isNew( ORowSetBase::GrantNotifierAccess() ) )
+ )
+ m_pRowSet->fireProperty( PROPERTY_ID_ISNEW, false, true, ORowSetBase::GrantNotifierAccess() );
+}
+
+std::vector<sal_Int32>& ORowSetNotifier::getChangedColumns() const
+{
+ OSL_ENSURE(m_pImpl, "Illegal CTor call, use the other one!");
+ return m_pImpl->aChangedColumns;
+}
+
+void ORowSetNotifier::firePropertyChange()
+{
+ OSL_ENSURE(m_pImpl, "Illegal CTor call, use the other one!");
+ if (m_pImpl)
+ {
+ for (auto const& changedColumn : m_pImpl->aChangedColumns)
+ {
+ m_pRowSet->firePropertyChange(changedColumn-1 ,m_pImpl->aRow[changedColumn-1], ORowSetBase::GrantNotifierAccess());
+ }
+ if ( !m_pImpl->aChangedColumns.empty() )
+ m_pRowSet->fireProperty(PROPERTY_ID_ISMODIFIED,true,false, ORowSetBase::GrantNotifierAccess());
+ }
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetBase.hxx b/dbaccess/source/core/api/RowSetBase.hxx
new file mode 100644
index 000000000..f5443a2af
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetBase.hxx
@@ -0,0 +1,402 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include <cppuhelper/implbase10.hxx>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <cppuhelper/interfacecontainer.h>
+#include <connectivity/sqlerror.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/propertystatecontainer.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include "RowSetRow.hxx"
+#include "RowSetCacheIterator.hxx"
+
+#include <functional>
+
+namespace com::sun::star {
+ namespace sdb { struct RowChangeEvent; }
+ namespace lang { struct Locale; }
+}
+
+namespace dbaccess
+{
+ class OEmptyCollection;
+
+ typedef ::cppu::ImplHelper10< css::sdbcx::XRowLocate,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XColumnLocate,
+ css::sdbcx::XColumnsSupplier,
+ css::lang::XServiceInfo,
+ css::sdbc::XRowSet,
+ css::sdbc::XCloseable,
+ css::lang::XUnoTunnel> ORowSetBase_BASE;
+
+ class ORowSetCache;
+ class ORowSetDataColumns;
+ class ORowSetCacheIterator;
+ class ORowSetDataColumn;
+ class ORowSetBase : public ORowSetBase_BASE,
+ public ::comphelper::OPropertyStateContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<ORowSetBase> // this class hold the static property info
+ {
+ protected:
+ typedef std::vector<ORowSetDataColumn*> TDataColumns;
+ ::osl::Mutex* m_pMutex; // this is the mutex from the rowset itself
+ ::osl::Mutex // we need an extra mutex for columns to prevent deadlock when setting new values
+ // for a row
+ m_aColumnsMutex;
+
+ css::uno::Any m_aBookmark;
+ ORowSetCacheIterator m_aCurrentRow; // contains the actual fetched row
+ TORowSetOldRowHelperRef m_aOldRow;
+ TDataColumns m_aDataColumns; // holds the columns as m_pColumns but know the implementation class
+ connectivity::ORowSetValue m_aEmptyValue; // only for error case
+
+ ::cppu::OWeakObject* m_pMySelf; // set by derived classes
+ std::shared_ptr<ORowSetCache> m_pCache; // the cache is used by the rowset and his clone (shared)
+ std::unique_ptr<ORowSetDataColumns> m_pColumns; // represent the select columns
+ ::cppu::OBroadcastHelper& m_rBHelper; // must be set from the derived classes
+ // is used when the formatkey for database types is set
+ css::uno::Reference< css::util::XNumberFormatTypes> m_xNumberFormatTypes;
+ std::unique_ptr<OEmptyCollection> m_pEmptyCollection;
+
+ css::uno::Reference< css::uno::XComponentContext> m_aContext;
+ ::connectivity::SQLError m_aErrors;
+
+ sal_Int32 m_nLastColumnIndex; // the last column ask for, used for wasNull()
+ sal_Int32 m_nDeletedPosition; // is set only when a row was deleted
+ sal_Int32 m_nResultSetType; // fetch property
+ sal_Int32 m_nResultSetConcurrency;
+ bool m_bClone; // I'm clone or not
+ bool m_bIgnoreResult ;
+ bool m_bBeforeFirst : 1;
+ bool m_bAfterLast : 1;
+ bool m_bIsInsertRow : 1;
+
+ protected:
+ ORowSetBase(
+ const css::uno::Reference<css::uno::XComponentContext>& _rContext,
+ ::cppu::OBroadcastHelper& _rBHelper,
+ ::osl::Mutex* _pMutex
+ );
+
+ // fire a notification for all that are listening on column::VALUE property
+ void firePropertyChange(const ORowSetRow& _rOldRow);
+ // fire a change for one column
+ // _nPos starts at zero
+ void firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rNewValue);
+
+ // fire if rowcount changed
+ virtual void fireRowcount();
+ // notify row changed
+ virtual bool notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard);
+ // notify cursor moved
+ virtual void notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard);
+
+ // cancel the insertion, if necessary (means if we're on the insert row)
+ virtual void doCancelModification( ) = 0;
+ // return <TRUE/> if and only if we're using the insert row (means: we're updating _or_ inserting)
+ virtual bool isModification( ) = 0;
+ // return <TRUE/> if and only if the current row is modified
+ // TODO: isn't this the same as isModification?
+ virtual bool isModified( ) = 0;
+ // return <TRUE/> if and only if the current row is the insert row
+ virtual bool isNew( ) = 0;
+ // return <TRUE/> if the property change notification should be fired
+ // upon property change.
+ virtual bool isPropertyChangeNotificationEnabled() const;
+ // notify the change of a boolean property
+ void fireProperty( sal_Int32 _nProperty, bool _bNew, bool _bOld );
+
+ // OPropertyStateContainer
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue,sal_Int32 nHandle) const override;
+
+ enum CursorMoveDirection
+ {
+ /// denotes a cursor move forward
+ MOVE_FORWARD,
+ /// denotes a cursor move backwards
+ MOVE_BACKWARD,
+ /// denotes no cursor move at all, but move cache to current row (if it is not there already)
+ MOVE_NONE,
+ /// denotes no cursor move at all, but force the cache to move to current row (and refresh the row)
+ MOVE_NONE_REFRESH
+ };
+ /** positions the cache in preparation of a cursor move
+
+ Normally, the cache is simply moved to our bookmark (m_aBookmark). If however the current
+ row is deleted, then the cache is properly positioned for a following cursor movement in the
+ given direction.
+
+ @param _ePrepareForDirection
+ the direction into which the cursor should be moved after the call. If we're currently not on
+ a deleted row, this parameter is ignored, since in this case the cache is simply moved to
+ m_aBookmark.</br>
+ If, however, we're currently on a deleted row, this is used to properly position the cache
+ using <member>m_nDeletedPosition</member>.<br/>
+ In this case, MOVE_NONE(_REFRESH) is not supported. This is because the deleted row
+ (to which the RowSet currently points to) is not present in the cache. So, you cannot move the
+ cache to this row.
+ */
+ void positionCache( CursorMoveDirection _ePrepareForDirection );
+
+ // returns a value of a column of the current row
+ const connectivity::ORowSetValue& getValue(sal_Int32 columnIndex);
+ // the cache has to be checked before calling this method
+ const connectivity::ORowSetValue& impl_getValue(sal_Int32 columnIndex);
+ // sets the current and the bookmark
+ void setCurrentRow( bool _bMoved, bool _bDoNotify, const ORowSetRow& _rOldValues, ::osl::ResettableMutexGuard& _rGuard);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkPositioningAllowed();
+ // checks if the cache is null
+ void checkCache();
+ // sets the bookmark to Any()
+ // m_aCurrentRow to end of matrix
+ // m_aOldRow to NULL
+ void movementFailed();
+
+ ORowSetRow getOldRow(bool _bWasNew);
+ /** move the cache the position defined by the member functor
+ @param _aCheckFunctor
+ Return <TRUE/> when we already stand on the row we want to.
+ @param _aMovementFunctor
+ The method used to move.
+ @return
+ <TRUE/> if movement was successful.
+ */
+ bool SAL_CALL move( std::function<bool(ORowSetBase *)> const & _aCheckFunctor,
+ std::function<bool(ORowSetCache *)> const & _aMovementFunctor);
+
+ /** same meaning as isFirst. Only need by mem_fun
+ @return
+ <TRUE/> if so.
+ */
+ bool isOnFirst();
+ /** same meaning as isLast. Only need by mem_fun
+ @return
+ <TRUE/> if so.
+ */
+ bool isOnLast();
+
+ /** returns the current row count
+
+ This function takes into account that we might actually be positioned on a
+ deleted row, so that m_pCache->m_nRowCount does not really reflect the actual
+ count.
+
+ @precond
+ Our mutex is locked.
+ */
+ sal_Int32 impl_getRowCount() const;
+
+ // the checkCache has to be called before calling this methods
+ sal_Int32 impl_getRow();
+ bool impl_rowDeleted();
+
+ public:
+ virtual ~ORowSetBase() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing();
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override
+ {
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+ }
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+
+ // css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // css::sdbc::XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // css::sdbc::XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute( ) override = 0;
+ virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override = 0;
+ virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override = 0;
+
+ // is called when the rowset is going to delete this bookmark _rBookmark
+ void onDeleteRow( const css::uno::Any& _rBookmark );
+ // is called when the rowset has deleted this bookmark _rBookmark
+ void onDeletedRow( const css::uno::Any& _rBookmark, sal_Int32 _nPos );
+
+ // granular access control
+ struct GrantNotifierAccess { friend class ORowSetNotifier; private: GrantNotifierAccess () { } };
+
+ // cancel the insertion, if necessary (means if we're on the insert row)
+ void doCancelModification( const GrantNotifierAccess& ) { doCancelModification(); }
+ bool isModification( const GrantNotifierAccess& ) { return isModification(); }
+ bool isModified( const GrantNotifierAccess& ) { return isModified(); }
+ bool isNew( const GrantNotifierAccess& ) { return isNew(); }
+ bool isInsertRow() const { return m_bIsInsertRow; } // isNew() || isModified(); }
+ void fireProperty( sal_Int32 _nProperty, bool _bNew, bool _bOld, const GrantNotifierAccess& )
+ {
+ fireProperty( _nProperty, _bNew, _bOld );
+ }
+ void firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rNewValue, const GrantNotifierAccess& )
+ {
+ firePropertyChange(_nPos,_rNewValue);
+ }
+ using ::comphelper::OPropertyStateContainer::getFastPropertyValue;
+ };
+
+ /** eases the handling of the doCancelModification and notifyCancelInsert methods
+
+ <p>The class can only be used on the stack, within a method of ORowSetBase (or derivees)</p>
+ */
+ struct ORowSetNotifierImpl;
+ class ORowSetNotifier
+ {
+ private:
+ std::unique_ptr<ORowSetNotifierImpl> m_pImpl;
+ ORowSetBase* m_pRowSet;
+ // not acquired! This is not necessary because this class here is to be used on the stack within
+ // a method of ORowSetBase (or derivees)
+ bool m_bWasNew;
+ bool m_bWasModified;
+
+ public:
+ /** constructs the object, and cancels the insertion
+
+ @see ORowSetBase::doCancelModification
+ */
+ explicit ORowSetNotifier( ORowSetBase* m_pRowSet );
+
+ /** use this one to construct a vector for change value notification
+ */
+ ORowSetNotifier( ORowSetBase* m_pRowSet, ORowSetValueVector::Vector&& i_aRow );
+
+ // destructs the object. <member>fire</member> has to be called before.
+ ~ORowSetNotifier( );
+
+ /** notifies the insertion
+
+ <p>This has <em>not</em> been put into the destructor by intention!<br/>
+
+ The destructor is called during stack unwinding in case of an exception, so if we would do
+ listener notification there, this would have the potential of another exception during stack
+ unwinding, which would terminate the application.</p>
+
+ @see ORowSetBase::notifyCancelInsert
+ */
+ void fire();
+
+ /** notifies value change events and notifies IsModified
+ @param i_aChangedColumns the index of the changed value columns
+ @param i_aRow the old values
+ @see ORowSetBase::notifyCancelInsert
+ */
+ void firePropertyChange();
+
+ /** use this one to store the inde of the changed column values
+ */
+ std::vector<sal_Int32>& getChangedColumns() const;
+
+ };
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCache.cxx b/dbaccess/source/core/api/RowSetCache.cxx
new file mode 100644
index 000000000..8a23d6624
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCache.cxx
@@ -0,0 +1,1713 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "BookmarkSet.hxx"
+#include "KeySet.hxx"
+#include "OptimisticSet.hxx"
+#include "RowSetBase.hxx"
+#include "RowSetCache.hxx"
+#include "StaticSet.hxx"
+#include "WrappedResultSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <sqlbison.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+
+using namespace dbaccess;
+using namespace dbtools;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+
+// This class calls m_pCacheSet->FOO_checked(..., sal_False)
+// (where FOO is absolute, last, previous)
+// when it does not immediately care about the values in the row's columns.
+// As a corollary, m_pCacheSet may be left in an inconsistent state,
+// and all ->fillFOO calls (and ->getFOO) may fail or give wrong results,
+// until m_pCacheSet is moved (or refreshed) again.
+// So always make sure m_pCacheSet is moved or refreshed before accessing column values.
+
+
+ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs,
+ const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const Reference<XComponentContext>& _rContext,
+ const OUString& _rUpdateTableName,
+ bool& _bModified,
+ bool& _bNew,
+ const ORowSetValueVector& _aParameterValueForCache,
+ const OUString& i_sRowSetFilter,
+ sal_Int32 i_nMaxRows)
+ :m_xSet(_xRs)
+ ,m_xMetaData(Reference< XResultSetMetaDataSupplier >(_xRs,UNO_QUERY_THROW)->getMetaData())
+ ,m_aContext( _rContext )
+ ,m_nFetchSize(0)
+ ,m_nRowCount(0)
+ ,m_nPrivileges( Privilege::SELECT )
+ ,m_nPosition(0)
+ ,m_nStartPos(0)
+ ,m_nEndPos(0)
+ ,m_bRowCountFinal(false)
+ ,m_bBeforeFirst(true)
+ ,m_bAfterLast( false )
+ ,m_bModified(_bModified)
+ ,m_bNew(_bNew)
+{
+
+ // first try if the result can be used to do inserts and updates
+ Reference< XPropertySet> xProp(_xRs,UNO_QUERY);
+ Reference< XPropertySetInfo > xPropInfo = xProp->getPropertySetInfo();
+ bool bBookmarkable = false;
+ try
+ {
+ Reference< XResultSetUpdate> xUp(_xRs,UNO_QUERY_THROW);
+ bBookmarkable = xPropInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) &&
+ any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is();
+ if ( bBookmarkable )
+ {
+ xUp->moveToInsertRow();
+ xUp->cancelRowUpdates();
+ _xRs->beforeFirst();
+ m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
+ m_xCacheSet = new WrappedResultSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ return;
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess.core");
+ }
+ try
+ {
+ if ( xPropInfo->hasPropertyByName(PROPERTY_RESULTSETTYPE) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETTYPE)) != ResultSetType::FORWARD_ONLY)
+ _xRs->beforeFirst();
+ }
+ catch(const SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ }
+
+ // check if all keys of the updateable table are fetched
+ bool bAllKeysFound = false;
+ sal_Int32 nTablesCount = 0;
+
+ bool bNeedKeySet = !bBookmarkable || (xPropInfo->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY);
+
+ OUString aUpdateTableName = _rUpdateTableName;
+ Reference< XConnection> xConnection;
+ // first we need a connection
+ Reference< XStatement> xStmt(_xRs->getStatement(),UNO_QUERY);
+ if(xStmt.is())
+ xConnection = xStmt->getConnection();
+ else
+ {
+ Reference< XPreparedStatement> xPrepStmt(_xRs->getStatement(),UNO_QUERY);
+ xConnection = xPrepStmt->getConnection();
+ }
+ OSL_ENSURE(xConnection.is(),"No connection!");
+ if(_xAnalyzer.is())
+ {
+ try
+ {
+ Reference<XTablesSupplier> xTabSup(_xAnalyzer,UNO_QUERY);
+ OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!");
+ Reference<XNameAccess> xTables = xTabSup->getTables();
+ Sequence< OUString> aTableNames = xTables->getElementNames();
+ if ( aTableNames.getLength() > 1 && _rUpdateTableName.isEmpty() && bNeedKeySet )
+ {// here we have a join or union and nobody told us which table to update, so we update them all
+ m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
+ rtl::Reference<OptimisticSet> pCursor = new OptimisticSet(m_aContext,xConnection,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
+ m_xCacheSet = pCursor;
+ try
+ {
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ if ( pCursor->isReadOnly() )
+ m_nPrivileges = Privilege::SELECT;
+ m_aKeyColumns = pCursor->getJoinedKeyColumns();
+ return;
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ }
+ m_xCacheSet.clear();
+ }
+ else
+ {
+ if(!_rUpdateTableName.isEmpty() && xTables->hasByName(_rUpdateTableName))
+ xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable;
+ else if(xTables->getElementNames().hasElements())
+ {
+ aUpdateTableName = xTables->getElementNames()[0];
+ xTables->getByName(aUpdateTableName) >>= m_aUpdateTable;
+ }
+ Reference<XIndexAccess> xIndexAccess(xTables,UNO_QUERY);
+ if(xIndexAccess.is())
+ nTablesCount = xIndexAccess->getCount();
+ else
+ nTablesCount = xTables->getElementNames().getLength();
+
+ if(m_aUpdateTable.is() && nTablesCount < 3) // for we can't handle more than 2 tables in our keyset
+ {
+ Reference<XPropertySet> xSet(m_aUpdateTable,UNO_QUERY);
+ const Reference<XNameAccess> xPrimaryKeyColumns = dbtools::getPrimaryKeyColumns_throw(xSet);
+ if ( xPrimaryKeyColumns.is() )
+ {
+ Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
+ if ( xColSup.is() )
+ {
+ Reference<XNameAccess> xSelColumns = xColSup->getColumns();
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+ ::dbaccess::getColumnPositions(xSelColumns,xPrimaryKeyColumns->getElementNames(),aUpdateTableName,aColumnNames);
+ bAllKeysFound = !aColumnNames.empty() && aColumnNames.size() == o3tl::make_unsigned(xPrimaryKeyColumns->getElementNames().getLength());
+ }
+ }
+ }
+ }
+ }
+ catch (Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ }
+ }
+
+ // first check if resultset is bookmarkable
+ if(!bNeedKeySet)
+ {
+ try
+ {
+ m_xCacheSet = new OBookmarkSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+
+ // check privileges
+ m_nPrivileges = Privilege::SELECT;
+ if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
+ {
+ Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
+ if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
+ {
+ m_nPrivileges = 0;
+ xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ if(!m_nPrivileges)
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+ }
+ catch (const SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ bNeedKeySet = true;
+ }
+
+ }
+ if(bNeedKeySet)
+ {
+ // need to check if we could handle this select clause
+ bAllKeysFound = bAllKeysFound && (nTablesCount == 1 || checkJoin(xConnection,_xAnalyzer,aUpdateTableName));
+
+ if(!bAllKeysFound )
+ {
+ if ( bBookmarkable )
+ {
+ // here I know that we have a read only bookmarkable cursor
+ _xRs->beforeFirst();
+ m_nPrivileges = Privilege::SELECT;
+ m_xCacheSet = new WrappedResultSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ return;
+ }
+ m_xCacheSet = new OStaticSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ m_nPrivileges = Privilege::SELECT;
+ }
+ else
+ {
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+ Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
+ Reference<XNameAccess> xSelColumns = xColSup->getColumns();
+ Reference<XNameAccess> xColumns = m_aUpdateTable->getColumns();
+ ::dbaccess::getColumnPositions(xSelColumns,xColumns->getElementNames(),aUpdateTableName,aColumnNames);
+
+ // check privileges
+ m_nPrivileges = Privilege::SELECT;
+ bool bNoInsert = false;
+
+ Sequence< OUString> aNames(xColumns->getElementNames());
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"Column in table is null!");
+ if(xColumn.is())
+ {
+ sal_Int32 nNullable = 0;
+ xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
+ if(nNullable == ColumnValue::NO_NULLS && aColumnNames.find(*pIter) == aColumnNames.end())
+ { // we found a column where null is not allowed so we can't insert new values
+ bNoInsert = true;
+ break; // one column is enough
+ }
+ }
+ }
+
+ rtl::Reference<OKeySet> pKeySet = new OKeySet(m_aUpdateTable, aUpdateTableName ,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
+ try
+ {
+ m_xCacheSet = pKeySet;
+ pKeySet->construct(_xRs,i_sRowSetFilter);
+
+ if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
+ {
+ Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
+ if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
+ {
+ m_nPrivileges = 0;
+ xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ if(!m_nPrivileges)
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+ if(bNoInsert)
+ m_nPrivileges |= ~Privilege::INSERT; // remove the insert privilege
+ }
+ catch (const SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ // we couldn't create a keyset here so we have to create a static cache
+ m_xCacheSet = new OStaticSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+
+ }
+ // last check
+ if(!bAllKeysFound && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY)
+ m_nPrivileges = Privilege::SELECT;
+}
+
+ORowSetCache::~ORowSetCache()
+{
+ m_xCacheSet.clear();
+ if(m_pMatrix)
+ {
+ m_pMatrix->clear();
+ m_pMatrix.reset();
+ }
+
+ if(m_pInsertMatrix)
+ {
+ m_pInsertMatrix->clear();
+ m_pInsertMatrix.reset();
+ }
+ m_xSet = WeakReference< XResultSet>();
+ m_xMetaData = nullptr;
+ m_aUpdateTable = nullptr;
+}
+
+void ORowSetCache::setFetchSize(sal_Int32 _nSize)
+{
+ if(_nSize == m_nFetchSize)
+ return;
+
+ m_nFetchSize = _nSize;
+ if(!m_pMatrix)
+ {
+ m_pMatrix.reset( new ORowSetMatrix(_nSize) );
+ m_aMatrixIter = m_pMatrix->end();
+ m_aMatrixEnd = m_pMatrix->end();
+
+ m_pInsertMatrix.reset( new ORowSetMatrix(1) ); // a little bit overkill but ??? :-)
+ m_aInsertRow = m_pInsertMatrix->end();
+ }
+ else
+ {
+ // now correct the iterator in our iterator vector
+ std::vector<sal_Int32> aPositions;
+ std::map<sal_Int32,bool> aCacheIterToChange;
+ // first get the positions where they stand now
+ for(const auto& [rIndex, rHelper] : m_aCacheIterators)
+ {
+ aCacheIterToChange[rIndex] = false;
+ if ( !rHelper.pRowSet->isInsertRow()
+ /*&& rHelper.aIterator != m_pMatrix->end()*/ && !m_bModified )
+ {
+ ptrdiff_t nDist = rHelper.aIterator - m_pMatrix->begin();
+ aPositions.push_back(nDist);
+ aCacheIterToChange[rIndex] = true;
+ }
+ }
+ sal_Int32 nKeyPos = m_aMatrixIter - m_pMatrix->begin();
+ m_pMatrix->resize(_nSize);
+
+ if ( nKeyPos < _nSize )
+ m_aMatrixIter = m_pMatrix->begin() + nKeyPos;
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ m_aMatrixEnd = m_pMatrix->end();
+
+ // now adjust their positions because a resize invalidates all iterators
+ std::vector<sal_Int32>::const_iterator aIter = aPositions.begin();
+ ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
+ for(const auto& rPosChange : aCacheIterToChange)
+ {
+ if ( rPosChange.second )
+ {
+ OSL_ENSURE((*aIter >= static_cast<ORowSetMatrix::difference_type>(0)) && (*aIter < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!");
+ if ( *aIter < _nSize )
+ aCacheIter->second.aIterator = m_pMatrix->begin() + *aIter++;
+ else
+ aCacheIter->second.aIterator = m_pMatrix->end();
+ }
+ ++aCacheIter;
+ }
+ }
+ if(!m_nPosition)
+ {
+ sal_Int32 nNewSt = 0;
+ fillMatrix(nNewSt,_nSize);
+ OSL_ENSURE(nNewSt == 0, "fillMatrix set new start to unexpected value");
+ m_nStartPos = 0;
+ m_nEndPos = _nSize;
+ }
+ else if (m_nStartPos < m_nPosition && m_nPosition <= m_nEndPos)
+ {
+ sal_Int32 nNewSt = -1;
+ _nSize += m_nStartPos;
+ fillMatrix(nNewSt, _nSize);
+ if (nNewSt >= 0)
+ {
+ m_nStartPos = nNewSt;
+ m_nEndPos = _nSize;
+ m_aMatrixIter = calcPosition();
+ }
+ else
+ {
+ m_nEndPos = m_nStartPos + m_nFetchSize;
+ }
+ }
+ else
+ {
+ OSL_FAIL("m_nPosition not between m_nStartPos and m_nEndpos");
+ // try to repair
+ moveWindow();
+ m_aMatrixIter = calcPosition();
+ }
+}
+
+// XResultSetMetaDataSupplier
+
+static Any lcl_getBookmark(ORowSetValue& i_aValue,OCacheSet* i_pCacheSet)
+{
+ switch ( i_aValue.getTypeKind() )
+ {
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ return Any(i_aValue.getInt32());
+ default:
+ if ( i_pCacheSet && i_aValue.isNull())
+ i_aValue = i_pCacheSet->getBookmark();
+ return i_aValue.getAny();
+ }
+}
+
+// css::sdbcx::XRowLocate
+Any ORowSetCache::getBookmark( )
+{
+ if(m_bAfterLast)
+ throwFunctionSequenceException(m_xSet.get());
+
+ if ( m_aMatrixIter >= m_pMatrix->end() || m_aMatrixIter < m_pMatrix->begin() || !(*m_aMatrixIter).is())
+ {
+ return Any(); // this is allowed here because the rowset knows what it is doing
+ }
+
+ return lcl_getBookmark((**m_aMatrixIter)[0],m_xCacheSet.get());
+}
+
+bool ORowSetCache::moveToBookmark( const Any& bookmark )
+{
+ if ( m_xCacheSet->moveToBookmark(bookmark) )
+ {
+ m_bBeforeFirst = false;
+ m_nPosition = m_xCacheSet->getRow();
+
+ checkPositionFlags();
+
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+ checkPositionFlags();
+ if ( !m_bAfterLast )
+ {
+ m_aMatrixIter = calcPosition();
+ OSL_ENSURE(m_aMatrixIter->is(),"Iterator after moveToBookmark not valid");
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ return false;
+
+ return m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).is();
+}
+
+bool ORowSetCache::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ bool bRet( moveToBookmark( bookmark ) );
+ if ( bRet )
+ {
+ m_nPosition = m_xCacheSet->getRow() + rows;
+ absolute(m_nPosition);
+
+ bRet = m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).is();
+ }
+
+ return bRet;
+}
+
+sal_Int32 ORowSetCache::compareBookmarks( const Any& _first, const Any& _second )
+{
+ return (!_first.hasValue() || !_second.hasValue()) ? CompareBookmark::NOT_COMPARABLE : m_xCacheSet->compareBookmarks(_first,_second);
+}
+
+bool ORowSetCache::hasOrderedBookmarks( )
+{
+ return m_xCacheSet->hasOrderedBookmarks();
+}
+
+sal_Int32 ORowSetCache::hashBookmark( const Any& bookmark )
+{
+ return m_xCacheSet->hashBookmark(bookmark);
+}
+
+// XRowUpdate
+void ORowSetCache::updateNull(sal_Int32 columnIndex,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ if ( !rInsert[columnIndex].isNull() )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex].setNull();
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex].setNull();
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ if ( rInsert[columnIndex] != x )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = x;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x
+ , sal_Int32 length,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ Sequence<sal_Int8> aSeq;
+ if(x.is())
+ x->readBytes(aSeq,length);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = aSeq;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = Any(x);
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+}
+
+void ORowSetCache::updateObject( sal_Int32 columnIndex, const Any& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ ORowSetValue aTemp;
+ aTemp.fill(x);
+ if ( rInsert[columnIndex] != aTemp )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = aTemp;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+void ORowSetCache::updateNumericObject( sal_Int32 columnIndex, const Any& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ ORowSetValue aTemp;
+ aTemp.fill(x);
+ if ( rInsert[columnIndex] != aTemp )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = aTemp;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+// XResultSet
+bool ORowSetCache::next( )
+{
+ if(!isAfterLast())
+ {
+ m_bBeforeFirst = false;
+ ++m_nPosition;
+
+ // after we increment the position we have to check if we are already after the last row
+ checkPositionFlags();
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ checkPositionFlags();
+ }
+ }
+
+ return !m_bAfterLast;
+}
+
+
+bool ORowSetCache::isFirst( ) const
+{
+ return m_nPosition == 1; // ask resultset for
+}
+
+bool ORowSetCache::isLast( ) const
+{
+ return m_nPosition == m_nRowCount;
+}
+
+void ORowSetCache::beforeFirst( )
+{
+ if(!m_bBeforeFirst)
+ {
+ m_bAfterLast = false;
+ m_nPosition = 0;
+ m_bBeforeFirst = true;
+ m_xCacheSet->beforeFirst();
+ moveWindow();
+ m_aMatrixIter = m_pMatrix->end();
+ }
+}
+
+void ORowSetCache::afterLast( )
+{
+ if(m_bAfterLast)
+ return;
+
+ m_bBeforeFirst = false;
+ m_bAfterLast = true;
+
+ if(!m_bRowCountFinal)
+ {
+ m_xCacheSet->last();
+ m_bRowCountFinal = true;
+ m_nRowCount = m_xCacheSet->getRow();// + 1 removed
+ }
+ m_xCacheSet->afterLast();
+
+ m_nPosition = 0;
+ m_aMatrixIter = m_pMatrix->end();
+}
+
+bool ORowSetCache::fillMatrix(sal_Int32& _nNewStartPos, sal_Int32 &_nNewEndPos)
+{
+ OSL_ENSURE((_nNewStartPos != _nNewEndPos) || (_nNewStartPos == 0 && _nNewEndPos == 0 && m_nRowCount == 0),
+ "ORowSetCache::fillMatrix: StartPos and EndPos can not be equal (unless the recordset is empty)!");
+ // If _nNewStartPos >= 0, then fill the whole window with new data
+ // Else if _nNewStartPos == -1, then fill only segment [m_nEndPos, _nNewEndPos)
+ // Else, undefined (invalid argument)
+ OSL_ENSURE( _nNewStartPos >= -1, "ORowSetCache::fillMatrix: invalid _nNewStartPos" );
+
+ ORowSetMatrix::iterator aIter;
+ sal_Int32 i;
+ bool bCheck;
+ sal_Int32 requestedStartPos;
+ if ( _nNewStartPos == -1 )
+ {
+ aIter = m_pMatrix->begin() + (m_nEndPos - m_nStartPos);
+ i = m_nEndPos + 1;
+ requestedStartPos = m_nStartPos;
+ }
+ else
+ {
+ aIter = m_pMatrix->begin();
+ i = _nNewStartPos + 1;
+ requestedStartPos = _nNewStartPos;
+ }
+ bCheck = m_xCacheSet->absolute(i);
+
+
+ for(; i <= _nNewEndPos; ++i,++aIter)
+ {
+ if(bCheck)
+ {
+ if(!aIter->is())
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*aIter,i);
+ }
+ else
+ { // there are no more rows found so we can fetch some before start
+
+ if(!m_bRowCountFinal)
+ {
+ if(m_xCacheSet->previous()) // because we stand after the last row
+ m_nRowCount = m_xCacheSet->getRow(); // here we have the row count
+ if(!m_nRowCount)
+ m_nRowCount = i-1; // it can be that getRow return zero
+ m_bRowCountFinal = true;
+ }
+ const ORowSetMatrix::iterator aEnd = aIter;
+ ORowSetMatrix::const_iterator aRealEnd = m_pMatrix->end();
+ sal_Int32 nPos;
+ if (m_nRowCount >= m_nFetchSize)
+ {
+ nPos = m_nRowCount - m_nFetchSize;
+ }
+ else
+ {
+ nPos = 0;
+ }
+ _nNewStartPos = nPos;
+ _nNewEndPos = m_nRowCount;
+ ++nPos;
+ bCheck = m_xCacheSet->absolute(nPos);
+
+ for(;bCheck && nPos <= requestedStartPos && aIter != aRealEnd; ++aIter, ++nPos)
+ {
+ if(!aIter->is())
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*aIter, nPos);
+ bCheck = m_xCacheSet->next();
+ }
+ if(aIter != aEnd)
+ std::rotate(m_pMatrix->begin(),aEnd,aIter);
+ break;
+ }
+ bCheck = m_xCacheSet->next();
+ }
+ // we have to read one row forward to ensure that we know when we are on last row
+ // but only when we don't know it already
+ if(!m_bRowCountFinal)
+ {
+ if(!m_xCacheSet->next())
+ {
+ if(m_xCacheSet->previous()) // because we stand after the last row
+ m_nRowCount = m_xCacheSet->getRow(); // here we have the row count
+ m_bRowCountFinal = true;
+ }
+ else
+ m_nRowCount = std::max(i,m_nRowCount);
+
+ }
+ return bCheck;
+}
+
+// If m_nPosition is out of the current window,
+// move it and update m_nStartPos and m_nEndPos
+// Caller is responsible for updating m_aMatrixIter
+void ORowSetCache::moveWindow()
+{
+ OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
+ OSL_ENSURE(m_nEndPos >= m_nStartPos,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
+ OSL_ENSURE(m_nEndPos-m_nStartPos <= m_nFetchSize,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
+
+ if ( m_nStartPos < m_nPosition && m_nPosition <= m_nEndPos )
+ {
+ // just move inside the window
+ OSL_ENSURE((m_nPosition - m_nStartPos) <= static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ // make double plus sure that we have fetched that row
+ m_aMatrixIter = calcPosition();
+ OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(), "New m_aMatrixIter is at end(), but should not.");
+ if(!m_aMatrixIter->is())
+ {
+ bool bOk( m_xCacheSet->absolute( m_nPosition ) );
+ if ( bOk )
+ {
+ *m_aMatrixIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ // we have to read one row forward to ensure that we know when we are on last row
+ // but only when we don't know it already
+ if ( !m_bRowCountFinal )
+ {
+ bOk = m_xCacheSet->absolute( m_nPosition + 1 );
+ if ( bOk )
+ m_nRowCount = std::max(sal_Int32(m_nPosition+1),m_nRowCount);
+ }
+ }
+ if(!bOk && !m_bRowCountFinal)
+ {
+ // because we stand after the last row
+ m_nRowCount = m_xCacheSet->previous() ? m_xCacheSet->getRow() : 0;
+ m_bRowCountFinal = true;
+ }
+ }
+ return;
+ }
+
+ sal_Int32 nDiff = (m_nFetchSize - 1) / 2;
+ sal_Int32 nNewStartPos = (m_nPosition - nDiff) - 1; //m_nPosition is 1-based, but m_nStartPos is 0-based
+ sal_Int32 nNewEndPos = nNewStartPos + m_nFetchSize;
+
+ if ( nNewStartPos < 0 )
+ {
+ // The computed new window crashes through the floor (begins before first row);
+ // nNew*Pos has to be shifted by -nNewStartPos
+ nNewEndPos -= nNewStartPos;
+ nNewStartPos = 0;
+ }
+
+ if ( nNewStartPos < m_nStartPos )
+ { // need to fill data *before* m_nStartPos
+ if ( nNewEndPos > m_nStartPos )
+ { // The two regions are overlapping.
+ // We'll first rotate the contents of m_pMatrix so that the overlap area
+ // is positioned right; in the old window it is at the beginning,
+ // it has to go to the end.
+ // then we fill in the rows between new and old start pos.
+
+ bool bCheck;
+ bCheck = m_xCacheSet->absolute(nNewStartPos + 1);
+
+ // m_nEndPos < nNewEndPos when window not filled (e.g. there are fewer rows in total than window size)
+ m_nEndPos = std::min(nNewEndPos, m_nEndPos);
+ const sal_Int32 nOverlapSize = m_nEndPos - m_nStartPos;
+ const sal_Int32 nStartPosOffset = m_nStartPos - nNewStartPos; // by how much m_nStartPos moves
+ m_nStartPos = nNewStartPos;
+ OSL_ENSURE( o3tl::make_unsigned(nOverlapSize) <= m_pMatrix->size(), "new window end is after end of cache matrix!" );
+ // the first position in m_pMatrix whose data we don't keep;
+ // content will be moved to m_pMatrix.begin()
+ ORowSetMatrix::iterator aEnd (m_pMatrix->begin() + nOverlapSize);
+ // the first unused position after we are done; it == m_pMatrix.end() if and only if the window is full
+ ORowSetMatrix::iterator aNewEnd (aEnd + nStartPosOffset);
+ // *m_pMatrix now looks like:
+ // [0; nOverlapSize) i.e. [begin(); aEnd): data kept
+ // [nOverlapSize; nOverlapSize + nStartPosOffset) i.e. [aEnd, aNewEnd): new data of positions < old m_nStartPos
+ // [nOverlapSize + nStartPosOffset; size()) i.e. [aNewEnd, end()): unused
+ // Note that nOverlapSize + nStartPosOffset == m_nEndPos - m_nStartPos (new values)
+ // When we are finished:
+ // [0; nStartPosOffset) i.e. [begin(); aEnd): new data of positions < old m_nStartPos
+ // [nStartPosOffset; nOverlapSize + nStartPosOffset) i.e. [aEnd, aNewEnd): kept
+ // [nOverlapSize + nStartPosOffset; size()) i.e. [aNewEnd, end()): unused
+
+ if ( bCheck )
+ {
+ {
+ ORowSetMatrix::iterator aIter(aEnd);
+ sal_Int32 nPos = m_nStartPos + 1;
+ fill(aIter, aNewEnd, nPos, bCheck);
+ }
+
+ std::rotate(m_pMatrix->begin(), aEnd, aNewEnd);
+ if (!m_bModified)
+ {
+ // now correct the iterator in our iterator vector
+ // rotateCacheIterator(aEnd-m_pMatrix->begin()); //can't be used because they decrement and here we need to increment
+ for(auto& rCacheIter : m_aCacheIterators)
+ {
+ if ( !rCacheIter.second.pRowSet->isInsertRow()
+ && rCacheIter.second.aIterator != m_pMatrix->end() )
+ {
+ const ptrdiff_t nDist = rCacheIter.second.aIterator - m_pMatrix->begin();
+ if ( nDist >= nOverlapSize )
+ {
+ // That's from outside the overlap area; invalidate iterator.
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ else
+ {
+ // Inside overlap area: move to correct position
+ OSL_ENSURE(((nDist + nStartPosOffset) >= static_cast<ORowSetMatrix::difference_type>(0)) &&
+ ((nDist + nStartPosOffset) < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!");
+ rCacheIter.second.aIterator += nStartPosOffset;
+ OSL_ENSURE(rCacheIter.second.aIterator >= m_pMatrix->begin()
+ && rCacheIter.second.aIterator < m_pMatrix->end(),"Iterator out of area!");
+ }
+ }
+ }
+ }
+ }
+ else
+ { // normally this should never happen
+ OSL_FAIL("What the hell is happen here!");
+ return;
+ }
+ }
+ else
+ {// no rows can be reused so fill again
+ reFillMatrix(nNewStartPos,nNewEndPos);
+ }
+ }
+
+ OSL_ENSURE(nNewStartPos >= m_nStartPos, "ORowSetCache::moveWindow internal error: new start pos before current start pos");
+ if ( m_nEndPos < nNewEndPos )
+ { // need to fill data *after* m_nEndPos
+ if( nNewStartPos < m_nEndPos )
+ { // The two regions are overlapping.
+ const sal_Int32 nRowsInCache = m_nEndPos - m_nStartPos;
+ if ( nRowsInCache < m_nFetchSize )
+ {
+ // There is some unused space in *m_pMatrix; fill it
+ OSL_ENSURE((nRowsInCache >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nRowsInCache) < m_pMatrix->size()),"Position is invalid!");
+ sal_Int32 nPos = m_nEndPos + 1;
+ bool bCheck = m_xCacheSet->absolute(nPos);
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin() + nRowsInCache;
+ const sal_Int32 nRowsToFetch = std::min(nNewEndPos-m_nEndPos, m_nFetchSize-nRowsInCache);
+ const ORowSetMatrix::const_iterator aEnd = aIter + nRowsToFetch;
+ bCheck = fill(aIter, aEnd, nPos, bCheck);
+ m_nEndPos = nPos - 1;
+ OSL_ENSURE( (!bCheck && m_nEndPos <= nNewEndPos ) ||
+ ( bCheck && m_nEndPos == nNewEndPos ),
+ "ORowSetCache::moveWindow opportunistic fetch-after-current-end went badly");
+ }
+
+ // A priori, the rows from begin() [inclusive] to (begin() + nNewStartPos - m_nStartPos) [exclusive]
+ // have to be refilled with new to-be-fetched rows.
+ // The rows behind this can be reused
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ const sal_Int32 nNewStartPosInMatrix = nNewStartPos - m_nStartPos;
+ OSL_ENSURE((nNewStartPosInMatrix >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nNewStartPosInMatrix) < m_pMatrix->size()),"Position is invalid!");
+ // first position we reuse
+ const ORowSetMatrix::const_iterator aEnd = m_pMatrix->begin() + nNewStartPosInMatrix;
+ // End of used portion of the matrix. Is < m_pMatrix->end() if less data than window size
+ ORowSetMatrix::iterator aDataEnd = m_pMatrix->begin() + (m_nEndPos - m_nStartPos);
+
+ sal_Int32 nPos = m_nEndPos + 1;
+ bool bCheck = m_xCacheSet->absolute(nPos);
+ bCheck = fill(aIter, aEnd, nPos, bCheck); // refill the region we don't need anymore
+ //aIter and nPos are now the position *after* last filled in one!
+
+ // bind end to front
+ if(bCheck)
+ {
+ OSL_ENSURE(aIter == aEnd, "fill() said went till end, but did not.");
+ // rotate the end to the front
+ std::rotate(m_pMatrix->begin(), aIter, aDataEnd);
+ // now correct the iterator in our iterator vector
+ rotateCacheIterator( nNewStartPosInMatrix );
+ m_nStartPos = nNewStartPos;
+ m_nEndPos = nNewEndPos;
+ // now I can say how many rows we have
+ // we have to read one row forward to ensure that we know when we are on last row
+ // but only when we don't know it already
+ bool bOk = true;
+ if(!m_bRowCountFinal)
+ bOk = m_xCacheSet->next();
+ if(!bOk)
+ {
+ m_xCacheSet->previous(); // because we stand after the last row
+ m_nRowCount = nPos; // here we have the row count
+ OSL_ENSURE(nPos == m_xCacheSet->getRow(),"nPos is not valid!");
+ m_bRowCountFinal = true;
+ }
+ else if(!m_bRowCountFinal)
+ m_nRowCount = std::max(nPos+1, m_nRowCount); //+1 because we successfully moved to row after nPos
+ else
+ OSL_ENSURE(m_nRowCount >= nPos, "Final m_nRowCount is smaller than row I moved to!");
+ }
+ else
+ { // the end was reached before or at end() so we can set the start before or at nNewStartPos
+ // and possibly keep more of m_pMatrix than planned.
+ const ORowSetMatrix::const_iterator::difference_type nFetchedRows = aIter - m_pMatrix->begin();
+ // *m_pMatrix now looks like:
+ // [0; nFetchedRows) i.e. [begin(); aIter): newly fetched data for positions m_nEndPos to m_nEndPos+nFetchedRows
+ // [nFetchedRows; ???) i.e. [aIter; aDataEnd]: data to be kept for positions m_nStartPos+nFetchedRows to ???
+
+ nPos -= 1;
+ m_nStartPos += nFetchedRows;
+ m_nEndPos = nPos;
+ std::rotate(m_pMatrix->begin(), aIter, aDataEnd);
+ // now correct the iterator in our iterator vector
+ rotateCacheIterator( nFetchedRows );
+
+ if ( !m_bRowCountFinal )
+ {
+ m_xCacheSet->previous(); // because we stand after the last row
+ m_nRowCount = std::max(m_nRowCount, nPos); // here we have the row count
+ OSL_ENSURE(nPos == m_xCacheSet->getRow(),"nPos isn't valid!");
+ m_bRowCountFinal = true;
+ }
+
+ }
+ // here we need only to check if the beginning row is valid. If not we have to fetch it.
+ if(!m_pMatrix->begin()->is())
+ {
+ aIter = m_pMatrix->begin();
+
+ nPos = m_nStartPos + 1;
+ bCheck = m_xCacheSet->absolute(nPos);
+ for(; !aIter->is() && bCheck;++aIter, ++nPos)
+ {
+ OSL_ENSURE(aIter != m_pMatrix->end(),"Invalid iterator");
+
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*aIter, nPos);
+
+ bCheck = m_xCacheSet->next();
+ }
+ }
+ }
+ else // no rows can be reused so fill again
+ reFillMatrix(nNewStartPos,nNewEndPos);
+ }
+
+ if(!m_bRowCountFinal)
+ m_nRowCount = std::max(m_nPosition,m_nRowCount);
+ OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
+ OSL_ENSURE(m_nEndPos > m_nStartPos,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
+ OSL_ENSURE(m_nEndPos-m_nStartPos <= m_nFetchSize,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
+}
+
+bool ORowSetCache::first( )
+{
+ // First move to the first row.
+ // Then check if the cache window is at the beginning.
+ // If not, then position the window and fill it with data.
+ // We move the window smartly, i.e. we clear only the rows that are out of range
+ bool bRet = m_xCacheSet->first();
+ if(bRet)
+ {
+ m_bBeforeFirst = m_bAfterLast = false;
+ m_nPosition = 1;
+ moveWindow();
+ m_aMatrixIter = m_pMatrix->begin();
+ }
+ else
+ {
+ m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = true;
+ m_nRowCount = m_nPosition = 0;
+
+ OSL_ENSURE(m_bBeforeFirst || m_bNew,"ORowSetCache::first return false and BeforeFirst isn't true");
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ return bRet;
+}
+
+bool ORowSetCache::last( )
+{
+ bool bRet = m_xCacheSet->last();
+ if(bRet)
+ {
+ m_bBeforeFirst = m_bAfterLast = false;
+ if(!m_bRowCountFinal)
+ {
+ m_bRowCountFinal = true;
+ m_nRowCount = m_xCacheSet->getRow(); // not + 1
+ }
+ m_nPosition = m_xCacheSet->getRow();
+ moveWindow();
+ // we have to repositioning because moveWindow can modify the cache
+ m_xCacheSet->last();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ }
+ else
+ {
+ m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = true;
+ m_nRowCount = m_nPosition = 0;
+ OSL_ENSURE(m_bBeforeFirst,"ORowSetCache::last return false and BeforeFirst isn't true");
+ m_aMatrixIter = m_pMatrix->end();
+ }
+#if OSL_DEBUG_LEVEL > 0
+ if(bRet)
+ {
+ assert((*m_aMatrixIter).is() && "ORowSetCache::last: Row not valid!");
+ }
+#endif
+
+ return bRet;
+}
+
+sal_Int32 ORowSetCache::getRow( ) const
+{
+ return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition;
+}
+
+bool ORowSetCache::absolute( sal_Int32 row )
+{
+ if(!row )
+ throw SQLException(DBA_RES(RID_STR_NO_ABS_ZERO),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ if(row < 0)
+ {
+ // here we have to scroll from the last row to backward so we have to go to last row and
+ // and to the previous
+ if(m_bRowCountFinal || last())
+ {
+ m_nPosition = m_nRowCount + row + 1; // + row because row is negative and +1 because row==-1 means last row
+ if(m_nPosition < 1)
+ {
+ m_bBeforeFirst = true;
+ m_bAfterLast = false;
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_bBeforeFirst = false;
+ m_bAfterLast = m_nPosition > m_nRowCount;
+ moveWindow();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ }
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_nPosition = row;
+ // the position flags
+ m_bBeforeFirst = false;
+ checkPositionFlags();
+
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+ checkPositionFlags();
+ if(!m_bAfterLast)
+ m_aMatrixIter = calcPosition();
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+
+ return !(m_bAfterLast || m_bBeforeFirst);
+}
+
+bool ORowSetCache::relative( sal_Int32 rows )
+{
+ bool bErg = true;
+ if(rows)
+ {
+ sal_Int32 nNewPosition = m_nPosition + rows;
+
+ if ( m_bBeforeFirst && rows > 0 )
+ nNewPosition = rows;
+ else if ( m_bRowCountFinal && m_bAfterLast && rows < 0 )
+ nNewPosition = m_nRowCount + 1 + rows;
+ else
+ if ( m_bBeforeFirst || ( m_bRowCountFinal && m_bAfterLast ) )
+ throw SQLException( DBA_RES( RID_STR_NO_RELATIVE ), nullptr, SQLSTATE_GENERAL, 1000, Any() );
+ if ( nNewPosition )
+ {
+ bErg = absolute( nNewPosition );
+ bErg = bErg && !isAfterLast() && !isBeforeFirst();
+ }
+ else
+ {
+ m_bBeforeFirst = true;
+ bErg = false;
+ }
+ }
+ return bErg;
+}
+
+bool ORowSetCache::previous( )
+{
+ bool bRet = false;
+ if(!isBeforeFirst())
+ {
+ if(m_bAfterLast) // we stand after the last row so one before is the last row
+ bRet = last();
+ else
+ {
+ m_bAfterLast = false;
+ --m_nPosition;
+ moveWindow();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+
+ checkPositionFlags();
+
+ if(!m_nPosition)
+ {
+ m_bBeforeFirst = true;
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_aMatrixIter = calcPosition();
+ bRet = (*m_aMatrixIter).is();
+ }
+ }
+ }
+ return bRet;
+}
+
+void ORowSetCache::refreshRow( )
+{
+ if(isAfterLast())
+ throw SQLException(DBA_RES(RID_STR_NO_REFRESH_AFTERLAST),nullptr,SQLSTATE_GENERAL,1000,Any() );
+ OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(),"refreshRow() called for invalid row!");
+ m_xCacheSet->refreshRow();
+ m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ if ( m_bNew )
+ {
+ cancelRowModification();
+ }
+}
+
+bool ORowSetCache::rowUpdated( )
+{
+ return m_xCacheSet->rowUpdated();
+}
+
+bool ORowSetCache::rowInserted( )
+{
+ return m_xCacheSet->rowInserted();
+}
+
+// XResultSetUpdate
+bool ORowSetCache::insertRow(std::vector< Any >& o_aBookmarks)
+{
+ if ( !m_bNew || !m_aInsertRow->is() )
+ throw SQLException(DBA_RES(RID_STR_NO_MOVETOINSERTROW_CALLED),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ m_xCacheSet->insertRow(*m_aInsertRow,m_aUpdateTable);
+
+ bool bRet( rowInserted() );
+ if ( bRet )
+ {
+ ++m_nRowCount;
+ Any aBookmark = (**m_aInsertRow)[0].makeAny();
+ m_bAfterLast = m_bBeforeFirst = false;
+ if(aBookmark.hasValue())
+ {
+ moveToBookmark(aBookmark);
+ // update the cached values
+ ORowSetValueVector::Vector& rCurrentRow = **m_aMatrixIter;
+ ORowSetMatrix::const_iterator aIter = m_pMatrix->begin();
+ for(;aIter != m_pMatrix->end();++aIter)
+ {
+ if ( m_aMatrixIter != aIter && aIter->is() && m_xCacheSet->columnValuesUpdated(**aIter,rCurrentRow) )
+ {
+ o_aBookmarks.push_back(lcl_getBookmark((**aIter)[0], m_xCacheSet.get()));
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("There must be a bookmark after the row was inserted!");
+ }
+ }
+ return bRet;
+}
+
+void ORowSetCache::resetInsertRow(bool _bClearInsertRow)
+{
+ if ( _bClearInsertRow )
+ clearInsertRow();
+ m_bNew = false;
+ m_bModified = false;
+}
+
+void ORowSetCache::cancelRowModification()
+{
+ // clear the insertrow references -> implies that the current row of the rowset changes as well
+ for(auto& rCacheIter : m_aCacheIterators)
+ {
+ if ( rCacheIter.second.pRowSet->isInsertRow() && rCacheIter.second.aIterator == m_aInsertRow )
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ resetInsertRow(false);
+}
+
+void ORowSetCache::updateRow( ORowSetMatrix::iterator const & _rUpdateRow, std::vector< Any >& o_aBookmarks )
+{
+ if(isAfterLast() || isBeforeFirst())
+ throw SQLException(DBA_RES(RID_STR_NO_UPDATEROW),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ Any aBookmark = (**_rUpdateRow)[0].makeAny();
+ OSL_ENSURE(aBookmark.hasValue(),"Bookmark must have a value!");
+ // here we don't have to reposition our CacheSet, when we try to update a row,
+ // the row was already fetched
+ moveToBookmark(aBookmark);
+ m_xCacheSet->updateRow(*_rUpdateRow,*m_aMatrixIter,m_aUpdateTable);
+ // refetch the whole row
+ (*m_aMatrixIter) = nullptr;
+
+ if ( moveToBookmark(aBookmark) )
+ {
+ // update the cached values
+ ORowSetValueVector::Vector& rCurrentRow = **m_aMatrixIter;
+ ORowSetMatrix::const_iterator aIter = m_pMatrix->begin();
+ for(;aIter != m_pMatrix->end();++aIter)
+ {
+ if ( m_aMatrixIter != aIter && aIter->is() && m_xCacheSet->columnValuesUpdated(**aIter,rCurrentRow) )
+ {
+ o_aBookmarks.push_back(lcl_getBookmark((**aIter)[0], m_xCacheSet.get()));
+ }
+ }
+ }
+
+ m_bModified = false;
+}
+
+bool ORowSetCache::deleteRow( )
+{
+ if(isAfterLast() || isBeforeFirst())
+ throw SQLException(DBA_RES(RID_STR_NO_DELETEROW),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ m_xCacheSet->deleteRow(*m_aMatrixIter,m_aUpdateTable);
+ if ( !m_xCacheSet->rowDeleted() )
+ return false;
+
+ --m_nRowCount;
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ ORowSetMatrix::iterator aPos = calcPosition();
+ (*aPos) = nullptr;
+
+ ORowSetMatrix::const_iterator aEnd = m_pMatrix->end();
+ for(++aPos;aPos != aEnd && aPos->is();++aPos)
+ {
+ *(aPos-1) = *aPos;
+ (*aPos) = nullptr;
+ }
+ m_aMatrixIter = m_pMatrix->end();
+
+ --m_nPosition;
+ return true;
+}
+
+void ORowSetCache::cancelRowUpdates( )
+{
+ m_bNew = m_bModified = false;
+ if(!m_nPosition)
+ {
+ OSL_FAIL("cancelRowUpdates:Invalid positions pos == 0");
+ ::dbtools::throwFunctionSequenceException(nullptr);
+ }
+
+ if(m_xCacheSet->absolute(m_nPosition))
+ m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ else
+ {
+ OSL_FAIL("cancelRowUpdates couldn't position right with absolute");
+ ::dbtools::throwFunctionSequenceException(nullptr);
+ }
+}
+
+void ORowSetCache::moveToInsertRow( )
+{
+ m_bNew = true;
+ m_bAfterLast = false;
+
+ m_aInsertRow = m_pInsertMatrix->begin();
+ if(!m_aInsertRow->is())
+ *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
+
+ // we don't unbound the bookmark column
+ ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->begin()+1;
+ ORowSetValueVector::Vector::const_iterator aEnd = (*m_aInsertRow)->end();
+ for(sal_Int32 i = 1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setBound(false);
+ aIter->setModified(false);
+ aIter->setNull();
+ aIter->setTypeKind(m_xMetaData->getColumnType(i));
+ }
+}
+
+ORowSetCacheIterator ORowSetCache::createIterator(ORowSetBase* _pRowSet)
+{
+ ORowSetCacheIterator_Helper aHelper;
+ aHelper.aIterator = m_pMatrix->end();
+ aHelper.pRowSet = _pRowSet;
+ return ORowSetCacheIterator(m_aCacheIterators.insert(m_aCacheIterators.begin(),ORowSetCacheMap::value_type(m_aCacheIterators.size()+1,aHelper)),this,_pRowSet);
+}
+
+void ORowSetCache::deleteIterator(const ORowSetBase* _pRowSet)
+{
+ ORowSetCacheMap::const_iterator aCacheIter = m_aCacheIterators.begin();
+ for(;aCacheIter != m_aCacheIterators.end();)
+ {
+ if ( aCacheIter->second.pRowSet == _pRowSet )
+ {
+ aCacheIter = m_aCacheIterators.erase(aCacheIter);
+ }
+ else
+ ++aCacheIter;
+ }
+}
+
+void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist)
+{
+ if (m_bModified)
+ return;
+
+ if(!_nDist)
+ return;
+
+ // now correct the iterator in our iterator vector
+ for(auto& rCacheIter : m_aCacheIterators)
+ {
+ if ( !rCacheIter.second.pRowSet->isInsertRow()
+ && rCacheIter.second.aIterator != m_pMatrix->end())
+ {
+ ptrdiff_t nDist = rCacheIter.second.aIterator - m_pMatrix->begin();
+ if(nDist < _nDist)
+ {
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ else
+ {
+ OSL_ENSURE((rCacheIter.second.aIterator - m_pMatrix->begin()) >= _nDist,"Invalid Dist value!");
+ rCacheIter.second.aIterator -= _nDist;
+ OSL_ENSURE(rCacheIter.second.aIterator >= m_pMatrix->begin()
+ && rCacheIter.second.aIterator < m_pMatrix->end(),"Iterator out of area!");
+ }
+ }
+ }
+}
+
+void ORowSetCache::rotateAllCacheIterators()
+{
+ if (m_bModified)
+ return;
+
+ // now correct the iterator in our iterator vector
+ for (auto& rCacheIter : m_aCacheIterators)
+ {
+ if (!rCacheIter.second.pRowSet->isInsertRow())
+ {
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ }
+}
+
+void ORowSetCache::setUpdateIterator(const ORowSetMatrix::iterator& _rOriginalRow)
+{
+ m_aInsertRow = m_pInsertMatrix->begin();
+ if(!m_aInsertRow->is())
+ *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
+
+ (*(*m_aInsertRow)) = *(*_rOriginalRow);
+ // we don't unbound the bookmark column
+ for(auto& rItem : **m_aInsertRow)
+ rItem.setModified(false);
+}
+
+void ORowSetCache::checkPositionFlags()
+{
+ if(m_bRowCountFinal)
+ {
+ m_bAfterLast = m_nPosition > m_nRowCount;
+ if(m_bAfterLast)
+ m_nPosition = 0;//m_nRowCount;
+ }
+}
+
+void ORowSetCache::checkUpdateConditions(sal_Int32 columnIndex)
+{
+ if(m_bAfterLast || columnIndex >= static_cast<sal_Int32>((*m_aInsertRow)->size()))
+ throwFunctionSequenceException(m_xSet.get());
+}
+
+bool ORowSetCache::checkInnerJoin(const ::connectivity::OSQLParseNode *pNode,const Reference< XConnection>& _xConnection,const OUString& _sUpdateTableName)
+{
+ bool bOk = false;
+ if (pNode->count() == 3 && // expression in parentheses
+ SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pNode->getChild(2),")"))
+ {
+ bOk = checkInnerJoin(pNode->getChild(1),_xConnection,_sUpdateTableName);
+ }
+ else if ((SQL_ISRULE(pNode,search_condition) || SQL_ISRULE(pNode,boolean_term)) && // AND/OR link
+ pNode->count() == 3)
+ {
+ // only allow an AND link
+ if ( SQL_ISTOKEN(pNode->getChild(1),AND) )
+ bOk = checkInnerJoin(pNode->getChild(0),_xConnection,_sUpdateTableName)
+ && checkInnerJoin(pNode->getChild(2),_xConnection,_sUpdateTableName);
+ }
+ else if (SQL_ISRULE(pNode,comparison_predicate))
+ {
+ // only the comparison of columns is allowed
+ OSL_ENSURE(pNode->count() == 3,"checkInnerJoin: Error in Parse Tree");
+ if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
+ SQL_ISRULE(pNode->getChild(2),column_ref) &&
+ pNode->getChild(1)->getNodeType() == SQLNodeType::Equal))
+ {
+ bOk = false;
+ }
+ else
+ {
+ OUString sColumnName,sTableRange;
+ OSQLParseTreeIterator::getColumnRange( pNode->getChild(0), _xConnection, sColumnName, sTableRange );
+ bOk = sTableRange == _sUpdateTableName;
+ if ( !bOk )
+ {
+ OSQLParseTreeIterator::getColumnRange( pNode->getChild(2), _xConnection, sColumnName, sTableRange );
+ bOk = sTableRange == _sUpdateTableName;
+ }
+ }
+ }
+ return bOk;
+}
+
+bool ORowSetCache::checkJoin(const Reference< XConnection>& _xConnection,
+ const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const OUString& _sUpdateTableName )
+{
+ bool bOk = false;
+ OUString sSql = _xAnalyzer->getQuery();
+ OUString sErrorMsg;
+ ::connectivity::OSQLParser aSqlParser( m_aContext );
+ std::unique_ptr< ::connectivity::OSQLParseNode> pSqlParseNode( aSqlParser.parseTree(sErrorMsg,sSql));
+ if ( pSqlParseNode && SQL_ISRULE(pSqlParseNode, select_statement) )
+ {
+ OSQLParseNode* pTableRefCommalist = pSqlParseNode->getByRule(::connectivity::OSQLParseNode::table_ref_commalist);
+ OSL_ENSURE(pTableRefCommalist,"NO tables why!?");
+ if(pTableRefCommalist && pTableRefCommalist->count() == 1)
+ {
+ // we found only one element so it must some kind of join here
+ OSQLParseNode* pJoin = pTableRefCommalist->getByRule(::connectivity::OSQLParseNode::qualified_join);
+ if(pJoin)
+ { // we are only interested in qualified joins like RIGHT or LEFT
+ OSQLParseNode* pJoinType = pJoin->getChild(1);
+ OSQLParseNode* pOuterType = nullptr;
+ if(SQL_ISRULE(pJoinType,join_type) && pJoinType->count() == 2)
+ pOuterType = pJoinType->getChild(0);
+ else if(SQL_ISRULE(pJoinType,outer_join_type))
+ pOuterType = pJoinType;
+
+ bool bCheck = false;
+ bool bLeftSide = false;
+ if(pOuterType)
+ { // found outer join
+ bLeftSide = SQL_ISTOKEN(pOuterType->getChild(0),LEFT);
+ bCheck = bLeftSide || SQL_ISTOKEN(pOuterType->getChild(0),RIGHT);
+ }
+
+ if(bCheck)
+ { // here we know that we have to check on which side our table resides
+ const OSQLParseNode* pTableRef;
+ if(bLeftSide)
+ pTableRef = pJoin->getChild(0);
+ else
+ pTableRef = pJoin->getChild(3);
+ OSL_ENSURE(SQL_ISRULE(pTableRef,table_ref),"Must be a tableref here!");
+
+ OUString sTableRange = OSQLParseNode::getTableRange(pTableRef);
+ if(sTableRange.isEmpty())
+ pTableRef->getChild(0)->parseNodeToStr( sTableRange, _xConnection, nullptr, false, false );
+ bOk = sTableRange == _sUpdateTableName;
+ }
+ }
+ }
+ else
+ {
+ OSQLParseNode* pWhereOpt = pSqlParseNode->getChild(3)->getChild(1);
+ if ( pWhereOpt && !pWhereOpt->isLeaf() )
+ bOk = checkInnerJoin(pWhereOpt->getChild(1),_xConnection,_sUpdateTableName);
+ }
+ }
+ return bOk;
+}
+
+void ORowSetCache::clearInsertRow()
+{
+ // we don't unbound the bookmark column
+ if ( m_aInsertRow != m_pInsertMatrix->end() && m_aInsertRow->is() )
+ {
+ ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->begin()+1;
+ ORowSetValueVector::Vector::const_iterator aEnd = (*m_aInsertRow)->end();
+ for(;aIter != aEnd;++aIter)
+ {
+ aIter->setBound(false);
+ aIter->setModified(false);
+ aIter->setNull();
+ }
+ }
+}
+
+ORowSetMatrix::iterator ORowSetCache::calcPosition() const
+{
+ sal_Int32 nValue = (m_nPosition - m_nStartPos) - 1;
+ OSL_ENSURE((nValue >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nValue) < m_pMatrix->size()),"Position is invalid!");
+ return ( nValue < 0 || o3tl::make_unsigned(nValue) >= m_pMatrix->size() ) ? m_pMatrix->end() : (m_pMatrix->begin() + nValue);
+}
+
+TORowSetOldRowHelperRef ORowSetCache::registerOldRow()
+{
+ TORowSetOldRowHelperRef pRef = new ORowSetOldRowHelper(ORowSetRow());
+ m_aOldRows.push_back(pRef);
+ return pRef;
+}
+
+void ORowSetCache::deregisterOldRow(const TORowSetOldRowHelperRef& _rRow)
+{
+ TOldRowSetRows::iterator aOldRowIter = std::find_if(m_aOldRows.begin(), m_aOldRows.end(),
+ [&_rRow](const TORowSetOldRowHelperRef& rxOldRow) { return rxOldRow.get() == _rRow.get(); });
+ if (aOldRowIter != m_aOldRows.end())
+ m_aOldRows.erase(aOldRowIter);
+}
+
+bool ORowSetCache::reFillMatrix(sal_Int32 _nNewStartPos, sal_Int32 _nNewEndPos)
+{
+ for (const auto& rxOldRow : m_aOldRows)
+ {
+ if ( rxOldRow.is() && rxOldRow->getRow().is() )
+ rxOldRow->setRow(new ORowSetValueVector( *(rxOldRow->getRow()) ) );
+ }
+ sal_Int32 nNewSt = _nNewStartPos;
+ bool bRet = fillMatrix(nNewSt,_nNewEndPos);
+ m_nStartPos = nNewSt;
+ m_nEndPos = _nNewEndPos;
+ rotateAllCacheIterators(); // invalidate every iterator
+ return bRet;
+}
+
+bool ORowSetCache::fill(ORowSetMatrix::iterator& _aIter, const ORowSetMatrix::const_iterator& _aEnd, sal_Int32& _nPos, bool _bCheck)
+{
+ const sal_Int32 nColumnCount = m_xMetaData->getColumnCount();
+ for (; _bCheck && _aIter != _aEnd; ++_aIter, ++_nPos)
+ {
+ if ( !_aIter->is() )
+ *_aIter = new ORowSetValueVector(nColumnCount);
+ else
+ {
+ for (const auto& rxOldRow : m_aOldRows)
+ {
+ if ( rxOldRow->getRow() == *_aIter )
+ *_aIter = new ORowSetValueVector(nColumnCount);
+ }
+ }
+ m_xCacheSet->fillValueRow(*_aIter, _nPos);
+ _bCheck = m_xCacheSet->next();
+ }
+ return _bCheck;
+}
+
+bool ORowSetCache::isResultSetChanged() const
+{
+ return m_xCacheSet->isResultSetChanged();
+}
+
+void ORowSetCache::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ m_xSet = _xDriverSet;
+ m_xMetaData.set(Reference< XResultSetMetaDataSupplier >(_xDriverSet,UNO_QUERY_THROW)->getMetaData());
+ m_xCacheSet->reset(_xDriverSet);
+
+ m_bRowCountFinal = false;
+ m_nRowCount = 0;
+ reFillMatrix(m_nStartPos,m_nEndPos);
+}
+
+void ORowSetCache::impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32> const & o_ChangedColumns)
+{
+ if ( o_ChangedColumns.size() > 1 )
+ {
+ for (auto const& elem : *m_pMatrix)
+ {
+ if ( elem.is() && m_xCacheSet->updateColumnValues(*elem,io_aRow,o_ChangedColumns))
+ {
+ return;
+ }
+ }
+ m_xCacheSet->fillMissingValues(io_aRow);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCache.hxx b/dbaccess/source/core/api/RowSetCache.hxx
new file mode 100644
index 000000000..01ed6394d
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCache.hxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include "RowSetRow.hxx"
+#include "RowSetCacheIterator.hxx"
+
+namespace connectivity
+{
+ class OSQLParseNode;
+}
+namespace dbaccess
+{
+ class OCacheSet;
+
+ class ORowSetCache
+ {
+ friend class ORowSetBase;
+ friend class ORowSet;
+ friend class ORowSetClone;
+ friend class ORowSetCacheIterator;
+
+ typedef std::vector< TORowSetOldRowHelperRef > TOldRowSetRows;
+
+ std::map<sal_Int32,sal_Int32> m_aKeyColumns;
+ //the set can be static, bookmarkable or keyset
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xSet;
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData; // must be before m_aInsertRow
+ css::uno::Reference< css::uno::XComponentContext> m_aContext;
+
+ rtl::Reference<OCacheSet> m_xCacheSet; // is a bookmarkable, keyset or static resultset
+
+ std::unique_ptr<ORowSetMatrix> m_pMatrix; // represent the table struct
+ ORowSetMatrix::iterator m_aMatrixIter; // represent a row of the table
+ ORowSetMatrix::iterator m_aMatrixEnd; // present the row behind the last row of the table
+ ORowSetCacheMap m_aCacheIterators;
+ TOldRowSetRows m_aOldRows;
+
+ std::unique_ptr<ORowSetMatrix> m_pInsertMatrix; // represent the rows which should be inserted normally this is only one
+ ORowSetMatrix::iterator m_aInsertRow; // represent an insert row
+
+ connectivity::OSQLTable m_aUpdateTable; // used for updates/deletes and inserts
+
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nRowCount;
+ sal_Int32 m_nPrivileges;
+ sal_Int32 m_nPosition; // 0 means before first (i.e. 1-based)
+
+ sal_Int32 m_nStartPos; // start pos of the window zero based (inclusive)
+ sal_Int32 m_nEndPos; // end pos of the window zero based (exclusive)
+
+ bool m_bRowCountFinal ;
+ bool m_bBeforeFirst ;
+ bool m_bAfterLast ;
+ bool& m_bModified ; // points to the rowset member m_bModified
+ bool& m_bNew ; // points to the rowset member m_bNew
+
+ bool fill(ORowSetMatrix::iterator& _aIter, const ORowSetMatrix::const_iterator& _aEnd, sal_Int32& _nPos, bool _bCheck);
+ bool reFillMatrix(sal_Int32 _nNewStartPos,sal_Int32 nNewEndPos);
+ bool fillMatrix(sal_Int32 &_nNewStartPos,sal_Int32 &_nNewEndPos);
+ void moveWindow();
+
+ void rotateCacheIterator(ORowSetMatrix::difference_type _nDist);
+ void rotateAllCacheIterators();
+ void updateValue(sal_Int32 columnIndex
+ ,const connectivity::ORowSetValue& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ );
+
+ void impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32> const & o_ChangedColumns
+ );
+ // checks and set the flags isAfterLast isLast and position when afterlast is true
+ void checkPositionFlags();
+ void checkUpdateConditions(sal_Int32 columnIndex);
+ bool checkJoin( const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xComposer,
+ const OUString& _sUpdateTableName);
+ bool checkInnerJoin(const ::connectivity::OSQLParseNode *pNode
+ ,const css::uno::Reference< css::sdbc::XConnection>& _xConnection
+ ,const OUString& _sUpdateTableName);
+
+ // clears the insert row
+ void clearInsertRow();
+ ORowSetMatrix::iterator calcPosition() const;
+
+ protected:
+ const ORowSetMatrix::iterator& getEnd() const { return m_aMatrixEnd;}
+ // is called when after a moveToInsertRow a movement (next, etc) was called
+ void cancelRowModification();
+ public:
+ ORowSetCache(const css::uno::Reference< css::sdbc::XResultSet >& _xRs,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const OUString& _rUpdateTableName,
+ bool& _bModified,
+ bool& _bNew,
+ const ORowSetValueVector& _aParameterValueForCache,
+ const OUString& i_sRowSetFilter,
+ sal_Int32 i_nMaxRows);
+ ~ORowSetCache();
+
+
+ // called from the rowset when an updateXXX was called for the first time
+ void setUpdateIterator(const ORowSetMatrix::iterator& _rOriginalRow);
+ ORowSetCacheIterator createIterator(ORowSetBase* _pRowSet);
+ void deleteIterator(const ORowSetBase* _pRowSet);
+ // sets the size of the matrix
+ void setFetchSize(sal_Int32 _nSize);
+
+ TORowSetOldRowHelperRef registerOldRow();
+ void deregisterOldRow(const TORowSetOldRowHelperRef& _rRow);
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ const css::uno::Reference< css::sdbc::XResultSetMetaData >& getMetaData( ) const { return m_xMetaData;}
+
+ // css::sdbcx::XRowLocate
+ css::uno::Any getBookmark( );
+ bool moveToBookmark( const css::uno::Any& bookmark );
+ bool moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows );
+ sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second );
+ bool hasOrderedBookmarks( );
+ sal_Int32 hashBookmark( const css::uno::Any& bookmark );
+
+ // css::sdbc::XRowUpdate
+ void updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_ChangedColumns
+ );
+ void updateObject( sal_Int32 columnIndex, const css::uno::Any& x,ORowSetValueVector::Vector& io_aRow ,std::vector<sal_Int32>& o_ChangedColumns);
+ void updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, ORowSetValueVector::Vector& io_aRow ,std::vector<sal_Int32>& o_ChangedColumns);
+ void updateNull(sal_Int32 columnIndex
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ );
+
+ // css::sdbc::XResultSet
+ bool next( );
+ bool isBeforeFirst( ) const { return m_bBeforeFirst;}
+ bool isAfterLast( ) const { return m_bAfterLast;}
+ bool isFirst( ) const;
+ bool isLast( ) const;
+ void beforeFirst( );
+ void afterLast( );
+ bool first( );
+ bool last( );
+ sal_Int32 getRow( ) const;
+ bool absolute( sal_Int32 row );
+ bool relative( sal_Int32 rows );
+ bool previous( );
+ void refreshRow( );
+ bool rowUpdated( );
+ bool rowInserted( );
+
+ // css::sdbc::XResultSetUpdate
+ bool insertRow(std::vector< css::uno::Any >& o_aBookmarks);
+ void resetInsertRow(bool _bClearInsertRow);
+
+ void updateRow( ORowSetMatrix::iterator const & _rUpdateRow, std::vector< css::uno::Any >& o_aBookmarks );
+ bool deleteRow();
+ void cancelRowUpdates( );
+ void moveToInsertRow( );
+
+ const std::map<sal_Int32,sal_Int32>& getKeyColumns() const { return m_aKeyColumns; }
+ bool isResultSetChanged() const;
+ void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCacheIterator.cxx b/dbaccess/source/core/api/RowSetCacheIterator.cxx
new file mode 100644
index 000000000..7df7bae6b
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCacheIterator.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "RowSetCacheIterator.hxx"
+#include "RowSetCache.hxx"
+#include "RowSetBase.hxx"
+
+using namespace dbaccess;
+
+ORowSetCacheIterator::ORowSetCacheIterator(const ORowSetCacheIterator& _rRH)
+: m_aIter(_rRH.m_aIter)
+, m_pCache(_rRH.m_pCache)
+,m_pRowSet(_rRH.m_pRowSet)
+{
+}
+
+ORowSetCacheIterator::operator ORowSetMatrix::iterator const &()
+{
+ return m_aIter->second.aIterator;
+}
+
+ORowSetCacheIterator& ORowSetCacheIterator::operator =(const ORowSetCacheIterator& _rRH)
+{
+ if(this == &_rRH)
+ return *this;
+
+ m_pCache = _rRH.m_pCache;
+ m_aIter = _rRH.m_aIter;
+ m_pRowSet = _rRH.m_pRowSet;
+
+ return *this;
+}
+
+ORowSetCacheIterator& ORowSetCacheIterator::operator =(const ORowSetMatrix::iterator& _rIter)
+{
+ m_aIter->second.aIterator = _rIter;
+ return *this;
+}
+
+ORowSetRow& ORowSetCacheIterator::operator *()
+{
+ return *m_aIter->second.aIterator;
+}
+
+ORowSetMatrix::iterator& ORowSetCacheIterator::operator ->()
+{
+ return m_aIter->second.aIterator;
+}
+
+bool ORowSetCacheIterator::operator <(const ORowSetMatrix::iterator& _rRH) const
+{
+ return m_aIter->second.aIterator < _rRH;
+}
+
+bool ORowSetCacheIterator::operator !=(const ORowSetMatrix::iterator& _rRH) const
+{
+ return m_aIter->second.aIterator != _rRH;
+}
+
+bool ORowSetCacheIterator::isNull() const
+{
+ bool bRet = !m_pCache || !m_pRowSet || m_aIter == m_pCache->m_aCacheIterators.end();
+ if ( !bRet )
+ {
+ bRet = ( m_pRowSet->isInsertRow()
+ ?
+ m_aIter->second.aIterator == m_pCache->m_pInsertMatrix->end()
+ :
+ m_aIter->second.aIterator == m_pCache->m_pMatrix->end()
+ );
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCacheIterator.hxx b/dbaccess/source/core/api/RowSetCacheIterator.hxx
new file mode 100644
index 000000000..9c7a9afd4
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCacheIterator.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include "RowSetRow.hxx"
+
+namespace dbaccess
+{
+ class ORowSetBase;
+ struct ORowSetCacheIterator_Helper
+ {
+ ORowSetMatrix::iterator aIterator;
+ ORowSetBase* pRowSet;
+ };
+
+ typedef std::map<sal_Int32, ORowSetCacheIterator_Helper> ORowSetCacheMap;
+
+ class ORowSetCache;
+ class ORowSetCacheIterator final
+ {
+ friend class ORowSetCache;
+ ORowSetCacheMap::iterator m_aIter;
+ ORowSetCache* m_pCache;
+ ORowSetBase* m_pRowSet;
+
+ ORowSetCacheIterator(const ORowSetCacheMap::iterator& _rIter,ORowSetCache* _pCache,ORowSetBase* _pRowSet)
+ : m_aIter(_rIter)
+ ,m_pCache(_pCache)
+ ,m_pRowSet(_pRowSet)
+ {
+ }
+ public:
+ ORowSetCacheIterator() :m_aIter(),m_pCache(nullptr),m_pRowSet(nullptr){}
+ ORowSetCacheIterator(const ORowSetCacheIterator& _rRH);
+ ORowSetCacheIterator& operator =(const ORowSetCacheIterator&);
+
+ bool isNull() const;
+ ORowSetCacheIterator& operator =(const ORowSetMatrix::iterator&);
+ operator ORowSetMatrix::iterator const &();
+
+ ORowSetRow& operator *();
+
+ ORowSetMatrix::iterator& operator ->();
+
+ bool operator <(const ORowSetMatrix::iterator& _rRH) const;
+ bool operator !=(const ORowSetMatrix::iterator& _rRH) const;
+
+ const ORowSetCacheMap::iterator& getIter() const { return m_aIter; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetRow.hxx b/dbaccess/source/core/api/RowSetRow.hxx
new file mode 100644
index 000000000..7f24267b7
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetRow.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+namespace dbaccess
+{
+ typedef connectivity::ORowVector< connectivity::ORowSetValue > ORowSetValueVector;
+ typedef ::rtl::Reference< ORowSetValueVector > ORowSetRow;
+ typedef std::vector< ORowSetRow > ORowSetMatrix;
+
+ class ORowSetOldRowHelper : public salhelper::SimpleReferenceObject
+ {
+ ORowSetRow m_aRow;
+
+ ORowSetOldRowHelper& operator=(const ORowSetOldRowHelper& _rRH) = delete;
+ ORowSetOldRowHelper(const ORowSetOldRowHelper& _rRh) = delete;
+ public:
+ explicit ORowSetOldRowHelper(const ORowSetRow& _rRow)
+ : m_aRow(_rRow)
+ {}
+
+ const ORowSetRow& getRow() const { return m_aRow; }
+ void clearRow() { m_aRow = nullptr; }
+ void setRow(const ORowSetRow& _rRow) { m_aRow = _rRow; }
+ };
+
+ typedef ::rtl::Reference< ORowSetOldRowHelper > TORowSetOldRowHelperRef;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/SingleSelectQueryComposer.cxx b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx
new file mode 100644
index 000000000..3c6906893
--- /dev/null
+++ b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx
@@ -0,0 +1,1922 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+#include <sal/log.hxx>
+#include <composertools.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <stringconstants.hxx>
+#include "HelperCollections.hxx"
+#include <SingleSelectQueryComposer.hxx>
+#include <sqlbison.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/PColumn.hxx>
+#include <connectivity/predicateinput.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <unotools/sharedunocomponent.hxx>
+
+#include <memory>
+#include <string_view>
+
+using namespace ::dbaccess;
+using namespace ::dbtools;
+using namespace ::comphelper;
+using namespace ::connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::util;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::utl;
+
+namespace dbaccess {
+namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;
+}
+
+constexpr OUStringLiteral STR_SELECT = u"SELECT ";
+constexpr OUStringLiteral STR_FROM = u" FROM ";
+constexpr OUStringLiteral STR_WHERE = u" WHERE ";
+constexpr OUStringLiteral STR_GROUP_BY = u" GROUP BY ";
+constexpr OUStringLiteral STR_HAVING = u" HAVING ";
+constexpr OUStringLiteral STR_ORDER_BY = u" ORDER BY ";
+constexpr OUStringLiteral STR_AND = u" AND ";
+constexpr OUStringLiteral STR_OR = u" OR ";
+constexpr OUStringLiteral STR_LIKE = u" LIKE ";
+constexpr OUStringLiteral L_BRACKET = u"(";
+constexpr OUStringLiteral R_BRACKET = u")";
+constexpr OUStringLiteral COMMA = u",";
+
+namespace
+{
+ /** parses the given statement, using the given parser, returns a parse node representing
+ the statement
+
+ If the statement cannot be parsed, an error is thrown.
+ */
+ std::unique_ptr<OSQLParseNode> parseStatement_throwError( OSQLParser& _rParser, const OUString& _rStatement, const Reference< XInterface >& _rxContext )
+ {
+ OUString aErrorMsg;
+ std::unique_ptr<OSQLParseNode> pNewSqlParseNode = _rParser.parseTree( aErrorMsg, _rStatement );
+ if ( !pNewSqlParseNode )
+ {
+ OUString sSQLStateGeneralError( getStandardSQLState( StandardSQLState::GENERAL_ERROR ) );
+ SQLException aError2( aErrorMsg, _rxContext, sSQLStateGeneralError, 1000, Any() );
+ SQLException aError1( _rStatement, _rxContext, sSQLStateGeneralError, 1000, Any( aError2 ) );
+ throw SQLException(_rParser.getContext().getErrorMessage(OParseContext::ErrorCode::General),_rxContext,sSQLStateGeneralError,1000,Any(aError1));
+ }
+ return pNewSqlParseNode;
+ }
+
+ /** checks whether the given parse node describes a valid single select statement, throws
+ an error if not
+ */
+ void checkForSingleSelect_throwError( const OSQLParseNode* pStatementNode, OSQLParseTreeIterator& _rIterator,
+ const Reference< XInterface >& _rxContext, const OUString& _rOriginatingCommand )
+ {
+ const OSQLParseNode* pOldNode = _rIterator.getParseTree();
+
+ // determine the statement type
+ _rIterator.setParseTree( pStatementNode );
+ _rIterator.traverseAll();
+ bool bIsSingleSelect = ( _rIterator.getStatementType() == OSQLStatementType::Select );
+
+ // throw the error, if necessary
+ if ( !bIsSingleSelect || SQL_ISRULE( pStatementNode, union_statement ) ) // #i4229# OJ
+ {
+ // restore the old node before throwing the exception
+ _rIterator.setParseTree( pOldNode );
+ // and now really ...
+ SQLException aError1( _rOriginatingCommand, _rxContext, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() );
+ throw SQLException( DBA_RES( RID_STR_ONLY_QUERY ), _rxContext,
+ getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any( aError1 ) );
+ }
+
+ delete pOldNode;
+ }
+
+ /** combines parseStatement_throwError and checkForSingleSelect_throwError
+ */
+ void parseAndCheck_throwError( OSQLParser& _rParser, const OUString& _rStatement,
+ OSQLParseTreeIterator& _rIterator, const Reference< XInterface >& _rxContext )
+ {
+ std::unique_ptr<OSQLParseNode> pNode = parseStatement_throwError( _rParser, _rStatement, _rxContext );
+ checkForSingleSelect_throwError( pNode.release(), _rIterator, _rxContext, _rStatement );
+ }
+
+ /** transforms a parse node describing a complete statement into a pure select
+ statement, without any filter/order/groupby/having clauses
+ */
+ OUString getPureSelectStatement( const OSQLParseNode* _pRootNode, const Reference< XConnection >& _rxConnection )
+ {
+ OUString sSQL = STR_SELECT;
+ _pRootNode->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
+ _pRootNode->getChild(2)->parseNodeToStr( sSQL, _rxConnection );
+ sSQL += STR_FROM;
+ _pRootNode->getChild(3)->getChild(0)->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
+ return sSQL;
+ }
+
+ /** resets an SQL iterator, including deletion of the parse tree, and dispose
+ */
+ void resetIterator( OSQLParseTreeIterator& _rIterator )
+ {
+ const OSQLParseNode* pSqlParseNode = _rIterator.getParseTree();
+ _rIterator.setParseTree(nullptr);
+ delete pSqlParseNode;
+ _rIterator.dispose();
+ }
+ void lcl_addFilterCriteria_throw(sal_Int32 i_nFilterOperator,std::u16string_view i_sValue,OUStringBuffer& o_sRet)
+ {
+ switch( i_nFilterOperator )
+ {
+ case SQLFilterOperator::EQUAL:
+ o_sRet.append(OUString::Concat(" = ") + i_sValue);
+ break;
+ case SQLFilterOperator::NOT_EQUAL:
+ o_sRet.append(OUString::Concat(" <> ") + i_sValue);
+ break;
+ case SQLFilterOperator::LESS:
+ o_sRet.append(OUString::Concat(" < ") + i_sValue);
+ break;
+ case SQLFilterOperator::GREATER:
+ o_sRet.append(OUString::Concat(" > ") + i_sValue);
+ break;
+ case SQLFilterOperator::LESS_EQUAL:
+ o_sRet.append(OUString::Concat(" <= ") + i_sValue);
+ break;
+ case SQLFilterOperator::GREATER_EQUAL:
+ o_sRet.append(OUString::Concat(" >= ") + i_sValue);
+ break;
+ case SQLFilterOperator::LIKE:
+ o_sRet.append(OUString::Concat(" LIKE ") + i_sValue);
+ break;
+ case SQLFilterOperator::NOT_LIKE:
+ o_sRet.append(OUString::Concat(" NOT LIKE ") + i_sValue);
+ break;
+ case SQLFilterOperator::SQLNULL:
+ o_sRet.append(" IS NULL");
+ break;
+ case SQLFilterOperator::NOT_SQLNULL:
+ o_sRet.append(" IS NOT NULL");
+ break;
+ default:
+ throw SQLException();
+ }
+ }
+
+}
+
+
+OSingleSelectQueryComposer::OSingleSelectQueryComposer(const Reference< XNameAccess>& _rxTables,
+ const Reference< XConnection>& _xConnection,
+ const Reference<XComponentContext>& _rContext )
+ :OSubComponent(m_aMutex,_xConnection)
+ ,OPropertyContainer(m_aBHelper)
+ ,m_aSqlParser( _rContext, &m_aParseContext )
+ ,m_aSqlIterator( _xConnection, _rxTables, m_aSqlParser )
+ ,m_aAdditiveIterator( _xConnection, _rxTables, m_aSqlParser )
+ ,m_aElementaryParts( size_t(SQLPartCount) )
+ ,m_xConnection(_xConnection)
+ ,m_xMetaData(_xConnection->getMetaData())
+ ,m_xConnectionTables( _rxTables )
+ ,m_aContext( _rContext )
+ ,m_nBoolCompareMode( BooleanComparisonMode::EQUAL_INTEGER )
+ ,m_nCommandType(CommandType::COMMAND)
+{
+ if ( !m_aContext.is() || !m_xConnection.is() || !m_xConnectionTables.is() )
+ throw IllegalArgumentException();
+
+ registerProperty(PROPERTY_ORIGINAL,PROPERTY_ID_ORIGINAL,PropertyAttribute::BOUND|PropertyAttribute::READONLY,&m_sOriginal,cppu::UnoType<decltype(m_sOriginal)>::get());
+
+ m_aCurrentColumns.resize(4);
+
+ m_aLocale = m_aParseContext.getPreferredLocale();
+ m_xNumberFormatsSupplier = dbtools::getNumberFormats( m_xConnection, true, m_aContext );
+ Reference< XLocaleData4 > xLocaleData( LocaleData::create(m_aContext) );
+ LocaleDataItem aData = xLocaleData->getLocaleItem(m_aLocale);
+ m_sDecimalSep = aData.decimalSeparator;
+ OSL_ENSURE(m_sDecimalSep.getLength() == 1,"OSingleSelectQueryComposer::OSingleSelectQueryComposer decimal separator is not 1 length");
+ try
+ {
+ Any aValue;
+ Reference<XInterface> xDs = dbaccess::getDataSource(_xConnection);
+ if ( dbtools::getDataSourceSetting(xDs,static_cast <OUString> (PROPERTY_BOOLEANCOMPARISONMODE),aValue) )
+ {
+ OSL_VERIFY( aValue >>= m_nBoolCompareMode );
+ }
+ Reference< XQueriesSupplier > xQueriesAccess(m_xConnection, UNO_QUERY);
+ if (xQueriesAccess.is())
+ m_xConnectionQueries = xQueriesAccess->getQueries();
+ }
+ catch(Exception&)
+ {
+ }
+}
+
+OSingleSelectQueryComposer::~OSingleSelectQueryComposer()
+{
+}
+
+// OComponentHelper
+void SAL_CALL OSingleSelectQueryComposer::disposing()
+{
+ OSubComponent::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ resetIterator( m_aSqlIterator );
+ resetIterator( m_aAdditiveIterator );
+
+ m_xConnectionTables = nullptr;
+ m_xConnection = nullptr;
+
+ clearCurrentCollections();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3(OSingleSelectQueryComposer,OSubComponent,OSingleSelectQueryComposer_BASE,OPropertyContainer)
+OUString SAL_CALL OSingleSelectQueryComposer::getImplementationName()
+ {
+ return "org.openoffice.comp.dba.OSingleSelectQueryComposer";
+ }
+sal_Bool SAL_CALL OSingleSelectQueryComposer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OSingleSelectQueryComposer::getSupportedServiceNames()
+{
+ return { SERVICE_NAME_SINGLESELECTQUERYCOMPOSER };
+}
+
+css::uno::Sequence<sal_Int8> OSingleSelectQueryComposer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OSingleSelectQueryComposer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OSubComponent::getTypes( ),
+ OSingleSelectQueryComposer_BASE::getTypes( ),
+ OPropertyContainer::getTypes( )
+ );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OSingleSelectQueryComposer::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+::cppu::IPropertyArrayHelper& OSingleSelectQueryComposer::getInfoHelper()
+{
+ return *OSingleSelectQueryComposer::getArrayHelper();
+}
+::cppu::IPropertyArrayHelper* OSingleSelectQueryComposer::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+// XSingleSelectQueryAnalyzer
+OUString SAL_CALL OSingleSelectQueryComposer::getQuery( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getParseTree);
+ return getStatementPart(F_tmp,m_aSqlIterator);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setQuery( const OUString& command )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_nCommandType = CommandType::COMMAND;
+ // first clear the tables and columns
+ clearCurrentCollections();
+ // now set the new one
+ setQuery_Impl(command);
+ m_sOriginal = command;
+
+ // reset the additive iterator to the same statement
+ parseAndCheck_throwError( m_aSqlParser, m_sOriginal, m_aAdditiveIterator, *this );
+
+ // we have no "elementary" parts anymore (means filter/groupby/having/order clauses)
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ m_aElementaryParts[ eLoopParts ].clear();
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setCommand( const OUString& Command,sal_Int32 _nCommandType )
+{
+ OUStringBuffer sSQL;
+ switch(_nCommandType)
+ {
+ case CommandType::COMMAND:
+ setElementaryQuery(Command);
+ return;
+ case CommandType::TABLE:
+ if ( m_xConnectionTables->hasByName(Command) )
+ {
+ sSQL.append("SELECT * FROM ");
+ Reference< XPropertySet > xTable;
+ try
+ {
+ m_xConnectionTables->getByName( Command ) >>= xTable;
+ }
+ catch(const WrappedTargetException& e)
+ {
+ SQLException e2;
+ if ( e.TargetException >>= e2 )
+ throw e2;
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ sSQL.append(dbtools::composeTableNameForSelect(m_xConnection,xTable));
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_TABLE_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
+ }
+ break;
+ case CommandType::QUERY:
+ if ( m_xConnectionQueries->hasByName(Command) )
+ {
+
+ Reference<XPropertySet> xQuery(m_xConnectionQueries->getByName(Command),UNO_QUERY);
+ OUString sCommand;
+ xQuery->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
+ sSQL.append(sCommand);
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_QUERY_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
+ }
+
+ break;
+ default:
+ break;
+ }
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_nCommandType = _nCommandType;
+ m_sCommand = Command;
+ // first clear the tables and columns
+ clearCurrentCollections();
+ // now set the new one
+ OUString sCommand = sSQL.makeStringAndClear();
+ setElementaryQuery(sCommand);
+ m_sOriginal = sCommand;
+}
+
+void OSingleSelectQueryComposer::setQuery_Impl( const OUString& command )
+{
+ // parse this
+ parseAndCheck_throwError( m_aSqlParser, command, m_aSqlIterator, *this );
+
+ // strip it from all clauses, to have the pure SELECT statement
+ m_aPureSelectSQL = getPureSelectStatement( m_aSqlIterator.getParseTree(), m_xConnection );
+
+ // update tables
+ getTables();
+}
+
+Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredHavingClause( )
+{
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleHavingTree);
+ return getStructuredCondition(F_tmp);
+}
+
+Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredFilter( )
+{
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
+ return getStructuredCondition(F_tmp);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendHavingClauseByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
+{
+ auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetHavingClause);
+ setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendFilterByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
+{
+ auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetFilter);
+ setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
+}
+
+OUString OSingleSelectQueryComposer::impl_getColumnRealName_throw(const Reference< XPropertySet >& column, bool bGroupBy)
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ getColumns();
+ if ( !column.is()
+ || !m_aCurrentColumns[SelectColumns]
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
+ )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
+ SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any(aErr) );
+ }
+
+ OUString aName, aNewName;
+ column->getPropertyValue(PROPERTY_NAME) >>= aName;
+
+ if ( bGroupBy &&
+ !m_xMetaData->supportsGroupByUnrelated() &&
+ m_aCurrentColumns[SelectColumns] &&
+ !m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
+ throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
+ }
+
+ OUString aQuote = m_xMetaData->getIdentifierQuoteString();
+ if ( m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ Reference<XPropertySet> xColumn;
+ m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName("Function"),"Property FUNCTION not available!");
+
+ OUString sRealName, sTableName;
+ xColumn->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
+ bool bFunction = false;
+ xColumn->getPropertyValue("Function") >>= bFunction;
+ if ( sRealName == aName )
+ {
+ if ( bFunction )
+ aNewName = aName;
+ else
+ {
+ if(sTableName.indexOf('.') != -1)
+ {
+ OUString aCatlog,aSchema,aTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
+ sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ else if (!sTableName.isEmpty())
+ sTableName = ::dbtools::quoteName(aQuote,sTableName);
+
+ if(sTableName.isEmpty())
+ aNewName = ::dbtools::quoteName(aQuote,sRealName);
+ else
+ aNewName = sTableName + "." + ::dbtools::quoteName(aQuote,sRealName);
+ }
+ }
+ else
+ aNewName = ::dbtools::quoteName(aQuote,aName);
+ }
+ else
+ aNewName = getTableAlias(column) + ::dbtools::quoteName(aQuote,aName);
+ return aNewName;
+}
+
+OUString OSingleSelectQueryComposer::impl_getColumnNameOrderBy_throw(const Reference< XPropertySet >& column)
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ getColumns();
+ if ( !column.is()
+ || !m_aCurrentColumns[SelectColumns]
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
+ )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
+ SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any(aErr) );
+ }
+
+ OUString aName;
+ column->getPropertyValue(PROPERTY_NAME) >>= aName;
+
+ const OUString aQuote = m_xMetaData->getIdentifierQuoteString();
+
+ if ( m_aCurrentColumns[SelectColumns] &&
+ m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ // It is a column from the SELECT list, use it as such.
+ return ::dbtools::quoteName(aQuote,aName);
+ }
+
+ // Nope, it is an unrelated column.
+ // Is that supported?
+ if ( !m_xMetaData->supportsOrderByUnrelated() )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
+ throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
+ }
+
+ // We need to refer to it by its "real" name, that is by schemaName.tableName.columnNameInTable
+ return impl_getColumnRealName_throw(column, false);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendOrderByColumn( const Reference< XPropertySet >& column, sal_Bool ascending )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OUString sColumnName( impl_getColumnNameOrderBy_throw(column) );
+ OUString sOrder = getOrder();
+ if ( !(sOrder.isEmpty() || sColumnName.isEmpty()) )
+ sOrder += COMMA;
+ sOrder += sColumnName;
+ if ( !(ascending || sColumnName.isEmpty()) )
+ sOrder += " DESC ";
+
+ setOrder(sOrder);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendGroupByColumn( const Reference< XPropertySet >& column)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OUString sColumnName( impl_getColumnRealName_throw(column, true) );
+ OrderCreator aComposer;
+ aComposer.append( getGroup() );
+ aComposer.append( sColumnName );
+ setGroup( aComposer.getComposedAndClear() );
+}
+
+OUString OSingleSelectQueryComposer::composeStatementFromParts( const std::vector< OUString >& _rParts )
+{
+ OSL_ENSURE( _rParts.size() == size_t(SQLPartCount), "OSingleSelectQueryComposer::composeStatementFromParts: invalid parts array!" );
+
+ OUStringBuffer aSql( m_aPureSelectSQL );
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ if ( !_rParts[ eLoopParts ].isEmpty() )
+ {
+ aSql.append( getKeyword( eLoopParts ) );
+ aSql.append( _rParts[ eLoopParts ] );
+ }
+
+ return aSql.makeStringAndClear();
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getElementaryQuery()
+{
+ return composeStatementFromParts( m_aElementaryParts );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setElementaryQuery( const OUString& _rElementary )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // remember the 4 current "additive" clauses
+ std::vector< OUString > aAdditiveClauses( SQLPartCount );
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aAdditiveClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, false );
+
+ // clear the tables and columns
+ clearCurrentCollections();
+ // set and parse the new query
+ setQuery_Impl( _rElementary );
+
+ // get the 4 elementary parts of the statement
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ m_aElementaryParts[ eLoopParts ] = getSQLPart( eLoopParts, m_aSqlIterator, false );
+
+ // reset the AdditiveIterator: m_aPureSelectSQL may have changed
+ try
+ {
+ parseAndCheck_throwError( m_aSqlParser, composeStatementFromParts( aAdditiveClauses ), m_aAdditiveIterator, *this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setElementaryQuery: there should be no error anymore for the additive statement!" );
+ // every part of the additive statement should have passed other tests already, and should not
+ // be able to cause any errors ... me thinks
+ }
+}
+
+namespace
+{
+ OUString getComposedClause( const OUString& _rElementaryClause, const OUString& _rAdditionalClause,
+ TokenComposer& _rComposer, std::u16string_view _rKeyword )
+ {
+ _rComposer.clear();
+ _rComposer.append( _rElementaryClause );
+ _rComposer.append( _rAdditionalClause );
+ OUString sComposed = _rComposer.getComposedAndClear();
+ if ( !sComposed.isEmpty() )
+ sComposed = _rKeyword + sComposed;
+ return sComposed;
+ }
+}
+
+void OSingleSelectQueryComposer::setSingleAdditiveClause( SQLPart _ePart, const OUString& _rClause )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // if nothing is changed, do nothing
+ if ( getSQLPart( _ePart, m_aAdditiveIterator, false ) == _rClause )
+ return;
+
+ // collect the 4 single parts as they're currently set
+ std::vector< OUString > aClauses;
+ aClauses.reserve( size_t(SQLPartCount) );
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aClauses.push_back( getSQLPart( eLoopParts, m_aSqlIterator, true ) );
+
+ // overwrite the one part in question here
+ std::unique_ptr< TokenComposer > pComposer;
+ if ( ( _ePart == Where ) || ( _ePart == Having ) )
+ pComposer.reset( new FilterCreator );
+ else
+ pComposer.reset( new OrderCreator );
+ aClauses[ _ePart ] = getComposedClause( m_aElementaryParts[ _ePart ], _rClause,
+ *pComposer, getKeyword( _ePart ) );
+
+ // construct the complete statement
+ OUStringBuffer aSql(m_aPureSelectSQL);
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aSql.append(aClauses[ eLoopParts ]);
+
+ // set the query
+ setQuery_Impl(aSql.makeStringAndClear());
+
+ // clear column collections which (might) have changed
+ clearColumns( ParameterColumns );
+ if ( _ePart == Order )
+ clearColumns( OrderColumns );
+ else if ( _ePart == Group )
+ clearColumns( GroupByColumns );
+
+ // also, since the "additive filter" change, we need to rebuild our "additive" statement
+ aSql = m_aPureSelectSQL;
+ // again, first get all the old additive parts
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, true );
+ // then overwrite the one in question
+ aClauses[ _ePart ] = getComposedClause( OUString(), _rClause, *pComposer, getKeyword( _ePart ) );
+ // and parse it, so that m_aAdditiveIterator is up to date
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aSql.append(aClauses[ eLoopParts ]);
+ try
+ {
+ parseAndCheck_throwError( m_aSqlParser, aSql.makeStringAndClear(), m_aAdditiveIterator, *this );
+ }
+ catch( const Exception& )
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setSingleAdditiveClause: there should be no error anymore for the additive statement!" );
+ // every part of the additive statement should have passed other tests already, and should not
+ // be able to cause any errors ... me thinks
+ }
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setFilter( const OUString& filter )
+{
+ setSingleAdditiveClause( Where, filter );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setOrder( const OUString& order )
+{
+ setSingleAdditiveClause( Order, order );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setGroup( const OUString& group )
+{
+ setSingleAdditiveClause( Group, group );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setHavingClause( const OUString& filter )
+{
+ setSingleAdditiveClause( Having, filter );
+}
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getTables( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_pTables )
+ {
+ const OSQLTables& aTables = m_aSqlIterator.getTables();
+ std::vector< OUString> aNames;
+ for (auto const& elem : aTables)
+ aNames.push_back(elem.first);
+
+ m_pTables.reset( new OPrivateTables(aTables,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,std::move(aNames)) );
+ }
+
+ return m_pTables.get();
+}
+
+// XColumnsSupplier
+Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getColumns( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !!m_aCurrentColumns[SelectColumns] )
+ return m_aCurrentColumns[SelectColumns].get();
+
+ std::vector< OUString> aNames;
+ ::rtl::Reference< OSQLColumns> aSelectColumns;
+ bool bCase = true;
+ Reference< XNameAccess> xQueryColumns;
+ if ( m_nCommandType == CommandType::QUERY )
+ {
+ Reference<XColumnsSupplier> xSup(m_xConnectionQueries->getByName(m_sCommand),UNO_QUERY);
+ if(xSup.is())
+ xQueryColumns = xSup->getColumns();
+ }
+
+ do {
+
+ try
+ {
+ SharedUNOComponent< XStatement, DisposableComponent > xStatement;
+ SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
+
+ bCase = m_xMetaData->supportsMixedCaseQuotedIdentifiers();
+ aSelectColumns = m_aSqlIterator.getSelectColumns();
+
+ OUStringBuffer aSQL( m_aPureSelectSQL + STR_WHERE + " ( 0 = 1 )");
+
+ // preserve the original WHERE clause
+ // #i102234#
+ OUString sOriginalWhereClause = getSQLPart( Where, m_aSqlIterator, false );
+ if ( !sOriginalWhereClause.isEmpty() )
+ {
+ aSQL.append( " AND ( " + sOriginalWhereClause + " ) " );
+ }
+
+ OUString sGroupBy = getSQLPart( Group, m_aSqlIterator, true );
+ if ( !sGroupBy.isEmpty() )
+ aSQL.append( sGroupBy );
+
+ OUString sSQL( aSQL.makeStringAndClear() );
+ // normalize the statement so that it doesn't contain any application-level features anymore
+ OUString sError;
+ const std::unique_ptr< OSQLParseNode > pStatementTree( m_aSqlParser.parseTree( sError, sSQL ) );
+ OSL_ENSURE(pStatementTree, "OSingleSelectQueryComposer::getColumns: could not parse the "
+ "column retrieval statement!");
+ if (pStatementTree)
+ if ( !pStatementTree->parseNodeToExecutableStatement( sSQL, m_xConnection, m_aSqlParser, nullptr ) )
+ break;
+
+ Reference< XResultSetMetaData > xResultSetMeta;
+ Reference< XResultSetMetaDataSupplier > xResMetaDataSup;
+ try
+ {
+ xPreparedStatement.set( m_xConnection->prepareStatement( sSQL ), UNO_QUERY_THROW );
+ xResMetaDataSup.set( xPreparedStatement, UNO_QUERY_THROW );
+ xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
+ }
+ catch( const Exception& ) { }
+
+ if ( !xResultSetMeta.is() && xPreparedStatement.is() )
+ {
+ try
+ {
+ //@see issue http://qa.openoffice.org/issues/show_bug.cgi?id=110111
+ // access returns a different order of column names when executing select * from
+ // and asking the columns from the metadata.
+ Reference< XParameters > xParameters( xPreparedStatement, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xPara = getParameters();
+ for(sal_Int32 i = 1;i <= xPara->getCount();++i)
+ xParameters->setNull(i,DataType::VARCHAR);
+ xResMetaDataSup.set(xPreparedStatement->executeQuery(), UNO_QUERY_THROW );
+ xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
+ }
+ catch( const Exception& ) { }
+ }
+
+ if ( !xResultSetMeta.is() )
+ {
+ xStatement.reset( Reference< XStatement >( m_xConnection->createStatement(), UNO_SET_THROW ) );
+ Reference< XPropertySet > xStatementProps( xStatement, UNO_QUERY_THROW );
+ try { xStatementProps->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, Any( false ) ); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
+ xResMetaDataSup.set( xStatement->executeQuery( sSQL ), UNO_QUERY_THROW );
+ xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
+
+ if (xResultSetMeta.is())
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getColumns failed to get xResultSetMeta from executed PreparedStatement, but got it from 'no escape processing' statement. SQL command:\n\t" << sSQL );
+ }
+ }
+
+ if ( aSelectColumns->empty() )
+ {
+ // This is a valid case. If we can syntactically parse the query, but not semantically
+ // (e.g. because it is based on a table we do not know), then there will be no SelectColumns
+ aSelectColumns = ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, m_xMetaData ,xQueryColumns);
+ break;
+ }
+
+ const ::comphelper::UStringMixEqual aCaseCompare( bCase );
+ std::set< size_t > aUsedSelectColumns;
+ ::connectivity::parse::OParseColumn::StringMap aColumnNames;
+
+ sal_Int32 nCount = xResultSetMeta->getColumnCount();
+ OSL_ENSURE( static_cast<size_t>(nCount) == aSelectColumns->size(), "OSingleSelectQueryComposer::getColumns: inconsistent column counts, this might result in wrong columns!" );
+ for(sal_Int32 i=1;i<=nCount;++i)
+ {
+ OUString sColumnName = xResultSetMeta->getColumnName(i);
+ OUString sColumnLabel;
+ if ( xQueryColumns.is() && xQueryColumns->hasByName(sColumnName) )
+ {
+ Reference<XPropertySet> xQueryColumn(xQueryColumns->getByName(sColumnName),UNO_QUERY_THROW);
+ xQueryColumn->getPropertyValue(PROPERTY_LABEL) >>= sColumnLabel;
+ }
+ else
+ sColumnLabel = xResultSetMeta->getColumnLabel(i);
+ bool bFound = false;
+ OSQLColumns::Vector::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),sColumnLabel,aCaseCompare);
+ size_t nFoundSelectColumnPos = aFind - aSelectColumns->begin();
+ if ( aFind != aSelectColumns->end() )
+ {
+ if ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
+ { // we found a column name which exists twice
+ // so we start after the first found
+ do
+ {
+ aFind = ::connectivity::findRealName(++aFind,aSelectColumns->end(),sColumnName,aCaseCompare);
+ nFoundSelectColumnPos = aFind - aSelectColumns->begin();
+ }
+ while ( ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
+ && ( aFind != aSelectColumns->end() )
+ );
+ }
+ if ( aFind != aSelectColumns->end() )
+ {
+ (*aFind)->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
+ aUsedSelectColumns.insert( nFoundSelectColumnPos );
+ aNames.push_back(sColumnName);
+ bFound = true;
+ }
+ }
+
+ if ( bFound )
+ continue;
+
+ OSQLColumns::Vector::const_iterator aRealFind = ::connectivity::findRealName(
+ aSelectColumns->begin(), aSelectColumns->end(), sColumnName, aCaseCompare );
+
+ if ( i > static_cast< sal_Int32>( aSelectColumns->size() ) )
+ {
+ aSelectColumns->emplace_back(::connectivity::parse::OParseColumn::createColumnForResultSet( xResultSetMeta, m_xMetaData, i ,aColumnNames)
+ );
+ OSL_ENSURE( aSelectColumns->size() == static_cast<size_t>(i), "OSingleSelectQueryComposer::getColumns: inconsistency!" );
+ }
+ else if ( aRealFind == aSelectColumns->end() )
+ {
+ // we can now only look if we found it under the realname property
+ // here we have to make the assumption that the position is correct
+ OSQLColumns::Vector::const_iterator aFind2 = aSelectColumns->begin() + i-1;
+ Reference<XPropertySet> xProp = *aFind2;
+ if ( !xProp.is() || !xProp->getPropertySetInfo()->hasPropertyByName( PROPERTY_REALNAME ) )
+ continue;
+
+ rtl::Reference<::connectivity::parse::OParseColumn> pColumn = new ::connectivity::parse::OParseColumn(xProp,bCase);
+ pColumn->setFunction(::comphelper::getBOOL(xProp->getPropertyValue("Function")));
+ pColumn->setAggregateFunction(::comphelper::getBOOL(xProp->getPropertyValue("AggregateFunction")));
+
+ OUString sRealName;
+ xProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ if ( sColumnName.isEmpty() )
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
+
+ sal_Int32 j = 0;
+ while ( std::any_of(aNames.begin(),aNames.end(),
+ [&aCaseCompare, &sColumnName](const OUString& lhs)
+ { return aCaseCompare(lhs, sColumnName); } ) )
+ {
+ sColumnName += OUString::number(++j);
+ }
+
+ pColumn->setName(sColumnName);
+ pColumn->setRealName(sRealName);
+ pColumn->setTableName(::comphelper::getString(xProp->getPropertyValue(PROPERTY_TABLENAME)));
+
+ (*aSelectColumns)[i-1] = pColumn;
+ }
+ else
+ continue;
+
+ aUsedSelectColumns.insert( static_cast<size_t>(i - 1) );
+ aNames.push_back( sColumnName );
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+
+ } while ( false );
+
+ bool bMissingSomeColumnLabels = !aNames.empty() && aNames.size() != aSelectColumns->size();
+ SAL_WARN_IF(bMissingSomeColumnLabels, "dbaccess", "We have column labels for *some* columns but not all");
+ //^^this happens in the evolution address book where we have real column names of e.g.
+ //first_name, second_name and city. On parsing via
+ //OSQLParseTreeIterator::appendColumns it creates some labels using those real names
+ //but the evo address book gives them proper labels of First Name, Second Name and City
+ //the munge means that here we have e.g. just "City" as a label because it matches
+
+ //This is all a horrible mess
+ if (bMissingSomeColumnLabels)
+ aNames.clear();
+
+ if ( aNames.empty() )
+ m_aCurrentColumns[ SelectColumns ] = OPrivateColumns::createWithIntrinsicNames( aSelectColumns, bCase, *this, m_aMutex );
+ else
+ m_aCurrentColumns[ SelectColumns ].reset( new OPrivateColumns( aSelectColumns, bCase, *this, m_aMutex, aNames ) );
+
+ return m_aCurrentColumns[SelectColumns].get();
+}
+
+bool OSingleSelectQueryComposer::setORCriteria(OSQLParseNode const * pCondition, OSQLParseTreeIterator& _rIterator,
+ std::vector< std::vector < PropertyValue > >& rFilters, const Reference< css::util::XNumberFormatter > & xFormatter) const
+{
+ // Round brackets around the expression
+ if (pCondition->count() == 3 &&
+ SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
+ {
+ return setORCriteria(pCondition->getChild(1), _rIterator, rFilters, xFormatter);
+ }
+ // OR logic expression
+ // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
+ else if (SQL_ISRULE(pCondition,search_condition))
+ {
+ bool bResult = true;
+ for (int i = 0; bResult && i < 3; i+=2)
+ {
+ // Is the first element a OR logic expression again?
+ // Then descend recursively ...
+ if (SQL_ISRULE(pCondition->getChild(i),search_condition))
+ bResult = setORCriteria(pCondition->getChild(i), _rIterator, rFilters, xFormatter);
+ else
+ {
+ rFilters.emplace_back();
+ bResult = setANDCriteria(pCondition->getChild(i), _rIterator, rFilters[rFilters.size() - 1], xFormatter);
+ }
+ }
+ return bResult;
+ }
+ else
+ {
+ rFilters.emplace_back();
+ return setANDCriteria(pCondition, _rIterator, rFilters[rFilters.size() - 1], xFormatter);
+ }
+}
+
+bool OSingleSelectQueryComposer::setANDCriteria( OSQLParseNode const * pCondition,
+ OSQLParseTreeIterator& _rIterator, std::vector < PropertyValue >& rFilter, const Reference< XNumberFormatter > & xFormatter) const
+{
+ // Round brackets
+ if (SQL_ISRULE(pCondition,boolean_primary))
+ {
+ // this should not occur
+ SAL_WARN("dbaccess","boolean_primary in And-Criteria");
+ return false;
+ }
+ // The first element is an AND logical expression again
+ else if ( SQL_ISRULE(pCondition,boolean_term) && pCondition->count() == 3 )
+ {
+ return setANDCriteria(pCondition->getChild(0), _rIterator, rFilter, xFormatter) &&
+ setANDCriteria(pCondition->getChild(2), _rIterator, rFilter, xFormatter);
+ }
+ else if (SQL_ISRULE(pCondition, comparison_predicate))
+ {
+ return setComparisonPredicate(pCondition,_rIterator,rFilter,xFormatter);
+ }
+ else if (SQL_ISRULE(pCondition,like_predicate))
+ {
+ return setLikePredicate(pCondition,_rIterator,rFilter,xFormatter);
+ }
+ else if (SQL_ISRULE(pCondition,test_for_null) ||
+ SQL_ISRULE(pCondition,in_predicate) ||
+ SQL_ISRULE(pCondition,all_or_any_predicate) ||
+ SQL_ISRULE(pCondition,between_predicate))
+ {
+ if (SQL_ISRULE(pCondition->getChild(0), column_ref))
+ {
+ PropertyValue aItem;
+ OUString aValue;
+ OUString aColumnName;
+
+ pCondition->parseNodeToStr( aValue, m_xConnection );
+ pCondition->getChild(0)->parseNodeToStr( aColumnName, m_xConnection );
+
+ // don't display the column name
+ aValue = aValue.copy(aColumnName.getLength());
+ aValue = aValue.trim();
+
+ aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
+ aItem.Value <<= aValue;
+ aItem.Handle = 0; // just to know that this is not one the known ones
+ if ( SQL_ISRULE(pCondition,like_predicate) )
+ {
+ if ( SQL_ISTOKEN(pCondition->getChild(1)->getChild(0),NOT) )
+ aItem.Handle = SQLFilterOperator::NOT_LIKE;
+ else
+ aItem.Handle = SQLFilterOperator::LIKE;
+ }
+ else if (SQL_ISRULE(pCondition,test_for_null))
+ {
+ if (SQL_ISTOKEN(pCondition->getChild(1)->getChild(1),NOT) )
+ aItem.Handle = SQLFilterOperator::NOT_SQLNULL;
+ else
+ aItem.Handle = SQLFilterOperator::SQLNULL;
+ }
+ else if (SQL_ISRULE(pCondition,in_predicate))
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: in_predicate not implemented!" );
+ }
+ else if (SQL_ISRULE(pCondition,all_or_any_predicate))
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: all_or_any_predicate not implemented!" );
+ }
+ else if (SQL_ISRULE(pCondition,between_predicate))
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: between_predicate not implemented!" );
+ }
+
+ rFilter.push_back(aItem);
+ }
+ else
+ return false;
+ }
+ else if (SQL_ISRULE(pCondition,existence_test) ||
+ SQL_ISRULE(pCondition,unique_test))
+ {
+ // this couldn't be handled here, too complex
+ // as we need a field name
+ return false;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+sal_Int32 OSingleSelectQueryComposer::getPredicateType(OSQLParseNode const * _pPredicate)
+{
+ sal_Int32 nPredicate = SQLFilterOperator::EQUAL;
+ switch (_pPredicate->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ nPredicate = SQLFilterOperator::EQUAL;
+ break;
+ case SQLNodeType::NotEqual:
+ nPredicate = SQLFilterOperator::NOT_EQUAL;
+ break;
+ case SQLNodeType::Less:
+ nPredicate = SQLFilterOperator::LESS;
+ break;
+ case SQLNodeType::LessEq:
+ nPredicate = SQLFilterOperator::LESS_EQUAL;
+ break;
+ case SQLNodeType::Great:
+ nPredicate = SQLFilterOperator::GREATER;
+ break;
+ case SQLNodeType::GreatEq:
+ nPredicate = SQLFilterOperator::GREATER_EQUAL;
+ break;
+ default:
+ SAL_WARN("dbaccess","Wrong NodeType!");
+ }
+ return nPredicate;
+}
+
+bool OSingleSelectQueryComposer::setLikePredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
+ std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
+{
+ OSL_ENSURE(SQL_ISRULE(pCondition, like_predicate),"setLikePredicate: pCondition is not a LikePredicate");
+
+ assert(pCondition->count() == 2);
+ OSQLParseNode const *pRowValue = pCondition->getChild(0);
+ OSQLParseNode const *pPart2 = pCondition->getChild(1);
+
+ PropertyValue aItem;
+ if ( SQL_ISTOKEN(pPart2->getChild(0),NOT) )
+ aItem.Handle = SQLFilterOperator::NOT_LIKE;
+ else
+ aItem.Handle = SQLFilterOperator::LIKE;
+
+ if (SQL_ISRULE(pRowValue, column_ref))
+ {
+ OUString aValue;
+
+ // skip (optional "NOT") and "LIKE"
+ for (size_t i=2; i < pPart2->count(); i++)
+ {
+ pPart2->getChild(i)->parseNodeToPredicateStr(
+ aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ }
+
+ aItem.Name = getColumnName(pRowValue,_rIterator);
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ else if (SQL_ISRULE(pRowValue, set_fct_spec ) ||
+ SQL_ISRULE(pRowValue, general_set_fct))
+ {
+ OUString aValue;
+ OUString aColumnName;
+
+ pPart2->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pRowValue->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = getColumnName(pRowValue,_rIterator);
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ else // Can only be an expression
+ {
+ OUString aName, aValue;
+
+ OSQLParseNode const *pValue = pPart2->getChild(2);
+
+ // Field names
+ for (size_t i=0;i< pRowValue->count();i++)
+ pRowValue->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ // Criterion
+ for(size_t i=0;i< pValue->count();i++)
+ pValue->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = aName;
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ return true;
+}
+
+bool OSingleSelectQueryComposer::setComparisonPredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
+ std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
+{
+ OSL_ENSURE(SQL_ISRULE(pCondition, comparison_predicate),"setComparisonPredicate: pCondition is not a ComparisonPredicate");
+ if (SQL_ISRULE(pCondition->getChild(0), column_ref) ||
+ SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
+ {
+ PropertyValue aItem;
+ OUString aValue;
+ sal_uInt32 nPos;
+ if (SQL_ISRULE(pCondition->getChild(0), column_ref))
+ {
+ nPos = 0;
+ size_t i=1;
+
+ aItem.Handle = getPredicateType(pCondition->getChild(i));
+
+ // go forward - don't display the operator
+ for (i++;i < pCondition->count();i++)
+ pCondition->getChild(i)->parseNodeToPredicateStr(
+ aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ }
+ else if (SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
+ {
+ nPos = pCondition->count()-1;
+
+ sal_Int32 i = pCondition->count() - 2;
+ switch (pCondition->getChild(i)->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ aItem.Handle = SQLFilterOperator::EQUAL;
+ break;
+ case SQLNodeType::NotEqual:
+ aItem.Handle = SQLFilterOperator::NOT_EQUAL;
+ break;
+ case SQLNodeType::Less:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::GREATER_EQUAL;
+ break;
+ case SQLNodeType::LessEq:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::GREATER;
+ break;
+ case SQLNodeType::Great:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::LESS_EQUAL;
+ break;
+ case SQLNodeType::GreatEq:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::LESS;
+ break;
+ default:
+ break;
+ }
+
+ // go backward - don't display the operator
+ for (i--; i >= 0; i--)
+ pCondition->getChild(i)->parseNodeToPredicateStr(
+ aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ }
+ else
+ return false;
+
+ aItem.Name = getColumnName(pCondition->getChild(nPos),_rIterator);
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ else if (SQL_ISRULE(pCondition->getChild(0), set_fct_spec ) ||
+ SQL_ISRULE(pCondition->getChild(0), general_set_fct))
+ {
+ PropertyValue aItem;
+ OUString aValue;
+ OUString aColumnName;
+
+ pCondition->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pCondition->getChild(0)->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
+ aItem.Value <<= aValue;
+ aItem.Handle = getPredicateType(pCondition->getChild(1));
+ rFilter.push_back(aItem);
+ }
+ else // Can only be an expression
+ {
+ PropertyValue aItem;
+ OUString aName, aValue;
+
+ OSQLParseNode *pLhs = pCondition->getChild(0);
+ OSQLParseNode *pRhs = pCondition->getChild(2);
+
+ // Field names
+ for (size_t i=0;i< pLhs->count();i++)
+ pLhs->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ // Criterion
+ aItem.Handle = getPredicateType(pCondition->getChild(1));
+ for(size_t i=0;i< pRhs->count();i++)
+ pRhs->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = aName;
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ return true;
+}
+
+// Functions for analysing SQL
+OUString OSingleSelectQueryComposer::getColumnName( ::connectivity::OSQLParseNode const * pColumnRef, OSQLParseTreeIterator const & _rIterator )
+{
+ OUString aTableRange, aColumnName;
+ _rIterator.getColumnRange(pColumnRef,aColumnName,aTableRange);
+ return aColumnName;
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getFilter( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Where,m_aAdditiveIterator,false);
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getOrder( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Order,m_aAdditiveIterator,false);
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getGroup( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Group,m_aAdditiveIterator,false);
+}
+
+OUString OSingleSelectQueryComposer::getHavingClause()
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Having,m_aAdditiveIterator,false);
+}
+
+OUString OSingleSelectQueryComposer::getTableAlias(const Reference< XPropertySet >& column) const
+{
+ OUString sReturn;
+ if(m_pTables && m_pTables->getCount() > 1)
+ {
+ OUString aCatalog,aSchema,aTable,aColumnName;
+ if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_CATALOGNAME))
+ column->getPropertyValue(PROPERTY_CATALOGNAME) >>= aCatalog;
+ if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_SCHEMANAME))
+ column->getPropertyValue(PROPERTY_SCHEMANAME) >>= aSchema;
+ if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME))
+ column->getPropertyValue(PROPERTY_TABLENAME) >>= aTable;
+ column->getPropertyValue(PROPERTY_NAME) >>= aColumnName;
+
+ Sequence< OUString> aNames(m_pTables->getElementNames());
+ const OUString* pBegin = aNames.getConstArray();
+ const OUString* const pEnd = pBegin + aNames.getLength();
+
+ if(aTable.isEmpty())
+ { // we haven't found a table name, now we must search every table for this column
+ for(;pBegin != pEnd;++pBegin)
+ {
+ Reference<XColumnsSupplier> xColumnsSupp;
+ m_pTables->getByName(*pBegin) >>= xColumnsSupp;
+
+ if(xColumnsSupp.is() && xColumnsSupp->getColumns()->hasByName(aColumnName))
+ {
+ aTable = *pBegin;
+ break;
+ }
+ }
+ }
+ else
+ {
+ OUString aComposedName = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, false, ::dbtools::EComposeRule::InDataManipulation );
+
+ // Is this the right case for the table name?
+ // Else, look for it with different case, if applicable.
+
+ if(!m_pTables->hasByName(aComposedName))
+ {
+ ::comphelper::UStringMixLess aTmp(m_aAdditiveIterator.getTables().key_comp());
+ ::comphelper::UStringMixEqual aComp(aTmp.isCaseSensitive());
+ for(;pBegin != pEnd;++pBegin)
+ {
+ Reference<XPropertySet> xTableProp;
+ m_pTables->getByName(*pBegin) >>= xTableProp;
+ OSL_ENSURE(xTableProp.is(),"Table isn't a propertyset!");
+ if(xTableProp.is())
+ {
+ OUString aCatalog2,aSchema2,aTable2;
+ xTableProp->getPropertyValue(PROPERTY_CATALOGNAME) >>= aCatalog2;
+ xTableProp->getPropertyValue(PROPERTY_SCHEMANAME) >>= aSchema2;
+ xTableProp->getPropertyValue(PROPERTY_NAME) >>= aTable2;
+ if(aComp(aCatalog,aCatalog2) && aComp(aSchema,aSchema2) && aComp(aTable,aTable2))
+ {
+ aCatalog = aCatalog2;
+ aSchema = aSchema2;
+ aTable = aTable2;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(pBegin != pEnd)
+ {
+ sReturn = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ) + ".";
+ }
+ }
+ return sReturn;
+}
+
+Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getParameters( )
+{
+ // now set the Parameters
+ if ( !m_aCurrentColumns[ParameterColumns] )
+ {
+ ::rtl::Reference< OSQLColumns> aCols = m_aSqlIterator.getParameters();
+ std::vector< OUString> aNames;
+ for (auto const& elem : *aCols)
+ aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
+ m_aCurrentColumns[ParameterColumns].reset( new OPrivateColumns(aCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
+ }
+
+ return m_aCurrentColumns[ParameterColumns].get();
+}
+
+void OSingleSelectQueryComposer::clearColumns( const EColumnType _eType )
+{
+ OPrivateColumns* pColumns = m_aCurrentColumns[ _eType ].get();
+ if ( pColumns != nullptr )
+ {
+ pColumns->disposing();
+ m_aColumnsCollection.push_back( std::move(m_aCurrentColumns[ _eType ]) );
+ }
+}
+
+void OSingleSelectQueryComposer::clearCurrentCollections()
+{
+ for (auto & currentColumn : m_aCurrentColumns)
+ {
+ if (currentColumn)
+ {
+ currentColumn->disposing();
+ m_aColumnsCollection.push_back(std::move(currentColumn));
+ }
+ }
+
+ if(m_pTables)
+ {
+ m_pTables->disposing();
+ m_aTablesCollection.push_back(std::move(m_pTables));
+ }
+}
+
+Reference< XIndexAccess > OSingleSelectQueryComposer::setCurrentColumns( EColumnType _eType,
+ const ::rtl::Reference< OSQLColumns >& _rCols )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // now set the group columns
+ if ( !m_aCurrentColumns[_eType] )
+ {
+ std::vector< OUString> aNames;
+ for (auto const& elem : *_rCols)
+ aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
+ m_aCurrentColumns[_eType].reset( new OPrivateColumns(_rCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
+ }
+
+ return m_aCurrentColumns[_eType].get();
+}
+
+Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getGroupColumns( )
+{
+ return setCurrentColumns( GroupByColumns, m_aAdditiveIterator.getGroupColumns() );
+}
+
+Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getOrderColumns( )
+{
+ return setCurrentColumns( OrderColumns, m_aAdditiveIterator.getOrderColumns() );
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getQueryWithSubstitution( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ OUString sSqlStatement( getQuery() );
+
+ const OSQLParseNode* pStatementNode = m_aSqlIterator.getParseTree();
+ if ( pStatementNode )
+ {
+ SQLException aError;
+ if ( !pStatementNode->parseNodeToExecutableStatement( sSqlStatement, m_xConnection, m_aSqlParser, &aError ) )
+ throw aError;
+ }
+
+ return sSqlStatement;
+}
+
+OUString OSingleSelectQueryComposer::getStatementPart( TGetParseNode const & _aGetFunctor, OSQLParseTreeIterator& _rIterator )
+{
+ OUString sResult;
+
+ const OSQLParseNode* pNode = _aGetFunctor( &_rIterator );
+ if ( pNode )
+ pNode->parseNodeToStr( sResult, m_xConnection );
+
+ return sResult;
+}
+
+namespace
+{
+ OUString lcl_getDecomposedColumnName(const OUString& rComposedName, const OUString& rQuoteString)
+ {
+ const sal_Int32 nQuoteLength = rQuoteString.getLength();
+ OUString sName = rComposedName.trim();
+ OUString sColumnName;
+ sal_Int32 nPos, nRPos = 0;
+
+ for (;;)
+ {
+ nPos = sName.indexOf( rQuoteString, nRPos );
+ if ( nPos >= 0 )
+ {
+ nRPos = sName.indexOf( rQuoteString, nPos + nQuoteLength );
+ if ( nRPos > nPos )
+ {
+ if ( nRPos + nQuoteLength < sName.getLength() )
+ {
+ nRPos += nQuoteLength; // -1 + 1 skip dot
+ }
+ else
+ {
+ sColumnName = sName.copy( nPos + nQuoteLength, nRPos - nPos - nQuoteLength );
+ break;
+ }
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ return sColumnName.isEmpty() ? rComposedName : sColumnName;
+ }
+
+ OUString lcl_getCondition(const Sequence< Sequence< PropertyValue > >& filter,
+ const OPredicateInputController& i_aPredicateInputController,
+ const Reference< XNameAccess >& i_xSelectColumns,
+ const OUString& rQuoteString)
+ {
+ OUStringBuffer sRet;
+ const Sequence< PropertyValue >* pOrIter = filter.getConstArray();
+ const Sequence< PropertyValue >* pOrEnd = pOrIter + filter.getLength();
+ while ( pOrIter != pOrEnd )
+ {
+ if ( pOrIter->hasElements() )
+ {
+ sRet.append(L_BRACKET);
+ const PropertyValue* pAndIter = pOrIter->getConstArray();
+ const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength();
+ while ( pAndIter != pAndEnd )
+ {
+ sRet.append(pAndIter->Name);
+ OUString sValue;
+ pAndIter->Value >>= sValue;
+ const OUString sColumnName = lcl_getDecomposedColumnName( pAndIter->Name, rQuoteString );
+ if ( i_xSelectColumns.is() && i_xSelectColumns->hasByName(sColumnName) )
+ {
+ Reference<XPropertySet> xColumn(i_xSelectColumns->getByName(sColumnName),UNO_QUERY);
+ sValue = i_aPredicateInputController.getPredicateValueStr(sValue,xColumn);
+ }
+ else
+ {
+ sValue = i_aPredicateInputController.getPredicateValueStr(pAndIter->Name,sValue);
+ }
+ lcl_addFilterCriteria_throw(pAndIter->Handle,sValue,sRet);
+ ++pAndIter;
+ if ( pAndIter != pAndEnd )
+ sRet.append(STR_AND);
+ }
+ sRet.append(R_BRACKET);
+ }
+ ++pOrIter;
+ if ( pOrIter != pOrEnd && !sRet.isEmpty() )
+ sRet.append(STR_OR);
+ }
+ return sRet.makeStringAndClear();
+ }
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setStructuredFilter( const Sequence< Sequence< PropertyValue > >& filter )
+{
+ OPredicateInputController aPredicateInput(m_aContext, m_xConnection, &m_aParseContext);
+ setFilter(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setStructuredHavingClause( const Sequence< Sequence< PropertyValue > >& filter )
+{
+ OPredicateInputController aPredicateInput(m_aContext, m_xConnection);
+ setHavingClause(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
+}
+
+void OSingleSelectQueryComposer::setConditionByColumn( const Reference< XPropertySet >& column, bool andCriteria, std::function<bool(OSingleSelectQueryComposer *, const OUString&)> const & _aSetFunctor, sal_Int32 filterOperator)
+{
+ try
+ {
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ if ( !column.is()
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_VALUE)
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE))
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ sal_Int32 nType = 0;
+ column->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ sal_Int32 nSearchable = dbtools::getSearchColumnFlag(m_xConnection,nType);
+ if(nSearchable == ColumnSearch::NONE)
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_SEARCHABLE),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OUString aName;
+ column->getPropertyValue(PROPERTY_NAME) >>= aName;
+
+ const Any aValue = column->getPropertyValue(PROPERTY_VALUE);
+
+ OUStringBuffer aSQL;
+ const OUString aQuote = m_xMetaData->getIdentifierQuoteString();
+ getColumns();
+
+ // TODO: if this is called for HAVING, check that the column is a GROUP BY column
+ // or that it is an aggregate function
+
+ if ( m_aCurrentColumns[SelectColumns] && m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ Reference<XPropertySet> xColumn;
+ m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName("AggregateFunction"),"Property AggregateFunction not available!");
+
+ OUString sRealName,sTableName;
+ xColumn->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
+ if(sTableName.indexOf('.') != -1)
+ {
+ OUString aCatlog,aSchema,aTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
+ sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ else
+ sTableName = ::dbtools::quoteName(aQuote,sTableName);
+
+ if ( !::comphelper::getBOOL(xColumn->getPropertyValue("Function")) )
+ {
+ aSQL = sTableName + "." + ::dbtools::quoteName( aQuote, sRealName );
+ }
+ else
+ aSQL = sRealName;
+ }
+ else
+ {
+ aSQL = getTableAlias( column ) + ::dbtools::quoteName( aQuote, aName );
+ }
+
+ if ( aValue.hasValue() )
+ {
+ if( !m_xTypeConverter.is() )
+ m_xTypeConverter.set( Converter::create(m_aContext) );
+ OSL_ENSURE(m_xTypeConverter.is(),"NO typeconverter!");
+
+ if ( nType != DataType::BOOLEAN && DataType::BIT != nType )
+ {
+ lcl_addFilterCriteria_throw(filterOperator,u"",aSQL);
+ }
+
+ switch(nType)
+ {
+ case DataType::VARCHAR:
+ case DataType::CHAR:
+ case DataType::LONGVARCHAR:
+ aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
+ break;
+ case DataType::CLOB:
+ {
+ Reference< XClob > xClob(aValue,UNO_QUERY);
+ if ( xClob.is() )
+ {
+ const ::sal_Int64 nLength = xClob->length();
+ if ( sal_Int64(nLength + aSQL.getLength() + STR_LIKE.getLength() ) < sal_Int64(SAL_MAX_INT32) )
+ {
+ aSQL.append("'" + xClob->getSubString(1,static_cast<sal_Int32>(nLength)) + "'");
+ }
+ }
+ else
+ {
+ aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
+ }
+ }
+ break;
+ case DataType::VARBINARY:
+ case DataType::BINARY:
+ case DataType::LONGVARBINARY:
+ {
+ Sequence<sal_Int8> aSeq;
+ if(!(aValue >>= aSeq))
+ throw SQLException(DBA_RES(RID_STR_NOT_SEQUENCE_INT8),*this,SQLSTATE_GENERAL,1000,Any() );
+ if(nSearchable == ColumnSearch::CHAR)
+ {
+ aSQL.append( "\'" );
+ }
+ aSQL.append( "0x" );
+ const sal_Int8* pBegin = aSeq.getConstArray();
+ const sal_Int8* pEnd = pBegin + aSeq.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ aSQL.append( static_cast<sal_Int32>(*pBegin), 16 );
+ }
+ if(nSearchable == ColumnSearch::CHAR)
+ aSQL.append( "\'" );
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ {
+ bool bValue = false;
+ m_xTypeConverter->convertToSimpleType(aValue, TypeClass_BOOLEAN) >>= bValue;
+
+ OUString sColumnExp = aSQL.makeStringAndClear();
+ getBooleanComparisonPredicate( sColumnExp, bValue, m_nBoolCompareMode, aSQL );
+ }
+ break;
+ default:
+ aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
+ break;
+ }
+ }
+ else
+ {
+ sal_Int32 nFilterOp = filterOperator;
+ if ( filterOperator != SQLFilterOperator::SQLNULL && filterOperator != SQLFilterOperator::NOT_SQLNULL )
+ nFilterOp = SQLFilterOperator::SQLNULL;
+ lcl_addFilterCriteria_throw(nFilterOp,u"",aSQL);
+ }
+
+ // Attach filter
+ // Construct SELECT without WHERE and ORDER BY
+ OUString sFilter = getFilter();
+
+ if ( !sFilter.isEmpty() && !aSQL.isEmpty() )
+ {
+ sFilter = L_BRACKET + sFilter + R_BRACKET +
+ (andCriteria ? std::u16string_view(STR_AND) : std::u16string_view(STR_OR));
+ }
+ sFilter += aSQL;
+
+ // add the filter and the sort order
+ _aSetFunctor(this,sFilter);
+ }
+ catch (css::lang::WrappedTargetException & e)
+ {
+ if (e.TargetException.isExtractableTo(
+ cppu::UnoType<css::sdbc::SQLException>::get()))
+ {
+ cppu::throwException(e.TargetException);
+ }
+ else
+ {
+ throw;
+ }
+ }
+}
+
+Sequence< Sequence< PropertyValue > > OSingleSelectQueryComposer::getStructuredCondition( TGetParseNode const & _aGetFunctor )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ MutexGuard aGuard(m_aMutex);
+
+ Sequence< Sequence< PropertyValue > > aFilterSeq;
+ OUString sFilter = getStatementPart( _aGetFunctor, m_aAdditiveIterator );
+
+
+ if ( !sFilter.isEmpty() )
+ {
+ OUString aSql(m_aPureSelectSQL + STR_WHERE + sFilter);
+ // build a temporary parse node
+ const OSQLParseNode* pTempNode = m_aAdditiveIterator.getParseTree();
+
+ OUString aErrorMsg;
+ std::unique_ptr<OSQLParseNode> pSqlParseNode( m_aSqlParser.parseTree(aErrorMsg,aSql));
+ if (pSqlParseNode)
+ {
+ m_aAdditiveIterator.setParseTree(pSqlParseNode.get());
+ // normalize the filter
+ OSQLParseNode* pWhereNode = const_cast<OSQLParseNode*>(m_aAdditiveIterator.getWhereTree());
+
+ OSQLParseNode* pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ OUString sCondition;
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ OSQLParseNode::negateSearchCondition(pCondition);
+
+ pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ sCondition.clear();
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ OSQLParseNode::disjunctiveNormalForm(pCondition);
+
+ pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ sCondition.clear();
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ OSQLParseNode::absorptions(pCondition);
+
+ pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ sCondition.clear();
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ if ( pCondition )
+ {
+ std::vector< std::vector < PropertyValue > > aFilters;
+ Reference< XNumberFormatter > xFormatter( NumberFormatter::create(m_aContext), UNO_QUERY_THROW );
+ xFormatter->attachNumberFormatsSupplier( m_xNumberFormatsSupplier );
+
+ if (setORCriteria(pCondition, m_aAdditiveIterator, aFilters, xFormatter))
+ {
+ aFilterSeq.realloc(aFilters.size());
+ Sequence<PropertyValue>* pFilters = aFilterSeq.getArray();
+ for (auto const& filter : aFilters)
+ {
+ pFilters->realloc(filter.size());
+ PropertyValue* pFilter = pFilters->getArray();
+ for (auto const& elem : filter)
+ {
+ *pFilter = elem;
+ ++pFilter;
+ }
+ ++pFilters;
+ }
+ }
+ }
+ // restore
+ m_aAdditiveIterator.setParseTree(pTempNode);
+ }
+ }
+ return aFilterSeq;
+}
+
+OUString OSingleSelectQueryComposer::getKeyword( SQLPart _ePart )
+{
+ OUString sKeyword;
+ switch(_ePart)
+ {
+ default:
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getKeyWord: Invalid enum value!" );
+ [[fallthrough]]; // fallback to WHERE
+ case Where:
+ sKeyword = STR_WHERE;
+ break;
+ case Group:
+ sKeyword = STR_GROUP_BY;
+ break;
+ case Having:
+ sKeyword = STR_HAVING;
+ break;
+ case Order:
+ sKeyword = STR_ORDER_BY;
+ break;
+ }
+ return sKeyword;
+}
+
+OUString OSingleSelectQueryComposer::getSQLPart( SQLPart _ePart, OSQLParseTreeIterator& _rIterator, bool _bWithKeyword )
+{
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
+ OUString sKeyword( getKeyword( _ePart ) );
+ switch(_ePart)
+ {
+ case Where:
+ F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleWhereTree);
+ break;
+ case Group:
+ F_tmp = TGetParseNode (&OSQLParseTreeIterator::getSimpleGroupByTree);
+ break;
+ case Having:
+ F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleHavingTree);
+ break;
+ case Order:
+ F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleOrderTree);
+ break;
+ default:
+ SAL_WARN("dbaccess","Invalid enum value!");
+ }
+
+ OUString sRet = getStatementPart( F_tmp, _rIterator );
+ if ( _bWithKeyword && !sRet.isEmpty() )
+ sRet = sKeyword + sRet;
+ return sRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/StaticSet.cxx b/dbaccess/source/core/api/StaticSet.cxx
new file mode 100644
index 000000000..97226b466
--- /dev/null
+++ b/dbaccess/source/core/api/StaticSet.cxx
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "StaticSet.hxx"
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/types.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::osl;
+
+void OStaticSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 /*_nPosition*/)
+{
+ _rRow = *m_aSetIter;
+}
+
+// css::sdbcx::XRowLocate
+Any OStaticSet::getBookmark()
+{
+ return Any(getRow());
+}
+
+bool OStaticSet::moveToBookmark( const Any& bookmark )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return absolute(::comphelper::getINT32(bookmark));
+}
+
+sal_Int32 OStaticSet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ sal_Int32 nFirst = 0, nSecond = 0;
+ _first >>= nFirst;
+ _second >>= nSecond;
+ return (nFirst < nSecond) ? CompareBookmark::LESS : ((nFirst > nSecond) ? CompareBookmark::GREATER : CompareBookmark::EQUAL);
+}
+
+bool OStaticSet::hasOrderedBookmarks( )
+{
+ return true;
+}
+
+sal_Int32 OStaticSet::hashBookmark( const Any& bookmark )
+{
+ return ::comphelper::getINT32(bookmark);
+}
+
+bool OStaticSet::fetchRow()
+{
+ bool bRet = false;
+ if ( !m_bEnd && (!m_nMaxRows || sal_Int32(m_aSet.size()) < m_nMaxRows) )
+ bRet = m_xDriverSet->next();
+ if ( bRet )
+ {
+ m_aSet.push_back(new connectivity::ORowVector< connectivity::ORowSetValue >(m_xSetMetaData->getColumnCount()));
+ m_aSetIter = m_aSet.end() - 1;
+ (**m_aSetIter)[0] = getRow();
+ OCacheSet::fillValueRow(*m_aSetIter,(**m_aSetIter)[0].getInt32());
+ }
+ else
+ m_bEnd = true;
+ return bRet;
+}
+
+void OStaticSet::fillAllRows()
+{
+ if(m_bEnd)
+ return;
+
+ sal_Int32 nColumnCount = m_xSetMetaData->getColumnCount();
+ while(m_xDriverSet->next())
+ {
+ ORowSetRow pRow = new connectivity::ORowVector< connectivity::ORowSetValue >(nColumnCount);
+ m_aSet.push_back(pRow);
+ m_aSetIter = m_aSet.end() - 1;
+ (*pRow)[0] = getRow();
+ OCacheSet::fillValueRow(pRow,(*pRow)[0].getInt32());
+ }
+ m_bEnd = true;
+}
+
+// XResultSet
+bool OStaticSet::next()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+
+ if(isAfterLast())
+ return false;
+ if(!m_bEnd) // not yet all records fetched
+ {
+ ++m_aSetIter;
+ if(m_aSetIter == m_aSet.end() && !fetchRow())
+ m_aSetIter = m_aSet.end();
+ }
+ else if(!isAfterLast())
+ ++m_aSetIter;
+ return !isAfterLast();
+}
+
+bool OStaticSet::isBeforeFirst( )
+{
+ return m_aSetIter == m_aSet.begin();
+}
+
+bool OStaticSet::isAfterLast( )
+{
+ return m_aSetIter == m_aSet.end() && m_bEnd;
+}
+
+void OStaticSet::beforeFirst( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aSetIter = m_aSet.begin();
+}
+
+void OStaticSet::afterLast( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ fillAllRows();
+ m_aSetIter = m_aSet.end();
+}
+
+bool OStaticSet::first()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aSetIter = m_aSet.begin()+1;
+ if(m_aSetIter == m_aSet.end() && !fetchRow())
+ m_aSetIter = m_aSet.end();
+
+ return m_aSetIter != m_aSet.end();
+}
+
+bool OStaticSet::last()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ fillAllRows();
+ m_aSetIter = m_aSet.end()-1;
+
+ return !isBeforeFirst() && !isAfterLast();
+}
+
+sal_Int32 OStaticSet::getRow( )
+{
+ OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
+ OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
+
+ sal_Int32 nPos = m_aSet.size() - (m_aSet.end() - m_aSetIter);
+ OSL_ENSURE(nPos > 0,"RowPos is < 0");
+ return nPos;
+}
+
+bool OStaticSet::absolute( sal_Int32 row )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ OSL_ENSURE(row,"OStaticSet::absolute: INVALID row number!");
+ // if row greater 0 than count from end - row means last
+ if(row < 0)
+ {
+ if(!m_bEnd)
+ fillAllRows();
+
+ sal_Int32 nRow = getRow();
+ nRow += row;
+ if(nRow <= static_cast<sal_Int32>(m_aSet.size()))
+ m_aSetIter = m_aSet.begin() + nRow;
+ else
+ m_aSetIter = m_aSet.begin();
+ }
+ else if(row > 0)
+ {
+ if(o3tl::make_unsigned(row) >= m_aSet.size())
+ {
+ if(!m_bEnd)
+ {
+ bool bNext = true;
+ for(sal_Int32 i=m_aSet.size()-1;i < row && bNext;++i)
+ bNext = fetchRow();
+ }
+
+ if(o3tl::make_unsigned(row) > m_aSet.size())
+ m_aSetIter = m_aSet.end(); // check again
+ else
+ m_aSetIter = m_aSet.begin() + row;
+ }
+ else
+ m_aSetIter = m_aSet.begin() + row;
+ }
+
+ return m_aSetIter != m_aSet.end() && m_aSetIter != m_aSet.begin();
+}
+
+bool OStaticSet::previous( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+
+ if(m_aSetIter != m_aSet.begin())
+ --m_aSetIter;
+
+ return m_aSetIter != m_aSet.begin();
+}
+
+void OStaticSet::refreshRow( )
+{
+}
+
+bool OStaticSet::rowUpdated( )
+{
+ return m_bUpdated;
+}
+
+bool OStaticSet::rowInserted( )
+{
+ return m_bInserted;
+}
+
+bool OStaticSet::rowDeleted( )
+{
+ return m_bDeleted;
+}
+
+void OStaticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable )
+{
+ OCacheSet::insertRow( _rInsertRow,_xTable);
+ if(m_bInserted)
+ {
+ m_aSet.push_back(new ORowVector< ORowSetValue >(*_rInsertRow)); // we don't know where the new row is so we append it to the current rows
+ m_aSetIter = m_aSet.end() - 1;
+ (**m_aSetIter)[0] = (*_rInsertRow)[0] = getBookmark();
+ m_bEnd = false;
+ }
+}
+
+void OStaticSet::deleteRow(const ORowSetRow& _rDeleteRow ,const connectivity::OSQLTable& _xTable )
+{
+ OCacheSet::deleteRow(_rDeleteRow,_xTable);
+ if(m_bDeleted)
+ {
+ ORowSetMatrix::iterator aPos = m_aSet.begin()+(*_rDeleteRow)[0].getInt32();
+ if(aPos == (m_aSet.end()-1))
+ m_aSetIter = m_aSet.end();
+ m_aSet.erase(aPos);
+ }
+}
+
+void OStaticSet::reset(const Reference< XResultSet> &_xDriverSet)
+{
+ OCacheSet::construct(_xDriverSet, m_sRowSetFilter);
+ ORowSetMatrix().swap(m_aSet);
+ m_aSetIter = m_aSet.end();
+ m_bEnd = false;
+ m_aSet.emplace_back(nullptr); // this is the beforefirst record
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/StaticSet.hxx b/dbaccess/source/core/api/StaticSet.hxx
new file mode 100644
index 000000000..9f765996b
--- /dev/null
+++ b/dbaccess/source/core/api/StaticSet.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+
+namespace dbaccess
+{
+ // is used when nothing is supported by the driver
+ // we use a snapshot
+ class OStaticSet : public OCacheSet
+ {
+ ORowSetMatrix m_aSet;
+ ORowSetMatrix::iterator m_aSetIter;
+ bool m_bEnd;
+ bool fetchRow();
+ void fillAllRows();
+ public:
+ explicit OStaticSet(sal_Int32 i_nMaxRows) : OCacheSet(i_nMaxRows)
+ , m_aSetIter(m_aSet.end())
+ , m_bEnd(false)
+ {
+ m_aSet.push_back(nullptr); // this is the beforefirst record
+ }
+
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+
+ virtual void fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual bool hasOrderedBookmarks( ) override;
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+
+ bool isBeforeFirst( );
+ bool isAfterLast( );
+
+ // css::sdbc::XResultSet
+ virtual bool next() override;
+ virtual void beforeFirst( ) override;
+ virtual void afterLast( ) override;
+ virtual bool first() override;
+ virtual bool last() override;
+ virtual sal_Int32 getRow( ) override;
+ virtual bool absolute( sal_Int32 row ) override;
+ virtual bool previous( ) override;
+ virtual void refreshRow( ) override;
+ virtual bool rowUpdated( ) override;
+ virtual bool rowInserted( ) override;
+ virtual bool rowDeleted( ) override;
+ // css::sdbc::XResultSetUpdate
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/TableDeco.cxx b/dbaccess/source/core/api/TableDeco.cxx
new file mode 100644
index 000000000..92821750f
--- /dev/null
+++ b/dbaccess/source/core/api/TableDeco.cxx
@@ -0,0 +1,634 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableDeco.hxx>
+#include <definitioncolumn.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <ContainerMediator.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::dbtools;
+using namespace ::cppu;
+
+// ODBTableDecorator
+
+ODBTableDecorator::ODBTableDecorator( const Reference< XConnection >& _rxConnection, const Reference< XColumnsSupplier >& _rxNewTable,
+ const Reference< XNumberFormatsSupplier >& _rxNumberFormats, const Reference< XNameAccess >& _xColumnDefinitions )
+ :OTableDescriptor_BASE(m_aMutex)
+ ,ODataSettings(OTableDescriptor_BASE::rBHelper)
+ ,m_xTable(_rxNewTable)
+ ,m_xColumnDefinitions(_xColumnDefinitions)
+ ,m_xConnection( _rxConnection )
+ ,m_xMetaData( _rxConnection.is() ? _rxConnection->getMetaData() : Reference< XDatabaseMetaData >() )
+ ,m_xNumberFormats( _rxNumberFormats )
+ ,m_nPrivileges(-1)
+{
+ ODataSettings::registerPropertiesFor(this);
+}
+
+ODBTableDecorator::~ODBTableDecorator()
+{
+}
+
+Sequence< sal_Int8 > ODBTableDecorator::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// OComponentHelper
+void SAL_CALL ODBTableDecorator::disposing()
+{
+ OPropertySetHelper::disposing();
+ OTableDescriptor_BASE::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+ m_xTable = nullptr;
+ m_xMetaData = nullptr;
+ m_xColumnDefinitions = nullptr;
+ m_xNumberFormats = nullptr;
+ if ( m_pColumns )
+ m_pColumns->disposing();
+ m_xColumnMediator = nullptr;
+}
+
+sal_Bool SAL_CALL ODBTableDecorator::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bRet = true;
+ switch(nHandle)
+ {
+ case PROPERTY_ID_PRIVILEGES:
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_APPLYFILTER:
+ case PROPERTY_ID_FONT:
+ case PROPERTY_ID_ROW_HEIGHT:
+ case PROPERTY_ID_AUTOGROW:
+ case PROPERTY_ID_TEXTCOLOR:
+ case PROPERTY_ID_TEXTLINECOLOR:
+ case PROPERTY_ID_TEXTEMPHASIS:
+ case PROPERTY_ID_TEXTRELIEF:
+ case PROPERTY_ID_FONTCHARWIDTH:
+ case PROPERTY_ID_FONTCHARSET:
+ case PROPERTY_ID_FONTFAMILY:
+ case PROPERTY_ID_FONTHEIGHT:
+ case PROPERTY_ID_FONTKERNING:
+ case PROPERTY_ID_FONTNAME:
+ case PROPERTY_ID_FONTORIENTATION:
+ case PROPERTY_ID_FONTPITCH:
+ case PROPERTY_ID_FONTSLANT:
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ case PROPERTY_ID_FONTSTYLENAME:
+ case PROPERTY_ID_FONTUNDERLINE:
+ case PROPERTY_ID_FONTWEIGHT:
+ case PROPERTY_ID_FONTWIDTH:
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ case PROPERTY_ID_FONTTYPE:
+ bRet = ODataSettings::convertFastPropertyValue(rConvertedValue, rOldValue,nHandle,rValue);
+ break;
+
+ default:
+ {
+ Any aValue;
+ getFastPropertyValue(aValue,nHandle);
+ bRet = ::comphelper::tryPropertyValue(rConvertedValue,rOldValue,rValue,aValue,::cppu::UnoType<OUString>::get());
+ }
+ break; // we assume that it works
+ }
+ return bRet;
+}
+
+void ODBTableDecorator::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
+{
+ switch(_nHandle)
+ {
+ case PROPERTY_ID_PRIVILEGES:
+ SAL_WARN("dbaccess", "Property is readonly!");
+ [[fallthrough]];
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_APPLYFILTER:
+ case PROPERTY_ID_FONT:
+ case PROPERTY_ID_ROW_HEIGHT:
+ case PROPERTY_ID_AUTOGROW:
+ case PROPERTY_ID_TEXTCOLOR:
+ case PROPERTY_ID_TEXTLINECOLOR:
+ case PROPERTY_ID_TEXTEMPHASIS:
+ case PROPERTY_ID_TEXTRELIEF:
+ case PROPERTY_ID_FONTCHARWIDTH:
+ case PROPERTY_ID_FONTCHARSET:
+ case PROPERTY_ID_FONTFAMILY:
+ case PROPERTY_ID_FONTHEIGHT:
+ case PROPERTY_ID_FONTKERNING:
+ case PROPERTY_ID_FONTNAME:
+ case PROPERTY_ID_FONTORIENTATION:
+ case PROPERTY_ID_FONTPITCH:
+ case PROPERTY_ID_FONTSLANT:
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ case PROPERTY_ID_FONTSTYLENAME:
+ case PROPERTY_ID_FONTUNDERLINE:
+ case PROPERTY_ID_FONTWEIGHT:
+ case PROPERTY_ID_FONTWIDTH:
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ case PROPERTY_ID_FONTTYPE:
+
+ ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
+ break;
+ case PROPERTY_ID_CATALOGNAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_CATALOGNAME,_rValue);
+ }
+ break;
+ case PROPERTY_ID_SCHEMANAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_SCHEMANAME,_rValue);
+ }
+ break;
+ case PROPERTY_ID_NAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_NAME,_rValue);
+ }
+ break;
+ case PROPERTY_ID_DESCRIPTION:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_DESCRIPTION,_rValue);
+ }
+ break;
+ case PROPERTY_ID_TYPE:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_TYPE,_rValue);
+ }
+ break;
+ }
+}
+
+void ODBTableDecorator::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
+{
+
+ switch(_nHandle)
+ {
+ case PROPERTY_ID_PRIVILEGES:
+ {
+ if ( -1 == m_nPrivileges )
+ fillPrivileges();
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+ if ( xInfo->hasPropertyByName(PROPERTY_PRIVILEGES) )
+ {
+ _rValue <<= m_nPrivileges;
+ break;
+ }
+ }
+ [[fallthrough]];
+
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_APPLYFILTER:
+ case PROPERTY_ID_FONT:
+ case PROPERTY_ID_ROW_HEIGHT:
+ case PROPERTY_ID_AUTOGROW:
+ case PROPERTY_ID_TEXTCOLOR:
+ case PROPERTY_ID_TEXTLINECOLOR:
+ case PROPERTY_ID_TEXTEMPHASIS:
+ case PROPERTY_ID_TEXTRELIEF:
+ case PROPERTY_ID_FONTCHARWIDTH:
+ case PROPERTY_ID_FONTCHARSET:
+ case PROPERTY_ID_FONTFAMILY:
+ case PROPERTY_ID_FONTHEIGHT:
+ case PROPERTY_ID_FONTKERNING:
+ case PROPERTY_ID_FONTNAME:
+ case PROPERTY_ID_FONTORIENTATION:
+ case PROPERTY_ID_FONTPITCH:
+ case PROPERTY_ID_FONTSLANT:
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ case PROPERTY_ID_FONTSTYLENAME:
+ case PROPERTY_ID_FONTUNDERLINE:
+ case PROPERTY_ID_FONTWEIGHT:
+ case PROPERTY_ID_FONTWIDTH:
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ case PROPERTY_ID_FONTTYPE:
+ ODataSettings::getFastPropertyValue(_rValue, _nHandle);
+ break;
+ case PROPERTY_ID_CATALOGNAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_CATALOGNAME);
+ }
+ break;
+ case PROPERTY_ID_SCHEMANAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_SCHEMANAME);
+ }
+ break;
+ case PROPERTY_ID_NAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_NAME);
+ }
+ break;
+ case PROPERTY_ID_DESCRIPTION:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_DESCRIPTION);
+ }
+ break;
+ case PROPERTY_ID_TYPE:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_TYPE);
+ }
+ break;
+ default:
+ SAL_WARN("dbaccess", "Invalid Handle for table");
+ }
+}
+
+void ODBTableDecorator::construct()
+{
+ bool bNotFound = true;
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+ bNotFound = !xInfo->hasPropertyByName(PROPERTY_PRIVILEGES);
+ }
+ if ( bNotFound )
+ registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ &m_nPrivileges, ::cppu::UnoType<sal_Int32>::get());
+}
+
+::cppu::IPropertyArrayHelper* ODBTableDecorator::createArrayHelper(sal_Int32 /*_nId*/) const
+{
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+
+ Sequence< Property > aTableProps = xInfo->getProperties();
+ for (Property & prop : asNonConstRange(aTableProps))
+ {
+ if (prop.Name == PROPERTY_CATALOGNAME)
+ prop.Handle = PROPERTY_ID_CATALOGNAME;
+ else if (prop.Name == PROPERTY_SCHEMANAME)
+ prop.Handle = PROPERTY_ID_SCHEMANAME;
+ else if (prop.Name == PROPERTY_NAME)
+ prop.Handle = PROPERTY_ID_NAME;
+ else if (prop.Name == PROPERTY_DESCRIPTION)
+ prop.Handle = PROPERTY_ID_DESCRIPTION;
+ else if (prop.Name == PROPERTY_TYPE)
+ prop.Handle = PROPERTY_ID_TYPE;
+ else if (prop.Name == PROPERTY_PRIVILEGES)
+ prop.Handle = PROPERTY_ID_PRIVILEGES;
+ }
+
+ describeProperties(aTableProps);
+
+ return new ::cppu::OPropertyArrayHelper(aTableProps);
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL ODBTableDecorator::getInfoHelper()
+{
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+ bool bIsDescriptor = (xInfo->getPropertyByName(PROPERTY_NAME).Attributes & PropertyAttribute::READONLY) == 0;
+
+ return *ODBTableDecorator_PROP::getArrayHelper( bIsDescriptor ? 0 : 1 );
+
+ // TODO: this is a HACK, and prone to errors
+ // The OIdPropertyArrayUsageHelper is intended for classes where there exists a known, limited
+ // number of different property set infos (distinguished by the ID), all implemented by this very
+ // same class.
+ // However, in this case here we have an unknown, potentially unlimited number of different
+ // property set infos: Depending on the table for which we act as decorator, different property
+ // sets might exist.
+}
+
+// XServiceInfo
+OUString SAL_CALL ODBTableDecorator::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.ODBTableDecorator";
+ }
+sal_Bool SAL_CALL ODBTableDecorator::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL ODBTableDecorator::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_TABLE };
+}
+
+
+Any SAL_CALL ODBTableDecorator::queryInterface( const Type & rType )
+{
+ Any aRet;
+ if(m_xTable.is())
+ {
+ aRet = m_xTable->queryInterface(rType);
+ if(aRet.hasValue())
+ { // now we know that our table supports this type so we return ourself
+ aRet = OTableDescriptor_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ODataSettings::queryInterface(rType);
+ }
+ }
+
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL ODBTableDecorator::getTypes( )
+{
+ Reference<XTypeProvider> xTypes(m_xTable,UNO_QUERY);
+ OSL_ENSURE(xTypes.is(),"Table must be a TypeProvider!");
+ return xTypes->getTypes();
+}
+
+// XRename,
+void SAL_CALL ODBTableDecorator::rename( const OUString& _rNewName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XRename> xRename(m_xTable,UNO_QUERY);
+ if(!xRename.is())
+ throw SQLException(DBA_RES(RID_STR_NO_TABLE_RENAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ // not supported
+ xRename->rename(_rNewName);
+}
+
+// XAlterTable,
+void SAL_CALL ODBTableDecorator::alterColumnByName( const OUString& _rName, const Reference< XPropertySet >& _rxDescriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY);
+ if(!xAlter.is())
+ throw SQLException(DBA_RES(RID_STR_COLUMN_ALTER_BY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ xAlter->alterColumnByName(_rName,_rxDescriptor);
+ if(m_pColumns)
+ m_pColumns->refresh();
+}
+
+void SAL_CALL ODBTableDecorator::alterColumnByIndex( sal_Int32 _nIndex, const Reference< XPropertySet >& _rxDescriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY);
+ if(!xAlter.is())
+ throw SQLException(DBA_RES(RID_STR_COLUMN_ALTER_BY_INDEX),*this,SQLSTATE_GENERAL,1000,Any() );
+ // not supported
+ xAlter->alterColumnByIndex(_nIndex,_rxDescriptor);
+ if(m_pColumns)
+ m_pColumns->refresh();
+}
+
+Reference< XNameAccess> ODBTableDecorator::getIndexes()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ return Reference< XIndexesSupplier>(m_xTable,UNO_QUERY_THROW)->getIndexes();
+}
+
+Reference< XIndexAccess> ODBTableDecorator::getKeys()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ return Reference< XKeysSupplier>(m_xTable,UNO_QUERY_THROW)->getKeys();
+}
+
+Reference< XNameAccess> ODBTableDecorator::getColumns()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ if(!m_pColumns)
+ refreshColumns();
+
+ return m_pColumns.get();
+}
+
+OUString SAL_CALL ODBTableDecorator::getName()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XNamed> xName(m_xTable,UNO_QUERY);
+ OSL_ENSURE(xName.is(),"Table should support the XNamed interface");
+ return xName->getName();
+}
+
+sal_Int64 SAL_CALL ODBTableDecorator::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ if (comphelper::isUnoTunnelId<ODBTableDecorator>(rId))
+ return comphelper::getSomething_cast(this);
+
+ sal_Int64 nRet = 0;
+ Reference<XUnoTunnel> xTunnel(m_xTable,UNO_QUERY);
+ if(xTunnel.is())
+ nRet = xTunnel->getSomething(rId);
+ return nRet;
+}
+
+const Sequence< sal_Int8 > & ODBTableDecorator::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+void ODBTableDecorator::fillPrivileges() const
+{
+ // somebody is asking for the privileges and we do not know them, yet
+ m_nPrivileges = 0;
+ try
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ if ( xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES) )
+ {
+ xProp->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ }
+ if ( m_nPrivileges == 0 ) // second chance
+ {
+ OUString sCatalog,sSchema,sName;
+ xProp->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog;
+ xProp->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema;
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
+ m_nPrivileges = ::dbtools::getTablePrivileges(m_xMetaData, sCatalog,sSchema, sName);
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ SAL_WARN("dbaccess", "ODBTableDecorator::ODBTableDecorator : could not collect the privileges !");
+ }
+}
+
+Reference< XPropertySet > SAL_CALL ODBTableDecorator::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ Reference< XDataDescriptorFactory > xFactory( m_xTable, UNO_QUERY );
+ OSL_ENSURE( xFactory.is(), "ODBTableDecorator::createDataDescriptor: invalid table!" );
+ Reference< XColumnsSupplier > xColsSupp;
+ if ( xFactory.is() )
+ xColsSupp.set(xFactory->createDataDescriptor(), css::uno::UNO_QUERY);
+
+ return new ODBTableDecorator(
+ m_xConnection,
+ xColsSupp,
+ m_xNumberFormats,
+ nullptr
+ );
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL ODBTableDecorator::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void ODBTableDecorator::refreshColumns()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ std::vector< OUString> aVector;
+
+ Reference<XNameAccess> xNames;
+ if(m_xTable.is())
+ {
+ xNames = m_xTable->getColumns();
+ if(xNames.is())
+ {
+ const Sequence< OUString> aNames = xNames->getElementNames();
+ aVector.insert(aVector.end(), aNames.begin(), aNames.end());
+ }
+ }
+ if(!m_pColumns)
+ {
+ OColumns* pCol = new OColumns(*this,m_aMutex,xNames,m_xMetaData.is() && m_xMetaData->supportsMixedCaseQuotedIdentifiers(),aVector,
+ this,this,
+ m_xMetaData.is() && m_xMetaData->supportsAlterTableWithAddColumn(),
+ m_xMetaData.is() && m_xMetaData->supportsAlterTableWithDropColumn());
+
+ pCol->setParent(*this);
+ rtl::Reference<OContainerMediator> pMediator = new OContainerMediator( pCol, m_xColumnDefinitions );
+ m_xColumnMediator = pMediator;
+ pCol->setMediator( pMediator.get() );
+ m_pColumns.reset(pCol);
+ }
+ else
+ m_pColumns->reFill(aVector);
+}
+
+rtl::Reference<OColumn> ODBTableDecorator::createColumn(const OUString& _rName) const
+{
+ rtl::Reference<OColumn> pReturn;
+
+ Reference<XNameAccess> xNames;
+ if ( m_xTable.is() )
+ {
+ xNames = m_xTable->getColumns();
+
+ if ( xNames.is() && xNames->hasByName(_rName) )
+ {
+ Reference<XPropertySet> xProp(xNames->getByName(_rName),UNO_QUERY);
+
+ Reference<XPropertySet> xColumnDefinition;
+ if ( m_xColumnDefinitions.is() && m_xColumnDefinitions->hasByName(_rName))
+ xColumnDefinition.set(m_xColumnDefinitions->getByName(_rName),UNO_QUERY);
+
+ pReturn = new OTableColumnWrapper( xProp, xColumnDefinition, false );
+ }
+ }
+ return pReturn;
+}
+
+void ODBTableDecorator::columnAppended( const Reference< XPropertySet >& /*_rxSourceDescriptor*/ )
+{
+ // not interested in
+}
+
+void ODBTableDecorator::columnDropped(const OUString& _sName)
+{
+ Reference<XDrop> xDrop(m_xColumnDefinitions,UNO_QUERY);
+ if ( xDrop.is() && m_xColumnDefinitions->hasByName(_sName) )
+ xDrop->dropByName(_sName);
+}
+
+Reference< XPropertySet > ODBTableDecorator::createColumnDescriptor()
+{
+ Reference<XDataDescriptorFactory> xNames;
+ if(m_xTable.is())
+ xNames.set(m_xTable->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xRet;
+ if ( xNames.is() )
+ xRet = new OTableColumnDescriptorWrapper( xNames->createDataDescriptor(), false, true );
+ return xRet;
+}
+
+void SAL_CALL ODBTableDecorator::acquire() noexcept
+{
+ OTableDescriptor_BASE::acquire();
+}
+
+void SAL_CALL ODBTableDecorator::release() noexcept
+{
+ OTableDescriptor_BASE::release();
+}
+
+void SAL_CALL ODBTableDecorator::setName( const OUString& /*aName*/ )
+{
+ throwFunctionNotSupportedRuntimeException( "XNamed::setName", *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/View.cxx b/dbaccess/source/core/api/View.cxx
new file mode 100644
index 000000000..c52c4885c
--- /dev/null
+++ b/dbaccess/source/core/api/View.cxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <View.hxx>
+#include <strings.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star::uno;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+
+ static OUString lcl_getServiceNameForSetting(const Reference< css::sdbc::XConnection >& _xConnection,const OUString& i_sSetting)
+ {
+ OUString sSupportService;
+ Any aValue;
+ if ( dbtools::getDataSourceSetting(_xConnection,i_sSetting,aValue) )
+ {
+ aValue >>= sSupportService;
+ }
+ return sSupportService;
+ }
+ // View
+ View::View( const Reference< XConnection >& _rxConnection, bool _bCaseSensitive,
+ const OUString& _rCatalogName,const OUString& _rSchemaName, const OUString& _rName )
+ :View_Base( _bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName, _rCatalogName )
+ {
+ m_nCommandHandle = getProperty(PROPERTY_COMMAND).Handle;
+ try
+ {
+ Reference<XMultiServiceFactory> xFac(_rxConnection,UNO_QUERY_THROW);
+ m_xViewAccess.set(xFac->createInstance(lcl_getServiceNameForSetting(_rxConnection,"ViewAccessServiceName")),UNO_QUERY);
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ View::~View()
+ {
+ }
+
+ IMPLEMENT_FORWARD_REFCOUNT( View, View_Base )
+ IMPLEMENT_GET_IMPLEMENTATION_ID( View )
+
+ Any SAL_CALL View::queryInterface( const Type & _rType )
+ {
+ if(_rType == cppu::UnoType<XAlterView>::get()&& !m_xViewAccess.is() )
+ return Any();
+ Any aReturn = View_Base::queryInterface( _rType );
+ if ( !aReturn.hasValue() )
+ aReturn = View_IBASE::queryInterface( _rType );
+ return aReturn;
+ }
+
+ Sequence< Type > SAL_CALL View::getTypes( )
+ {
+ Type aAlterType = cppu::UnoType<XAlterView>::get();
+
+ Sequence< Type > aTypes( ::comphelper::concatSequences(View_Base::getTypes(),View_IBASE::getTypes()) );
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+
+ const Type* pIter = aTypes.getConstArray();
+ const Type* pEnd = pIter + aTypes.getLength();
+ for(;pIter != pEnd ;++pIter)
+ {
+ if( *pIter != aAlterType || m_xViewAccess.is() )
+ aOwnTypes.push_back(*pIter);
+ }
+
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+ }
+
+ void SAL_CALL View::alterCommand( const OUString& _rNewCommand )
+ {
+ OSL_ENSURE(m_xViewAccess.is(),"Illegal call to AlterView!");
+ m_xViewAccess->alterCommand(this,_rNewCommand);
+ }
+
+ void SAL_CALL View::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ if ( _nHandle == m_nCommandHandle && m_xViewAccess.is() )
+ {
+ // retrieve the very current command, don't rely on the base classes cached value
+ // (which we initialized empty, anyway)
+ _rValue <<= m_xViewAccess->getCommand(const_cast<View*>(this));
+ return;
+ }
+
+ View_Base::getFastPropertyValue( _rValue, _nHandle );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/WrappedResultSet.cxx b/dbaccess/source/core/api/WrappedResultSet.cxx
new file mode 100644
index 000000000..09d70826b
--- /dev/null
+++ b/dbaccess/source/core/api/WrappedResultSet.cxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "WrappedResultSet.hxx"
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::osl;
+
+void WrappedResultSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+ m_xUpd.set(_xDriverSet,UNO_QUERY_THROW);
+ m_xRowLocate.set(_xDriverSet,UNO_QUERY_THROW);
+ m_xUpdRow.set(_xDriverSet,UNO_QUERY_THROW);
+}
+
+void WrappedResultSet::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ construct(_xDriverSet, m_sRowSetFilter);
+}
+
+Any WrappedResultSet::getBookmark()
+{
+ if ( m_xRowLocate.is() )
+ {
+ return m_xRowLocate->getBookmark( );
+ }
+ return Any(m_xDriverSet->getRow());
+}
+
+bool WrappedResultSet::moveToBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->moveToBookmark( bookmark );
+}
+
+sal_Int32 WrappedResultSet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ return m_xRowLocate->compareBookmarks( _first,_second );
+}
+
+bool WrappedResultSet::hasOrderedBookmarks( )
+{
+ return m_xRowLocate->hasOrderedBookmarks();
+}
+
+sal_Int32 WrappedResultSet::hashBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->hashBookmark(bookmark);
+}
+
+void WrappedResultSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ m_xUpd->moveToInsertRow();
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setSigned(m_aSignedFlags[i-1]);
+ updateColumn(i,m_xUpdRow,*aIter);
+ }
+ m_xUpd->insertRow();
+ (*_rInsertRow->begin()) = getBookmark();
+}
+
+void WrappedResultSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOriginalRow->begin()+1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
+ {
+ aIter->setSigned(aOrgIter->isSigned());
+ updateColumn(i,m_xUpdRow,*aIter);
+ }
+ m_xUpd->updateRow();
+}
+
+void WrappedResultSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ m_xUpd->deleteRow();
+}
+
+void WrappedResultSet::updateColumn(sal_Int32 nPos, const Reference< XRowUpdate >& _xParameter, const ORowSetValue& _rValue)
+{
+ if(!(_rValue.isBound() && _rValue.isModified()))
+ return;
+
+ if(_rValue.isNull())
+ _xParameter->updateNull(nPos);
+ else
+ {
+
+ switch(_rValue.getTypeKind())
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIGINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ else
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _xParameter->updateBoolean(nPos,_rValue.getBool());
+ break;
+ case DataType::TINYINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateByte(nPos,_rValue.getInt8());
+ else
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ break;
+ case DataType::SMALLINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ else
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ break;
+ case DataType::INTEGER:
+ if ( _rValue.isSigned() )
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ else
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ break;
+ case DataType::FLOAT:
+ _xParameter->updateFloat(nPos,_rValue.getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ _xParameter->updateDouble(nPos,_rValue.getDouble());
+ break;
+ case DataType::DATE:
+ _xParameter->updateDate(nPos,_rValue.getDate());
+ break;
+ case DataType::TIME:
+ _xParameter->updateTime(nPos,_rValue.getTime());
+ break;
+ case DataType::TIMESTAMP:
+ _xParameter->updateTimestamp(nPos,_rValue.getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ _xParameter->updateBytes(nPos,_rValue.getSequence());
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ _xParameter->updateObject(nPos,_rValue.getAny());
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/WrappedResultSet.hxx b/dbaccess/source/core/api/WrappedResultSet.hxx
new file mode 100644
index 000000000..58b2d7041
--- /dev/null
+++ b/dbaccess/source/core/api/WrappedResultSet.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+
+namespace dbaccess
+{
+ // this set is used when we have a bookmarkable set from the driver
+ class WrappedResultSet : public OCacheSet
+ {
+ css::uno::Reference< css::sdbcx::XRowLocate> m_xRowLocate;
+ css::uno::Reference< css::sdbc::XResultSetUpdate> m_xUpd;
+ css::uno::Reference< css::sdbc::XRowUpdate> m_xUpdRow;
+
+ void updateColumn(sal_Int32 nPos, const css::uno::Reference< css::sdbc::XRowUpdate >& _xParameter, const connectivity::ORowSetValue& _rValue);
+ public:
+ explicit WrappedResultSet(sal_Int32 i_nMaxRows) : OCacheSet(i_nMaxRows)
+ {}
+ virtual ~WrappedResultSet() override
+ {
+ m_xRowLocate = nullptr;
+ }
+
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual bool hasOrderedBookmarks( ) override;
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+ // css::sdbc::XResultSetUpdate
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/callablestatement.cxx b/dbaccess/source/core/api/callablestatement.cxx
new file mode 100644
index 000000000..8f864fbe0
--- /dev/null
+++ b/dbaccess/source/core/api/callablestatement.cxx
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <callablestatement.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <strings.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+
+// css::lang::XTypeProvider
+Sequence< Type > OCallableStatement::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XRow>::get(),
+ cppu::UnoType<XOutParameters>::get(),
+ OPreparedStatement::getTypes() );
+
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > OCallableStatement::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OCallableStatement::queryInterface( const Type & rType )
+{
+ Any aIface = OPreparedStatement::queryInterface( rType );
+ if (!aIface.hasValue())
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XRow * >( this ),
+ static_cast< XOutParameters * >( this ));
+ return aIface;
+}
+
+void OCallableStatement::acquire() noexcept
+{
+ OPreparedStatement::acquire();
+}
+
+void OCallableStatement::release() noexcept
+{
+ OPreparedStatement::release();
+}
+
+// XServiceInfo
+OUString OCallableStatement::getImplementationName( )
+{
+ return "com.sun.star.sdb.OCallableStatement";
+}
+
+Sequence< OUString > OCallableStatement::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_CALLABLESTATEMENT, SERVICE_SDB_CALLABLESTATEMENT };
+}
+
+// XOutParameters
+void SAL_CALL OCallableStatement::registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ Reference< XOutParameters >(m_xAggregateAsSet, UNO_QUERY_THROW)->registerOutParameter( parameterIndex, sqlType, typeName );
+}
+
+void SAL_CALL OCallableStatement::registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ Reference< XOutParameters >(m_xAggregateAsSet, UNO_QUERY_THROW)->registerNumericOutParameter( parameterIndex, sqlType, scale );
+}
+
+// XRow
+sal_Bool SAL_CALL OCallableStatement::wasNull( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->wasNull();
+}
+
+OUString SAL_CALL OCallableStatement::getString( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getString( columnIndex );
+}
+
+sal_Bool SAL_CALL OCallableStatement::getBoolean( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBoolean( columnIndex );
+}
+
+sal_Int8 SAL_CALL OCallableStatement::getByte( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getByte( columnIndex );
+}
+
+sal_Int16 SAL_CALL OCallableStatement::getShort( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getShort( columnIndex );
+}
+
+sal_Int32 SAL_CALL OCallableStatement::getInt( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getInt( columnIndex );
+}
+
+sal_Int64 SAL_CALL OCallableStatement::getLong( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getLong( columnIndex );
+}
+
+float SAL_CALL OCallableStatement::getFloat( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getFloat( columnIndex );
+}
+
+double SAL_CALL OCallableStatement::getDouble( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getDouble( columnIndex );
+}
+
+Sequence< sal_Int8 > SAL_CALL OCallableStatement::getBytes( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBytes( columnIndex );
+}
+
+css::util::Date SAL_CALL OCallableStatement::getDate( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getDate( columnIndex );
+}
+
+css::util::Time SAL_CALL OCallableStatement::getTime( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getTime( columnIndex );
+}
+
+css::util::DateTime SAL_CALL OCallableStatement::getTimestamp( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getTimestamp( columnIndex );
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getBinaryStream( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBinaryStream( columnIndex );
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getCharacterStream( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getCharacterStream( columnIndex );
+}
+
+Any SAL_CALL OCallableStatement::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getObject( columnIndex, typeMap );
+}
+
+Reference< XRef > SAL_CALL OCallableStatement::getRef( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getRef( columnIndex );
+}
+
+Reference< XBlob > SAL_CALL OCallableStatement::getBlob( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBlob( columnIndex );
+}
+
+Reference< XClob > SAL_CALL OCallableStatement::getClob( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getClob( columnIndex );
+}
+
+Reference< XArray > SAL_CALL OCallableStatement::getArray( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getArray( columnIndex );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/column.cxx b/dbaccess/source/core/api/column.cxx
new file mode 100644
index 000000000..5bc70affb
--- /dev/null
+++ b/dbaccess/source/core/api/column.cxx
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ContainerMediator.hxx>
+#include <column.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <stringconstants.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdb/tools/XTableAlteration.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/diagnose.h>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+
+// OColumn
+OColumn::OColumn( const bool _bNameIsReadOnly )
+ :OColumnBase( m_aMutex )
+ ,::comphelper::OPropertyContainer( OColumnBase::rBHelper )
+{
+
+ registerProperty( PROPERTY_NAME, PROPERTY_ID_NAME, _bNameIsReadOnly ? PropertyAttribute::READONLY : 0,
+ &m_sName, cppu::UnoType<decltype(m_sName)>::get() );
+}
+
+OColumn::~OColumn()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OColumn::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OColumnBase::getTypes(),
+ getBaseTypes()
+ );
+}
+
+// css::uno::XInterface
+IMPLEMENT_FORWARD_XINTERFACE2( OColumn, OColumnBase, ::comphelper::OPropertyContainer )
+
+// css::lang::XServiceInfo
+OUString OColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.OColumn";
+}
+
+sal_Bool OColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OColumn::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN };
+}
+
+// OComponentHelper
+void OColumn::disposing()
+{
+ OPropertyContainer::disposing();
+}
+
+// css::beans::XPropertySet
+Reference< XPropertySetInfo > OColumn::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+OUString SAL_CALL OColumn::getName( )
+{
+ return m_sName;
+}
+
+void SAL_CALL OColumn::setName( const OUString& _rName )
+{
+ m_sName = _rName;
+}
+
+void OColumn::registerProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, void* _pPointerToMember, const Type& _rMemberType )
+{
+ ::comphelper::OPropertyContainer::registerProperty( _rName, _nHandle, _nAttributes, _pPointerToMember, _rMemberType );
+}
+
+void OColumn::registerMayBeVoidProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, Any* _pPointerToMember, const Type& _rExpectedType )
+{
+ ::comphelper::OPropertyContainer::registerMayBeVoidProperty( _rName, _nHandle, _nAttributes, _pPointerToMember, _rExpectedType );
+}
+
+// OColumns
+
+OColumns::OColumns(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ bool _bCaseSensitive,const std::vector< OUString> &_rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn,
+ bool _bDropColumn,
+ bool _bUseHardRef)
+ : OColumns_BASE(_rParent,_bCaseSensitive,_rMutex,_rVector,_bUseHardRef)
+ ,m_pMediator(nullptr)
+ ,m_pColFactoryImpl(_pColFactory)
+ ,m_pRefreshColumns(_pRefresh)
+ ,m_bInitialized(false)
+ ,m_bAddColumn(_bAddColumn)
+ ,m_bDropColumn(_bDropColumn)
+{
+}
+
+OColumns::OColumns(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::container::XNameAccess >& _rxDrvColumns,
+ bool _bCaseSensitive,const std::vector< OUString> &_rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn,
+ bool _bDropColumn,
+ bool _bUseHardRef)
+ : OColumns_BASE(_rParent,_bCaseSensitive,_rMutex,_rVector,_bUseHardRef)
+ ,m_pMediator(nullptr)
+ ,m_xDrvColumns(_rxDrvColumns)
+ ,m_pColFactoryImpl(_pColFactory)
+ ,m_pRefreshColumns(_pRefresh)
+ ,m_bInitialized(false)
+ ,m_bAddColumn(_bAddColumn)
+ ,m_bDropColumn(_bDropColumn)
+{
+}
+
+OColumns::~OColumns()
+{
+}
+
+// XServiceInfo
+OUString OColumns::getImplementationName( )
+{
+ return "com.sun.star.sdb.OColumns";
+}
+
+sal_Bool OColumns::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OColumns::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_CONTAINER };
+}
+
+void OColumns::append( const OUString& _rName, OColumn* _pColumn )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ OSL_ENSURE( _pColumn, "OColumns::append: invalid column!" );
+ OSL_ENSURE( !m_pElements->exists( _rName ),"OColumns::append: Column already exists");
+
+ _pColumn->m_sName = _rName;
+
+ // now really insert the column
+ insertElement( _rName, _pColumn );
+}
+
+void OColumns::clearColumns()
+{
+ MutexGuard aGuard(m_rMutex);
+ disposing();
+}
+
+void OColumns::disposing()
+{
+ MutexGuard aGuard(m_rMutex);
+ m_xDrvColumns = nullptr;
+ m_pMediator = nullptr;
+ m_pColFactoryImpl = nullptr;
+ OColumns_BASE::disposing();
+}
+
+void OColumns::impl_refresh()
+{
+ if (m_pRefreshColumns)
+ m_pRefreshColumns->refreshColumns();
+}
+
+connectivity::sdbcx::ObjectType OColumns::createObject(const OUString& _rName)
+{
+ OSL_ENSURE(m_pColFactoryImpl, "OColumns::createObject: no column factory!");
+
+ connectivity::sdbcx::ObjectType xRet;
+ if ( m_pColFactoryImpl )
+ {
+ xRet = m_pColFactoryImpl->createColumn(_rName);
+ Reference<XChild> xChild(xRet,UNO_QUERY);
+ if ( xChild.is() )
+ xChild->setParent(static_cast<XChild*>(static_cast<TXChild*>(this)));
+ }
+
+ Reference<XPropertySet> xDest(xRet,UNO_QUERY);
+ if ( m_pMediator && xDest.is() )
+ m_pMediator->notifyElementCreated(_rName,xDest);
+
+ return xRet;
+}
+
+Reference< XPropertySet > OColumns::createDescriptor()
+{
+ if ( m_pColFactoryImpl )
+ {
+ Reference<XPropertySet> xRet = m_pColFactoryImpl->createColumnDescriptor();
+ Reference<XChild> xChild(xRet,UNO_QUERY);
+ if ( xChild.is() )
+ xChild->setParent(static_cast<XChild*>(static_cast<TXChild*>(this)));
+ return xRet;
+ }
+ else
+ return Reference< XPropertySet >();
+}
+
+Any SAL_CALL OColumns::queryInterface( const Type & rType )
+{
+ Any aRet;
+ if(m_xDrvColumns.is())
+ {
+ aRet = m_xDrvColumns->queryInterface(rType);
+ if ( aRet.hasValue() )
+ aRet = OColumns_BASE::queryInterface( rType);
+ if ( !aRet.hasValue() )
+ aRet = TXChild::queryInterface( rType);
+ return aRet;
+ }
+ else if(!m_pTable || !m_pTable->isNew())
+ {
+ if(!m_bAddColumn && rType == cppu::UnoType<XAppend>::get())
+ return Any();
+ if(!m_bDropColumn && rType == cppu::UnoType<XDrop>::get())
+ return Any();
+ }
+
+ aRet = OColumns_BASE::queryInterface( rType);
+ if ( !aRet.hasValue() )
+ aRet = TXChild::queryInterface( rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OColumns::getTypes( )
+{
+ bool bAppendFound = false,bDropFound = false;
+
+ sal_Int32 nSize = 0;
+ Type aAppendType = cppu::UnoType<XAppend>::get();
+ Type aDropType = cppu::UnoType<XDrop>::get();
+ if(m_xDrvColumns.is())
+ {
+ Reference<XTypeProvider> xTypes(m_xDrvColumns,UNO_QUERY);
+ Sequence< Type > aTypes(xTypes->getTypes());
+
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for (;pBegin != pEnd ; ++pBegin)
+ {
+ if(aAppendType == *pBegin)
+ bAppendFound = true;
+ else if(aDropType == *pBegin)
+ bDropFound = true;
+ }
+ nSize = (bDropFound ? (bAppendFound ? 0 : 1) : (bAppendFound ? 1 : 2));
+ }
+ else
+ {
+ if (m_pTable && m_pTable->isNew())
+ nSize = 0;
+ else if (m_bDropColumn)
+ nSize = m_bAddColumn ? 0 : 1;
+ else
+ nSize = m_bAddColumn ? 1 : 2;
+ bDropFound = (m_pTable && m_pTable->isNew()) || m_bDropColumn;
+ bAppendFound = (m_pTable && m_pTable->isNew()) || m_bAddColumn;
+ }
+ Sequence< Type > aTypes(::comphelper::concatSequences(OColumns_BASE::getTypes(),TXChild::getTypes()));
+ Sequence< Type > aRet(aTypes.getLength() - nSize);
+
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(sal_Int32 i=0;pBegin != pEnd ;++pBegin)
+ {
+ if(*pBegin != aAppendType && *pBegin != aDropType)
+ aRet.getArray()[i++] = *pBegin;
+ else if(bDropFound && *pBegin == aDropType)
+ aRet.getArray()[i++] = *pBegin;
+ else if(bAppendFound && *pBegin == aAppendType)
+ aRet.getArray()[i++] = *pBegin;
+ }
+ return aRet;
+}
+
+// XAppend
+sdbcx::ObjectType OColumns::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ sdbcx::ObjectType xReturn;
+
+ Reference< XAppend > xAppend( m_xDrvColumns, UNO_QUERY );
+ if ( xAppend.is() )
+ {
+ xAppend->appendByDescriptor(descriptor);
+ xReturn = createObject( _rForName );
+ }
+ else if ( m_pTable && !m_pTable->isNew() )
+ {
+ if ( m_bAddColumn )
+ {
+ Reference< css::sdb::tools::XTableAlteration> xAlterService = m_pTable->getAlterService();
+ if ( xAlterService.is() )
+ {
+ xAlterService->addColumn(m_pTable,descriptor);
+ xReturn = createObject( _rForName );
+ }
+ else
+ xReturn = OColumns_BASE::appendObject( _rForName, descriptor );
+ }
+ else
+ ::dbtools::throwGenericSQLException( DBA_RES( RID_STR_NO_COLUMN_ADD ), static_cast<XChild*>(static_cast<TXChild*>(this)) );
+ }
+ else
+ xReturn = cloneDescriptor( descriptor );
+
+ if ( m_pColFactoryImpl )
+ m_pColFactoryImpl->columnAppended( descriptor );
+
+ ::dbaccess::notifyDataSourceModified(m_xParent);
+
+ return xReturn;
+}
+
+// XDrop
+void OColumns::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference< XDrop > xDrop( m_xDrvColumns, UNO_QUERY );
+ if ( xDrop.is() )
+ {
+ xDrop->dropByName( _sElementName );
+ }
+ else if ( m_pTable && !m_pTable->isNew() )
+ {
+ if ( m_bDropColumn )
+ {
+ Reference< css::sdb::tools::XTableAlteration> xAlterService = m_pTable->getAlterService();
+ if ( xAlterService.is() )
+ xAlterService->dropColumn(m_pTable,_sElementName);
+ else
+ OColumns_BASE::dropObject(_nPos,_sElementName);
+ }
+ else
+ ::dbtools::throwGenericSQLException( DBA_RES( RID_STR_NO_COLUMN_DROP ), static_cast<XChild*>(static_cast<TXChild*>(this)) );
+ }
+
+ if ( m_pColFactoryImpl )
+ m_pColFactoryImpl->columnDropped(_sElementName);
+
+ ::dbaccess::notifyDataSourceModified(m_xParent);
+}
+
+Reference< XInterface > SAL_CALL OColumns::getParent( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_xParent;
+}
+
+void SAL_CALL OColumns::setParent( const Reference< XInterface >& _xParent )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ m_xParent = _xParent;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/columnsettings.cxx b/dbaccess/source/core/api/columnsettings.cxx
new file mode 100644
index 000000000..3f62a5a69
--- /dev/null
+++ b/dbaccess/source/core/api/columnsettings.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <columnsettings.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <comphelper/property.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+
+ // OColumnSettings
+
+ OColumnSettings::OColumnSettings()
+ :m_bHidden(false)
+ {
+ }
+
+ OColumnSettings::~OColumnSettings()
+ {
+ }
+
+ void OColumnSettings::registerProperties( IPropertyContainer& _rPropertyContainer )
+ {
+ const sal_Int32 nBoundAttr = PropertyAttribute::BOUND;
+ const sal_Int32 nMayBeVoidAttr = PropertyAttribute::MAYBEVOID | nBoundAttr;
+
+ const Type& rSalInt32Type = ::cppu::UnoType<sal_Int32>::get();
+ const Type& rStringType = ::cppu::UnoType<OUString>::get();
+
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_ALIGN, PROPERTY_ID_ALIGN, nMayBeVoidAttr, &m_aAlignment, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_NUMBERFORMAT, PROPERTY_ID_NUMBERFORMAT, nMayBeVoidAttr, &m_aFormatKey, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_RELATIVEPOSITION, PROPERTY_ID_RELATIVEPOSITION, nMayBeVoidAttr, &m_aRelativePosition, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_WIDTH, PROPERTY_ID_WIDTH, nMayBeVoidAttr, &m_aWidth, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_HELPTEXT, PROPERTY_ID_HELPTEXT, nMayBeVoidAttr, &m_aHelpText, rStringType );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_CONTROLDEFAULT, PROPERTY_ID_CONTROLDEFAULT, nMayBeVoidAttr, &m_aControlDefault, rStringType );
+ _rPropertyContainer.registerProperty( PROPERTY_CONTROLMODEL, PROPERTY_ID_CONTROLMODEL, nBoundAttr, &m_xControlModel, cppu::UnoType<decltype(m_xControlModel)>::get() );
+ _rPropertyContainer.registerProperty( PROPERTY_HIDDEN, PROPERTY_ID_HIDDEN, nBoundAttr, &m_bHidden, cppu::UnoType<decltype(m_bHidden)>::get() );
+ }
+
+ bool OColumnSettings::isColumnSettingProperty( const sal_Int32 _nPropertyHandle )
+ {
+ return ( _nPropertyHandle == PROPERTY_ID_ALIGN )
+ || ( _nPropertyHandle == PROPERTY_ID_NUMBERFORMAT )
+ || ( _nPropertyHandle == PROPERTY_ID_RELATIVEPOSITION )
+ || ( _nPropertyHandle == PROPERTY_ID_WIDTH )
+ || ( _nPropertyHandle == PROPERTY_ID_HELPTEXT )
+ || ( _nPropertyHandle == PROPERTY_ID_CONTROLDEFAULT )
+ || ( _nPropertyHandle == PROPERTY_ID_CONTROLMODEL )
+ || ( _nPropertyHandle == PROPERTY_ID_HIDDEN );
+ }
+
+ bool OColumnSettings::isDefaulted( const sal_Int32 _nPropertyHandle, const Any& _rPropertyValue )
+ {
+ switch ( _nPropertyHandle )
+ {
+ case PROPERTY_ID_ALIGN:
+ case PROPERTY_ID_NUMBERFORMAT:
+ case PROPERTY_ID_RELATIVEPOSITION:
+ case PROPERTY_ID_WIDTH:
+ case PROPERTY_ID_HELPTEXT:
+ case PROPERTY_ID_CONTROLDEFAULT:
+ return !_rPropertyValue.hasValue();
+
+ case PROPERTY_ID_CONTROLMODEL:
+ return !Reference< XPropertySet >( _rPropertyValue, UNO_QUERY ).is();
+
+ case PROPERTY_ID_HIDDEN:
+ {
+ bool bHidden = false;
+ OSL_VERIFY( _rPropertyValue >>= bHidden );
+ return !bHidden;
+ }
+ }
+ OSL_FAIL( "OColumnSettings::isDefaulted: illegal property handle!" );
+ return false;
+ }
+
+ bool OColumnSettings::hasDefaultSettings( const Reference< XPropertySet >& _rxColumn )
+ {
+ ENSURE_OR_THROW( _rxColumn.is(), "illegal column" );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( _rxColumn->getPropertySetInfo(), UNO_SET_THROW );
+
+ struct PropertyDescriptor
+ {
+ OUString sName;
+ sal_Int32 nHandle;
+ };
+ const PropertyDescriptor aProps[] =
+ {
+ { OUString(PROPERTY_ALIGN), PROPERTY_ID_ALIGN },
+ { OUString(PROPERTY_NUMBERFORMAT), PROPERTY_ID_NUMBERFORMAT },
+ { OUString(PROPERTY_RELATIVEPOSITION), PROPERTY_ID_RELATIVEPOSITION },
+ { OUString(PROPERTY_WIDTH), PROPERTY_ID_WIDTH },
+ { OUString(PROPERTY_HELPTEXT), PROPERTY_ID_HELPTEXT },
+ { OUString(PROPERTY_CONTROLDEFAULT), PROPERTY_ID_CONTROLDEFAULT },
+ { OUString(PROPERTY_CONTROLMODEL), PROPERTY_ID_CONTROLMODEL },
+ { OUString(PROPERTY_HIDDEN), PROPERTY_ID_HIDDEN }
+ };
+
+ for (const auto & aProp : aProps)
+ {
+ if ( xPSI->hasPropertyByName( aProp.sName ) )
+ if ( !isDefaulted( aProp.nHandle, _rxColumn->getPropertyValue( aProp.sName ) ) )
+ return false;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return true;
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/datacolumn.cxx b/dbaccess/source/core/api/datacolumn.cxx
new file mode 100644
index 000000000..c597a4064
--- /dev/null
+++ b/dbaccess/source/core/api/datacolumn.cxx
@@ -0,0 +1,396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "datacolumn.hxx"
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <strings.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+
+ODataColumn::ODataColumn(
+ const Reference < XResultSetMetaData >& _xMetaData,
+ const Reference < XRow >& _xRow,
+ const Reference < XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta)
+ :OResultColumn(_xMetaData, _nPos, _rxDBMeta)
+ ,m_xRow(_xRow)
+ ,m_xRowUpdate(_xRowUpdate)
+{
+}
+
+ODataColumn::~ODataColumn()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > ODataColumn::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XColumn>::get(),
+ cppu::UnoType<XColumnUpdate>::get(),
+ OColumn::getTypes());
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > ODataColumn::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any SAL_CALL ODataColumn::queryInterface( const Type & _rType )
+{
+ Any aReturn = OResultColumn::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< XColumn* >(this),
+ static_cast< XColumnUpdate* >(this)
+ );
+ return aReturn;
+}
+
+// XServiceInfo
+OUString ODataColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.ODataColumn";
+}
+
+Sequence< OUString > ODataColumn::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN, SERVICE_SDB_RESULTCOLUMN, SERVICE_SDB_DATACOLUMN };
+}
+
+// OComponentHelper
+void ODataColumn::disposing()
+{
+ OResultColumn::disposing();
+
+ m_xRow = nullptr;
+ m_xRowUpdate = nullptr;
+}
+
+// css::sdb::XColumn
+sal_Bool ODataColumn::wasNull()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->wasNull();
+}
+
+OUString ODataColumn::getString()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getString(m_nPos);
+}
+
+sal_Bool ODataColumn::getBoolean()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBoolean(m_nPos);
+}
+
+sal_Int8 ODataColumn::getByte()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getByte(m_nPos);
+}
+
+sal_Int16 ODataColumn::getShort()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getShort(m_nPos);
+}
+
+sal_Int32 ODataColumn::getInt()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getInt(m_nPos);
+}
+
+sal_Int64 ODataColumn::getLong()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getLong(m_nPos);
+}
+
+float ODataColumn::getFloat()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getFloat(m_nPos);
+}
+
+double ODataColumn::getDouble()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getDouble(m_nPos);
+}
+
+Sequence< sal_Int8 > ODataColumn::getBytes()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBytes(m_nPos);
+}
+
+css::util::Date ODataColumn::getDate()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getDate(m_nPos);
+}
+
+css::util::Time ODataColumn::getTime()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getTime(m_nPos);
+}
+
+css::util::DateTime ODataColumn::getTimestamp()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getTimestamp(m_nPos);
+}
+
+Reference< css::io::XInputStream > ODataColumn::getBinaryStream()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBinaryStream(m_nPos);
+}
+
+Reference< css::io::XInputStream > ODataColumn::getCharacterStream()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getCharacterStream(m_nPos);
+}
+
+Any ODataColumn::getObject(const Reference< css::container::XNameAccess > & typeMap)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getObject(m_nPos, typeMap);
+}
+
+Reference< XRef > ODataColumn::getRef()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getRef(m_nPos);
+}
+
+Reference< XBlob > ODataColumn::getBlob()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBlob(m_nPos);
+}
+
+Reference< XClob > ODataColumn::getClob()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getClob(m_nPos);
+}
+
+Reference< XArray > ODataColumn::getArray()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getArray(m_nPos);
+}
+
+// css::sdb::XColumnUpdate
+void ODataColumn::updateNull()
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateNull(m_nPos);
+}
+
+void ODataColumn::updateBoolean(sal_Bool x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateBoolean(m_nPos, x);
+}
+
+void ODataColumn::updateByte(sal_Int8 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateByte(m_nPos, x);
+}
+
+void ODataColumn::updateShort(sal_Int16 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateShort(m_nPos, x);
+}
+
+void ODataColumn::updateInt(sal_Int32 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateInt(m_nPos, x);
+}
+
+void ODataColumn::updateLong(sal_Int64 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateLong(m_nPos, x);
+}
+
+void ODataColumn::updateFloat(float x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateFloat(m_nPos, x);
+}
+
+void ODataColumn::updateDouble(double x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateDouble(m_nPos, x);
+}
+
+void ODataColumn::updateString(const OUString& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateString(m_nPos, x);
+}
+
+void ODataColumn::updateBytes(const Sequence< sal_Int8 >& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateBytes(m_nPos, x);
+}
+
+void ODataColumn::updateDate(const css::util::Date& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateDate(m_nPos, x);
+}
+
+void ODataColumn::updateTime(const css::util::Time& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateTime(m_nPos, x);
+}
+
+void ODataColumn::updateTimestamp(const css::util::DateTime& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateTimestamp(m_nPos, x);
+}
+
+void ODataColumn::updateCharacterStream(const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateCharacterStream(m_nPos, x, length);
+}
+
+void ODataColumn::updateBinaryStream(const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateBinaryStream(m_nPos, x, length);
+}
+
+void ODataColumn::updateNumericObject(const Any& x, sal_Int32 scale)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateNumericObject(m_nPos, x, scale);
+}
+
+void ODataColumn::updateObject(const Any& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateObject(m_nPos, x);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/datacolumn.hxx b/dbaccess/source/core/api/datacolumn.hxx
new file mode 100644
index 000000000..46512d945
--- /dev/null
+++ b/dbaccess/source/core/api/datacolumn.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+#include "resultcolumn.hxx"
+namespace dbaccess
+{
+
+ // ODataColumn
+
+ class ODataColumn : public OResultColumn,
+ public css::sdb::XColumn,
+ public css::sdb::XColumnUpdate
+ {
+ css::uno::Reference < css::sdbc::XRow > m_xRow;
+ css::uno::Reference < css::sdbc::XRowUpdate > m_xRowUpdate;
+ protected:
+ virtual ~ODataColumn() override;
+ public:
+ ODataColumn (const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ const css::uno::Reference < css::sdbc::XRow >& _xRow,
+ const css::uno::Reference < css::sdbc::XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta);
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override { OResultColumn::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OResultColumn::release(); }
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdb::XColumn
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( ) override;
+ virtual sal_Bool SAL_CALL getBoolean( ) override;
+ virtual sal_Int8 SAL_CALL getByte( ) override;
+ virtual sal_Int16 SAL_CALL getShort( ) override;
+ virtual sal_Int32 SAL_CALL getInt( ) override;
+ virtual sal_Int64 SAL_CALL getLong( ) override;
+ virtual float SAL_CALL getFloat( ) override;
+ virtual double SAL_CALL getDouble( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( ) override;
+ virtual css::util::Date SAL_CALL getDate( ) override;
+ virtual css::util::Time SAL_CALL getTime( ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( ) override;
+ virtual css::uno::Any SAL_CALL getObject( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( ) override;
+
+ // css::sdb::XColumnUpdate
+ virtual void SAL_CALL updateNull( ) override;
+ virtual void SAL_CALL updateBoolean( sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( float x ) override;
+ virtual void SAL_CALL updateDouble( double x ) override;
+ virtual void SAL_CALL updateString( const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( const css::uno::Any& x, sal_Int32 scale ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/datasettings.cxx b/dbaccess/source/core/api/datasettings.cxx
new file mode 100644
index 000000000..e845f1135
--- /dev/null
+++ b/dbaccess/source/core/api/datasettings.cxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <datasettings.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/awt/FontEmphasisMark.hpp>
+#include <com/sun/star/awt/FontRelief.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+// ODataSettings
+void ODataSettings::registerPropertiesFor(ODataSettings_Base* _pItem)
+{
+ if ( m_bQuery )
+ {
+ registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND,
+ &_pItem->m_sHavingClause, cppu::UnoType<decltype(_pItem->m_sHavingClause)>::get());
+
+ registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND,
+ &_pItem->m_sGroupBy, cppu::UnoType<decltype(_pItem->m_sGroupBy)>::get());
+ }
+
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND,
+ &_pItem->m_sFilter, cppu::UnoType<decltype(_pItem->m_sFilter)>::get());
+
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND,
+ &_pItem->m_sOrder, cppu::UnoType<decltype(_pItem->m_sOrder)>::get());
+
+ registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND,
+ &_pItem->m_bApplyFilter, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_FONT, PROPERTY_ID_FONT, PropertyAttribute::BOUND,
+ &_pItem->m_aFont, cppu::UnoType<decltype(_pItem->m_aFont)>::get());
+
+ registerMayBeVoidProperty(PROPERTY_ROW_HEIGHT, PROPERTY_ID_ROW_HEIGHT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &_pItem->m_aRowHeight, ::cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_AUTOGROW, PROPERTY_ID_AUTOGROW, PropertyAttribute::BOUND,
+ &_pItem->m_bAutoGrow, cppu::UnoType<bool>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTCOLOR, PROPERTY_ID_TEXTCOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &_pItem->m_aTextColor, ::cppu::UnoType<sal_Int32>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTLINECOLOR, PROPERTY_ID_TEXTLINECOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &_pItem->m_aTextLineColor, ::cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_TEXTEMPHASIS, PROPERTY_ID_TEXTEMPHASIS, PropertyAttribute::BOUND,
+ &_pItem->m_nFontEmphasis, cppu::UnoType<decltype(_pItem->m_nFontEmphasis)>::get());
+
+ registerProperty(PROPERTY_TEXTRELIEF, PROPERTY_ID_TEXTRELIEF, PropertyAttribute::BOUND,&_pItem->m_nFontRelief, cppu::UnoType<decltype(_pItem->m_nFontRelief)>::get());
+
+ registerProperty(PROPERTY_FONTNAME, PROPERTY_ID_FONTNAME, PropertyAttribute::BOUND,&_pItem->m_aFont.Name, cppu::UnoType<decltype(_pItem->m_aFont.Name)>::get());
+ registerProperty(PROPERTY_FONTHEIGHT, PROPERTY_ID_FONTHEIGHT, PropertyAttribute::BOUND,&_pItem->m_aFont.Height, cppu::UnoType<decltype(_pItem->m_aFont.Height)>::get());
+ registerProperty(PROPERTY_FONTWIDTH, PROPERTY_ID_FONTWIDTH, PropertyAttribute::BOUND,&_pItem->m_aFont.Width, cppu::UnoType<decltype(_pItem->m_aFont.Width)>::get());
+ registerProperty(PROPERTY_FONTSTYLENAME, PROPERTY_ID_FONTSTYLENAME, PropertyAttribute::BOUND,&_pItem->m_aFont.StyleName, cppu::UnoType<decltype(_pItem->m_aFont.StyleName)>::get());
+ registerProperty(PROPERTY_FONTFAMILY, PROPERTY_ID_FONTFAMILY, PropertyAttribute::BOUND,&_pItem->m_aFont.Family, cppu::UnoType<decltype(_pItem->m_aFont.Family)>::get());
+ registerProperty(PROPERTY_FONTCHARSET, PROPERTY_ID_FONTCHARSET, PropertyAttribute::BOUND,&_pItem->m_aFont.CharSet, cppu::UnoType<decltype(_pItem->m_aFont.CharSet)>::get());
+ registerProperty(PROPERTY_FONTPITCH, PROPERTY_ID_FONTPITCH, PropertyAttribute::BOUND,&_pItem->m_aFont.Pitch, cppu::UnoType<decltype(_pItem->m_aFont.Pitch)>::get());
+ registerProperty(PROPERTY_FONTCHARWIDTH, PROPERTY_ID_FONTCHARWIDTH, PropertyAttribute::BOUND,&_pItem->m_aFont.CharacterWidth, cppu::UnoType<decltype(_pItem->m_aFont.CharacterWidth)>::get());
+ registerProperty(PROPERTY_FONTWEIGHT, PROPERTY_ID_FONTWEIGHT, PropertyAttribute::BOUND,&_pItem->m_aFont.Weight, cppu::UnoType<decltype(_pItem->m_aFont.Weight)>::get());
+ registerProperty(PROPERTY_FONTSLANT, PROPERTY_ID_FONTSLANT, PropertyAttribute::BOUND,&_pItem->m_aFont.Slant, cppu::UnoType<decltype(_pItem->m_aFont.Slant)>::get());
+ registerProperty(PROPERTY_FONTUNDERLINE, PROPERTY_ID_FONTUNDERLINE, PropertyAttribute::BOUND,&_pItem->m_aFont.Underline, cppu::UnoType<decltype(_pItem->m_aFont.Underline)>::get());
+ registerProperty(PROPERTY_FONTSTRIKEOUT, PROPERTY_ID_FONTSTRIKEOUT, PropertyAttribute::BOUND,&_pItem->m_aFont.Strikeout, cppu::UnoType<decltype(_pItem->m_aFont.Strikeout)>::get());
+ registerProperty(PROPERTY_FONTORIENTATION, PROPERTY_ID_FONTORIENTATION, PropertyAttribute::BOUND,&_pItem->m_aFont.Orientation, cppu::UnoType<decltype(_pItem->m_aFont.Orientation)>::get());
+ registerProperty(PROPERTY_FONTKERNING, PROPERTY_ID_FONTKERNING, PropertyAttribute::BOUND,&_pItem->m_aFont.Kerning, cppu::UnoType<decltype(_pItem->m_aFont.Kerning)>::get());
+ registerProperty(PROPERTY_FONTWORDLINEMODE, PROPERTY_ID_FONTWORDLINEMODE,PropertyAttribute::BOUND,&_pItem->m_aFont.WordLineMode, cppu::UnoType<decltype(_pItem->m_aFont.WordLineMode)>::get());
+ registerProperty(PROPERTY_FONTTYPE, PROPERTY_ID_FONTTYPE, PropertyAttribute::BOUND,&_pItem->m_aFont.Type, cppu::UnoType<decltype(_pItem->m_aFont.Type)>::get());
+}
+
+ODataSettings::ODataSettings(OBroadcastHelper& _rBHelper,bool _bQuery)
+ :OPropertyStateContainer(_rBHelper)
+ ,m_bQuery(_bQuery)
+{
+}
+
+ODataSettings_Base::ODataSettings_Base()
+ :m_bApplyFilter(false)
+ ,m_bAutoGrow(false)
+ ,m_aFont(::comphelper::getDefaultFont())
+ ,m_nFontEmphasis(css::awt::FontEmphasisMark::NONE)
+ ,m_nFontRelief(css::awt::FontRelief::NONE)
+{
+}
+
+ODataSettings_Base::~ODataSettings_Base()
+{
+}
+
+void ODataSettings::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const
+{
+ static css::awt::FontDescriptor aFD = ::comphelper::getDefaultFont();
+ switch( _nHandle )
+ {
+ case PROPERTY_ID_HAVING_CLAUSE:
+ case PROPERTY_ID_GROUP_BY:
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ _rDefault <<= OUString();
+ break;
+ case PROPERTY_ID_FONT:
+ _rDefault <<= ::comphelper::getDefaultFont();
+ break;
+ case PROPERTY_ID_APPLYFILTER:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_TEXTRELIEF:
+ _rDefault <<= css::awt::FontRelief::NONE;
+ break;
+ case PROPERTY_ID_TEXTEMPHASIS:
+ _rDefault <<= css::awt::FontEmphasisMark::NONE;
+ break;
+ case PROPERTY_ID_FONTNAME:
+ _rDefault <<= aFD.Name;
+ break;
+ case PROPERTY_ID_FONTHEIGHT:
+ _rDefault <<= aFD.Height;
+ break;
+ case PROPERTY_ID_FONTWIDTH:
+ _rDefault <<= aFD.Width;
+ break;
+ case PROPERTY_ID_FONTSTYLENAME:
+ _rDefault <<= aFD.StyleName;
+ break;
+ case PROPERTY_ID_FONTFAMILY:
+ _rDefault <<= aFD.Family;
+ break;
+ case PROPERTY_ID_FONTCHARSET:
+ _rDefault <<= aFD.CharSet;
+ break;
+ case PROPERTY_ID_FONTPITCH:
+ _rDefault <<= aFD.Pitch;
+ break;
+ case PROPERTY_ID_FONTCHARWIDTH:
+ _rDefault <<= aFD.CharacterWidth;
+ break;
+ case PROPERTY_ID_FONTWEIGHT:
+ _rDefault <<= aFD.Weight;
+ break;
+ case PROPERTY_ID_FONTSLANT:
+ _rDefault <<= aFD.Slant;
+ break;
+ case PROPERTY_ID_FONTUNDERLINE:
+ _rDefault <<= aFD.Underline;
+ break;
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ _rDefault <<= aFD.Strikeout;
+ break;
+ case PROPERTY_ID_FONTORIENTATION:
+ _rDefault <<= aFD.Orientation;
+ break;
+ case PROPERTY_ID_FONTKERNING:
+ _rDefault <<= aFD.Kerning;
+ break;
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ _rDefault <<= aFD.WordLineMode;
+ break;
+ case PROPERTY_ID_FONTTYPE:
+ _rDefault <<= aFD.Type;
+ break;
+ }
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/definitioncolumn.cxx b/dbaccess/source/core/api/definitioncolumn.cxx
new file mode 100644
index 000000000..3f9542180
--- /dev/null
+++ b/dbaccess/source/core/api/definitioncolumn.cxx
@@ -0,0 +1,610 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <bitset>
+
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <definitioncolumn.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+
+#include <comphelper/property.hxx>
+#include <connectivity/dbtools.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+using namespace ::comphelper;
+using namespace ::osl;
+using namespace dbaccess;
+
+namespace
+{
+ const sal_Int32 HAS_DESCRIPTION = 0x00000001;
+ const sal_Int32 HAS_DEFAULTVALUE = 0x00000002;
+ const sal_Int32 HAS_ROWVERSION = 0x00000004;
+ const sal_Int32 HAS_AUTOINCREMENT_CREATION = 0x00000008;
+ const sal_Int32 HAS_CATALOGNAME = 0x00000010;
+ const sal_Int32 HAS_SCHEMANAME = 0x00000020;
+ const sal_Int32 HAS_TABLENAME = 0x00000040;
+}
+
+// OTableColumnDescriptor
+IMPLEMENT_FORWARD_XINTERFACE2(OTableColumnDescriptor,OColumn,TXChild)
+
+void OTableColumnDescriptor::impl_registerProperties()
+{
+ sal_Int32 nDefaultAttr = m_bActAsDescriptor ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty( PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, nDefaultAttr, &m_aTypeName, cppu::UnoType<decltype(m_aTypeName)>::get() );
+ registerProperty( PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, nDefaultAttr, &m_aDescription, cppu::UnoType<decltype(m_aDescription)>::get() );
+ registerProperty( PROPERTY_DEFAULTVALUE, PROPERTY_ID_DEFAULTVALUE, nDefaultAttr, &m_aDefaultValue, cppu::UnoType<decltype(m_aDefaultValue)>::get() );
+
+ if ( m_bActAsDescriptor )
+ registerProperty( PROPERTY_AUTOINCREMENTCREATION, PROPERTY_ID_AUTOINCREMENTCREATION, nDefaultAttr, &m_aAutoIncrementValue, cppu::UnoType<decltype(m_aAutoIncrementValue)>::get() );
+
+ registerProperty( PROPERTY_TYPE, PROPERTY_ID_TYPE, nDefaultAttr, &m_nType, cppu::UnoType<decltype(m_nType)>::get() );
+ registerProperty( PROPERTY_PRECISION, PROPERTY_ID_PRECISION, nDefaultAttr, &m_nPrecision, cppu::UnoType<decltype(m_nPrecision)>::get() );
+ registerProperty( PROPERTY_SCALE, PROPERTY_ID_SCALE, nDefaultAttr, &m_nScale, cppu::UnoType<decltype(m_nScale)>::get() );
+ registerProperty( PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, nDefaultAttr, &m_nIsNullable, cppu::UnoType<decltype(m_nIsNullable)>::get() );
+ registerProperty( PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, nDefaultAttr, &m_bAutoIncrement, cppu::UnoType<decltype(m_bAutoIncrement)>::get() );
+ registerProperty( PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, nDefaultAttr, &m_bRowVersion, cppu::UnoType<decltype(m_bRowVersion)>::get() );
+ registerProperty( PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, nDefaultAttr, &m_bCurrency, cppu::UnoType<decltype(m_bCurrency)>::get() );
+
+ OColumnSettings::registerProperties( *this );
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumnDescriptor )
+
+// css::lang::XServiceInfo
+OUString OTableColumnDescriptor::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumnDescriptor";
+}
+
+Sequence< OUString > OTableColumnDescriptor::getSupportedServiceNames( )
+{
+ return { m_bActAsDescriptor? OUString(SERVICE_SDBCX_COLUMNDESCRIPTOR) : OUString(SERVICE_SDBCX_COLUMN),
+ SERVICE_SDB_COLUMNSETTINGS };
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OTableColumnDescriptor::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OTableColumnDescriptor::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< OTableColumnDescriptor >* >(this)->getArrayHelper();
+}
+
+void OTableColumnDescriptor::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ OColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ ::dbaccess::notifyDataSourceModified( m_xParent );
+}
+
+Reference< XInterface > SAL_CALL OTableColumnDescriptor::getParent( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return m_xParent;
+}
+
+void SAL_CALL OTableColumnDescriptor::setParent( const Reference< XInterface >& _xParent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xParent = _xParent;
+}
+
+// OTableColumn
+
+OTableColumn::OTableColumn( const OUString& _rName )
+ :OTableColumnDescriptor( false /* do not act as descriptor */ )
+{
+ m_sName = _rName;
+}
+
+OTableColumn::~OTableColumn()
+{
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumn )
+
+OUString OTableColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumn";
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OTableColumn::getInfoHelper()
+{
+ return *OTableColumn_PBase::getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OTableColumn::createArrayHelper( ) const
+{
+ return OTableColumnDescriptor::createArrayHelper();
+}
+
+// OQueryColumn
+
+OQueryColumn::OQueryColumn( const Reference< XPropertySet >& _rxParserColumn, const Reference< XConnection >& _rxConnection, const OUString &i_sLabel )
+ :OTableColumnDescriptor( false /* do not act as descriptor */ )
+ ,m_sLabel(i_sLabel)
+{
+ const sal_Int32 nPropAttr = PropertyAttribute::READONLY;
+ registerProperty( PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, nPropAttr, &m_sCatalogName, cppu::UnoType<decltype(m_sCatalogName)>::get() );
+ registerProperty( PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, nPropAttr, &m_sSchemaName, cppu::UnoType<decltype(m_sSchemaName)>::get() );
+ registerProperty( PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, nPropAttr, &m_sTableName, cppu::UnoType<decltype(m_sTableName)>::get() );
+ registerProperty( PROPERTY_REALNAME, PROPERTY_ID_REALNAME, nPropAttr, &m_sRealName, cppu::UnoType<decltype(m_sRealName)>::get() );
+ registerProperty( PROPERTY_LABEL, PROPERTY_ID_LABEL, nPropAttr, &m_sLabel, cppu::UnoType<decltype(m_sLabel)>::get() );
+
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_TYPENAME ) >>= m_aTypeName) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_TYPENAME);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= m_nIsNullable) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_ISNULLABLE);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_PRECISION ) >>= m_nPrecision) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_PRECISION);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_SCALE ) >>= m_nScale) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_SCALE);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_TYPE ) >>= m_nType) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_TYPE);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_ISAUTOINCREMENT ) >>= m_bAutoIncrement) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_ISAUTOINCREMENT);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_ISCURRENCY ) >>= m_bCurrency) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_ISCURRENCY);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_NAME ) >>= m_sName) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_NAME);
+
+ m_bRowVersion = false;
+
+ Reference< XPropertySetInfo > xPSI( _rxParserColumn->getPropertySetInfo(), UNO_SET_THROW );
+ if ( xPSI->hasPropertyByName( PROPERTY_DEFAULTVALUE ) )
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_DEFAULTVALUE ) >>= m_aDefaultValue) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_DEFAULTVALUE);
+
+ // copy some optional properties from the parser column
+ struct PropertyDescriptor
+ {
+ OUString sName;
+ sal_Int32 nHandle;
+ };
+ const PropertyDescriptor aProps[] =
+ {
+ { OUString(PROPERTY_CATALOGNAME), PROPERTY_ID_CATALOGNAME },
+ { OUString(PROPERTY_SCHEMANAME), PROPERTY_ID_SCHEMANAME },
+ { OUString(PROPERTY_TABLENAME), PROPERTY_ID_TABLENAME },
+ { OUString(PROPERTY_REALNAME), PROPERTY_ID_REALNAME }
+ };
+ for (const auto & aProp : aProps)
+ {
+ if ( xPSI->hasPropertyByName( aProp.sName ) )
+ setFastPropertyValue_NoBroadcast( aProp.nHandle, _rxParserColumn->getPropertyValue( aProp.sName ) );
+ }
+
+ // determine the table column we're based on
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xOriginalTableColumn = impl_determineOriginalTableColumn( _rxConnection );
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OQueryColumn::~OQueryColumn()
+{
+}
+
+Reference< XPropertySet > OQueryColumn::impl_determineOriginalTableColumn( const Reference< XConnection >& _rxConnection )
+{
+ OSL_PRECOND( _rxConnection.is(), "OQueryColumn::impl_determineOriginalTableColumn: illegal connection!" );
+ if ( !_rxConnection.is() )
+ return nullptr;
+
+ Reference< XPropertySet > xOriginalTableColumn;
+ try
+ {
+ // determine the composed table name, plus the column name, as indicated by the
+ // respective properties
+ OUString sCatalog, sSchema, sTable;
+ if( ! (getPropertyValue( PROPERTY_CATALOGNAME ) >>= sCatalog) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_CATALOGNAME);
+ if( ! (getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_SCHEMANAME);
+ if( ! (getPropertyValue( PROPERTY_TABLENAME ) >>= sTable) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_TABLENAME);
+ if ( sCatalog.isEmpty() && sSchema.isEmpty() && sTable.isEmpty() )
+ return nullptr;
+
+ OUString sComposedTableName = ::dbtools::composeTableName(
+ _rxConnection->getMetaData(), sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::Complete );
+
+ // retrieve the table in question
+ Reference< XTablesSupplier > xSuppTables( _rxConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xTables( xSuppTables->getTables(), UNO_SET_THROW );
+ if ( !xTables->hasByName( sComposedTableName ) )
+ return nullptr;
+
+ Reference< XColumnsSupplier > xSuppCols( xTables->getByName( sComposedTableName ), UNO_QUERY_THROW );
+ Reference< XNameAccess > xColumns( xSuppCols->getColumns(), UNO_SET_THROW );
+
+ OUString sColumn;
+ if( ! (getPropertyValue( PROPERTY_REALNAME ) >>= sColumn) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_REALNAME);
+ if ( !xColumns->hasByName( sColumn ) )
+ return nullptr;
+
+ xOriginalTableColumn.set( xColumns->getByName( sColumn ), UNO_QUERY );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xOriginalTableColumn;
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OQueryColumn )
+
+OUString SAL_CALL OQueryColumn::getImplementationName( )
+{
+ return "org.openoffice.comp.dbaccess.OQueryColumn";
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OQueryColumn::getInfoHelper()
+{
+ return *OQueryColumn_PBase::getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OQueryColumn::createArrayHelper() const
+{
+ return OTableColumnDescriptor::createArrayHelper();
+}
+
+void SAL_CALL OQueryColumn::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+{
+ OTableColumnDescriptor::getFastPropertyValue( _rValue, _nHandle );
+
+ // special treatment for column settings:
+ if ( !OColumnSettings::isColumnSettingProperty( _nHandle ) )
+ return;
+
+ // If the setting has its default value, then try to obtain the value from the table column which
+ // this query column is based on
+ if ( !OColumnSettings::isDefaulted( _nHandle, _rValue ) )
+ return;
+
+ if ( !m_xOriginalTableColumn.is() )
+ return;
+
+ try
+ {
+ // determine original property name
+ OUString sPropName;
+ sal_Int16 nAttributes( 0 );
+ const_cast< OQueryColumn* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle );
+ OSL_ENSURE( !sPropName.isEmpty(), "OColumnWrapper::impl_getPropertyNameFromHandle: property not found!" );
+
+ _rValue = m_xOriginalTableColumn->getPropertyValue( sPropName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+// OColumnWrapper
+
+OColumnWrapper::OColumnWrapper( const Reference< XPropertySet > & rCol, const bool _bNameIsReadOnly )
+ :OColumn( _bNameIsReadOnly )
+ ,m_xAggregate(rCol)
+ ,m_nColTypeID(-1)
+{
+ // which type of aggregate property do we have?
+ // we distinguish the properties by the containment of optional properties
+ m_nColTypeID = 0;
+ if ( !m_xAggregate.is() )
+ return;
+
+ Reference <XPropertySetInfo > xInfo(m_xAggregate->getPropertySetInfo());
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_DESCRIPTION) ? HAS_DESCRIPTION : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE) ? HAS_DEFAULTVALUE : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_ISROWVERSION) ? HAS_ROWVERSION : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ? HAS_AUTOINCREMENT_CREATION : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_CATALOGNAME) ? HAS_CATALOGNAME : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_SCHEMANAME) ? HAS_SCHEMANAME : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_TABLENAME) ? HAS_TABLENAME : 0;
+
+ m_xAggregate->getPropertyValue(PROPERTY_NAME) >>= m_sName;
+}
+
+OColumnWrapper::~OColumnWrapper()
+{
+}
+
+OUString OColumnWrapper::impl_getPropertyNameFromHandle( const sal_Int32 _nHandle ) const
+{
+ OUString sPropName;
+ sal_Int16 nAttributes( 0 );
+ const_cast< OColumnWrapper* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle );
+ OSL_ENSURE( !sPropName.isEmpty(), "OColumnWrapper::impl_getPropertyNameFromHandle: property not found!" );
+ return sPropName;
+}
+
+void OColumnWrapper::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ // derived classes are free to either use the OPropertyContainer(Helper) mechanisms for properties,
+ // or to declare additional properties which are to be forwarded to the wrapped object. So we need
+ // to distinguish those cases.
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ OColumn::getFastPropertyValue( rValue, nHandle );
+ }
+ else
+ {
+ rValue = m_xAggregate->getPropertyValue( impl_getPropertyNameFromHandle( nHandle ) );
+ }
+}
+
+sal_Bool OColumnWrapper::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bModified( false );
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ bModified = OColumn::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
+ }
+ else
+ {
+ getFastPropertyValue( rOldValue, nHandle );
+ if ( rOldValue != rValue )
+ {
+ rConvertedValue = rValue;
+ bModified = true;
+ }
+ }
+ return bModified;
+}
+
+void OColumnWrapper::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ OColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ }
+ else
+ {
+ m_xAggregate->setPropertyValue( impl_getPropertyNameFromHandle( nHandle ), rValue );
+ }
+}
+
+// OTableColumnDescriptorWrapper
+OTableColumnDescriptorWrapper::OTableColumnDescriptorWrapper( const Reference< XPropertySet >& _rCol, const bool _bPureWrap, const bool _bIsDescriptor )
+ :OColumnWrapper( _rCol, !_bIsDescriptor )
+ ,m_bPureWrap( _bPureWrap )
+ ,m_bIsDescriptor( _bIsDescriptor )
+{
+ // let the ColumnSettings register its properties
+ OColumnSettings::registerProperties( *this );
+}
+
+// css::lang::XTypeProvider
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumnDescriptorWrapper )
+
+// css::lang::XServiceInfo
+OUString OTableColumnDescriptorWrapper::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumnDescriptorWrapper";
+}
+
+Sequence< OUString > OTableColumnDescriptorWrapper::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMNDESCRIPTOR, SERVICE_SDB_COLUMNSETTINGS };
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OTableColumnDescriptorWrapper::createArrayHelper( sal_Int32 nId ) const
+{
+ const sal_Int32 nHaveAlways = 7;
+
+ // Which optional properties are contained?
+ const sal_Int32 nHaveOptionally (std::bitset<7>(nId).count());
+
+ css::uno::Sequence< css::beans::Property> aDescriptor(nHaveAlways + nHaveOptionally);
+ css::beans::Property* pDesc = aDescriptor.getArray();
+ sal_Int32 nPos = 0;
+
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString >::get(), 0);
+
+ if ( nId & HAS_AUTOINCREMENT_CREATION )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_AUTOINCREMENTCREATION, PROPERTY_ID_AUTOINCREMENTCREATION, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID );
+ }
+ if ( nId & HAS_DEFAULTVALUE )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_DEFAULTVALUE, PROPERTY_ID_DEFAULTVALUE, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_DESCRIPTION )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_ROWVERSION )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), 0);
+ }
+ if ( nId & HAS_CATALOGNAME )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_SCHEMANAME )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_TABLENAME )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString >::get(), 0);
+ }
+
+ OSL_ENSURE(nPos == aDescriptor.getLength(), "forgot to adjust the count ?");
+
+ if ( !m_bIsDescriptor )
+ {
+ for ( auto & prop : asNonConstRange(aDescriptor) )
+ {
+ prop.Attributes |= PropertyAttribute::READONLY;
+ }
+ }
+
+ // finally also describe the properties which are maintained by our base class, in particular the OPropertyContainerHelper
+ Sequence< Property > aBaseProperties;
+ describeProperties( aBaseProperties );
+
+ Sequence< Property > aAllProperties( ::comphelper::concatSequences( aDescriptor, aBaseProperties ) );
+ return new ::cppu::OPropertyArrayHelper( aAllProperties, false );
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OTableColumnDescriptorWrapper::getInfoHelper()
+{
+ return *static_cast< OIdPropertyArrayUsageHelper< OTableColumnDescriptorWrapper >* >(this)->getArrayHelper(m_nColTypeID);
+}
+
+void OTableColumnDescriptorWrapper::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ if ( m_bPureWrap )
+ {
+ rValue = m_xAggregate->getPropertyValue( impl_getPropertyNameFromHandle( nHandle ) );
+ }
+ else
+ {
+ OColumnWrapper::getFastPropertyValue( rValue, nHandle );
+ }
+}
+
+sal_Bool OTableColumnDescriptorWrapper::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bModified(false);
+ if ( m_bPureWrap )
+ {
+ // do not delegate to OColumnWrapper: It would, for the properties which were registered with registerProperty,
+ // ask the OPropertyContainer base class, which is not what we want here.
+ // TODO: the whole "m_bPureWrap"-thingie is strange. We should have a dedicated class doing this wrapping,
+ // not a class which normally serves other purposes, and only sometimes does a "pure wrap". It makes the
+ // code unnecessarily hard to maintain, and error prone.
+ rOldValue = m_xAggregate->getPropertyValue( impl_getPropertyNameFromHandle( nHandle ) );
+ if ( rOldValue != rValue )
+ {
+ rConvertedValue = rValue;
+ bModified = true;
+ }
+ }
+ else
+ {
+ bModified = OColumnWrapper::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
+ }
+ return bModified;
+}
+
+void OTableColumnDescriptorWrapper::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const Any& rValue
+ )
+{
+ if ( m_bPureWrap )
+ {
+ m_xAggregate->setPropertyValue( impl_getPropertyNameFromHandle( nHandle ), rValue );
+ }
+ else
+ {
+ OColumnWrapper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ }
+}
+
+// OTableColumnWrapper
+OTableColumnWrapper::OTableColumnWrapper( const Reference< XPropertySet >& rCol, const Reference< XPropertySet >& _xColDefinition,
+ const bool _bPureWrap )
+ :OTableColumnDescriptorWrapper( rCol, _bPureWrap, false )
+{
+ osl_atomic_increment( &m_refCount );
+ if ( _xColDefinition.is() )
+ {
+ try
+ {
+ ::comphelper::copyProperties( _xColDefinition, this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OTableColumnWrapper::~OTableColumnWrapper()
+{
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumnWrapper )
+
+OUString OTableColumnWrapper::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumnWrapper";
+}
+
+Sequence< OUString > OTableColumnWrapper::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN, SERVICE_SDB_COLUMNSETTINGS };
+}
+
+::cppu::IPropertyArrayHelper& OTableColumnWrapper::getInfoHelper()
+{
+ return *static_cast< OIdPropertyArrayUsageHelper< OTableColumnWrapper >* >(this)->getArrayHelper(m_nColTypeID);
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OTableColumnWrapper::createArrayHelper( sal_Int32 nId ) const
+{
+ return OTableColumnDescriptorWrapper::createArrayHelper( nId );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/preparedstatement.cxx b/dbaccess/source/core/api/preparedstatement.cxx
new file mode 100644
index 000000000..02dd32379
--- /dev/null
+++ b/dbaccess/source/core/api/preparedstatement.cxx
@@ -0,0 +1,412 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <preparedstatement.hxx>
+#include <strings.hxx>
+#include "resultcolumn.hxx"
+#include "resultset.hxx"
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace dbaccess;
+
+
+OPreparedStatement::OPreparedStatement(const Reference< XConnection > & _xConn,
+ const Reference< XInterface > & _xStatement)
+ :OStatementBase(_xConn, _xStatement)
+{
+ m_xAggregateAsParameters.set( m_xAggregateAsSet, UNO_QUERY_THROW );
+
+ Reference<XDatabaseMetaData> xMeta = _xConn->getMetaData();
+ m_pColumns.reset( new OColumns(*this, m_aMutex, xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),std::vector< OUString>(), nullptr,nullptr) );
+}
+
+OPreparedStatement::~OPreparedStatement()
+{
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OPreparedStatement::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XServiceInfo>::get(),
+ cppu::UnoType<XPreparedStatement>::get(),
+ cppu::UnoType<XParameters>::get(),
+ cppu::UnoType<XResultSetMetaDataSupplier>::get(),
+ cppu::UnoType<XColumnsSupplier>::get(),
+ OStatementBase::getTypes() );
+
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > OPreparedStatement::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OPreparedStatement::queryInterface( const Type & rType )
+{
+ Any aIface = OStatementBase::queryInterface( rType );
+ if (!aIface.hasValue())
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XServiceInfo * >( this ),
+ static_cast< XParameters * >( this ),
+ static_cast< XColumnsSupplier * >( this ),
+ static_cast< XResultSetMetaDataSupplier * >( this ),
+ static_cast< XPreparedBatchExecution * >( this ),
+ static_cast< XMultipleResults * >( this ),
+ static_cast< XPreparedStatement * >( this ));
+ return aIface;
+}
+
+void OPreparedStatement::acquire() noexcept
+{
+ OStatementBase::acquire();
+}
+
+void OPreparedStatement::release() noexcept
+{
+ OStatementBase::release();
+}
+
+// XServiceInfo
+OUString OPreparedStatement::getImplementationName( )
+{
+ return "com.sun.star.sdb.OPreparedStatement";
+}
+
+sal_Bool OPreparedStatement::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OPreparedStatement::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_PREPAREDSTATEMENT, SERVICE_SDB_PREPAREDSTATMENT };
+}
+
+// OComponentHelper
+void OPreparedStatement::disposing()
+{
+ {
+ MutexGuard aGuard(m_aMutex);
+ m_pColumns->disposing();
+ m_xAggregateAsParameters = nullptr;
+ }
+ OStatementBase::disposing();
+}
+
+// css::sdbcx::XColumnsSupplier
+Reference< css::container::XNameAccess > OPreparedStatement::getColumns()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // do we have to populate the columns
+ if (!m_pColumns->isInitialized())
+ {
+ try
+ {
+ Reference< XResultSetMetaDataSupplier > xSuppMeta( m_xAggregateAsSet, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xMetaData( xSuppMeta->getMetaData(), UNO_SET_THROW );
+
+ Reference< XConnection > xConn( getConnection(), UNO_SET_THROW );
+ Reference< XDatabaseMetaData > xDBMeta( xConn->getMetaData(), UNO_SET_THROW );
+
+ for (sal_Int32 i = 0, nCount = xMetaData->getColumnCount(); i < nCount; ++i)
+ {
+ // retrieve the name of the column
+ OUString aName = xMetaData->getColumnName(i + 1);
+ rtl::Reference<OResultColumn> pColumn = new OResultColumn(xMetaData, i + 1, xDBMeta);
+ // don't silently assume that the name is unique - preparedStatement implementations
+ // are allowed to return duplicate names, but we are required to have
+ // unique column names
+ if ( m_pColumns->hasByName( aName ) )
+ aName = ::dbtools::createUniqueName( m_pColumns.get(), aName );
+
+ m_pColumns->append(aName, pColumn.get());
+ }
+ }
+ catch (const SQLException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_pColumns->setInitialized();
+ }
+ return m_pColumns.get();
+}
+
+// XResultSetMetaDataSupplier
+Reference< XResultSetMetaData > OPreparedStatement::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XResultSetMetaDataSupplier >( m_xAggregateAsSet, UNO_QUERY_THROW )->getMetaData();
+}
+
+// XPreparedStatement
+Reference< XResultSet > OPreparedStatement::executeQuery()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ Reference< XResultSet > xResultSet;
+ Reference< XResultSet > xDrvResultSet = Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->executeQuery();
+ if (xDrvResultSet.is())
+ {
+ xResultSet = new OResultSet(xDrvResultSet, *this, m_pColumns->isCaseSensitive());
+
+ // keep the resultset weak
+ m_aResultSet = xResultSet;
+ }
+ return xResultSet;
+}
+
+sal_Int32 OPreparedStatement::executeUpdate()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ return Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->executeUpdate();
+}
+
+sal_Bool OPreparedStatement::execute()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ return Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->execute();
+}
+
+Reference< XConnection > OPreparedStatement::getConnection()
+{
+ return Reference< XConnection > (m_xParent, UNO_QUERY);
+}
+
+// XParameters
+void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 sqlType )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setNull(parameterIndex, sqlType);
+}
+
+void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setObjectNull(parameterIndex, sqlType, typeName);
+}
+
+void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBoolean(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setByte(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setShort(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setInt(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setLong(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setFloat(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setDouble(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setString(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBytes(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setDate(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setTime(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setTimestamp(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBinaryStream(parameterIndex, x, length);
+}
+
+void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setCharacterStream(parameterIndex, x, length);
+}
+
+void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setObject(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
+}
+
+void SAL_CALL OPreparedStatement::setRef( sal_Int32 parameterIndex, const Reference< XRef >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setRef(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBlob(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setClob(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setArray( sal_Int32 parameterIndex, const Reference< XArray >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setArray(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::clearParameters( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->clearParameters();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/query.cxx b/dbaccess/source/core/api/query.cxx
new file mode 100644
index 000000000..33ceca9ce
--- /dev/null
+++ b/dbaccess/source/core/api/query.cxx
@@ -0,0 +1,383 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "query.hxx"
+#include <stringconstants.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/PColumn.hxx>
+#include <connectivity/warningscontainer.hxx>
+#include "HelperCollections.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+
+#include <comphelper/property.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <definitioncolumn.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <ContainerMediator.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::comphelper;
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::utl;
+
+namespace dbaccess
+{
+
+// OQuery
+
+OQuery::OQuery( const Reference< XPropertySet >& _rxCommandDefinition
+ ,const Reference< XConnection >& _rxConn
+ ,const Reference< XComponentContext >& _xORB)
+ :OContentHelper(_xORB,nullptr,std::make_shared<OContentHelper_Impl>())
+ ,OQueryDescriptor_Base(m_aMutex,*this)
+ ,ODataSettings(OContentHelper::rBHelper,true)
+ ,m_xCommandDefinition(_rxCommandDefinition)
+ ,m_xConnection(_rxConn)
+ ,m_pWarnings( nullptr )
+ ,m_eDoingCurrently(AggregateAction::NONE)
+{
+ registerProperties();
+ ODataSettings::registerPropertiesFor(this);
+
+ osl_atomic_increment(&m_refCount);
+ OSL_ENSURE(m_xCommandDefinition.is(), "OQuery::OQuery : invalid CommandDefinition object !");
+ if ( m_xCommandDefinition.is() )
+ {
+ try
+ {
+ ::comphelper::copyProperties(_rxCommandDefinition,this);
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "OQueryDescriptor_Base::OQueryDescriptor_Base");
+ }
+
+ m_xCommandDefinition->addPropertyChangeListener(OUString(), this);
+ // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
+ m_xCommandPropInfo = m_xCommandDefinition->getPropertySetInfo();
+ }
+ OSL_ENSURE(m_xConnection.is(), "OQuery::OQuery : invalid connection !");
+ osl_atomic_decrement(&m_refCount);
+}
+
+OQuery::~OQuery()
+{
+}
+
+css::uno::Sequence<sal_Int8> OQuery::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OQuery::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OQueryDescriptor_Base::getTypes( ),
+ ODataSettings::getTypes( ),
+ OContentHelper::getTypes( )
+ );
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3( OQuery,OContentHelper,OQueryDescriptor_Base,ODataSettings)
+
+void OQuery::rebuildColumns()
+{
+ OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
+ // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
+
+ try
+ {
+ m_pColumnMediator = nullptr;
+
+ Reference<XColumnsSupplier> xColSup(m_xCommandDefinition,UNO_QUERY);
+ Reference< XNameAccess > xColumnDefinitions;
+ if ( xColSup.is() )
+ {
+ xColumnDefinitions = xColSup->getColumns();
+ if ( xColumnDefinitions.is() )
+ m_pColumnMediator = new OContainerMediator( m_pColumns.get(), xColumnDefinitions );
+ }
+
+ // fill the columns with columns from the statement
+ Reference< XMultiServiceFactory > xFactory( m_xConnection, UNO_QUERY_THROW );
+ SharedUNOComponent< XSingleSelectQueryComposer, DisposableComponent > xComposer(
+ Reference< XSingleSelectQueryComposer >( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ) );
+
+ Reference< XNameAccess > xColumns;
+ Reference< XIndexAccess > xColumnsIndexed;
+ try
+ {
+ xComposer->setQuery( m_sCommand );
+ Reference< XColumnsSupplier > xCols( xComposer, UNO_QUERY_THROW );
+ xColumns.set( xCols->getColumns(), UNO_SET_THROW );
+ xColumnsIndexed.set( xColumns, UNO_QUERY_THROW );
+ }
+ catch( const SQLException& ) { }
+
+ SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
+ if ( !xColumns.is() || ( xColumnsIndexed->getCount() == 0 ) )
+ { // the QueryComposer could not parse it. Try a lean version.
+ xPreparedStatement.set( m_xConnection->prepareStatement( m_sCommand ), UNO_QUERY_THROW );
+ Reference< XResultSetMetaDataSupplier > xResMetaDataSup( xPreparedStatement, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xResultSetMeta( xResMetaDataSup->getMetaData() );
+ if ( !xResultSetMeta.is() )
+ {
+ OUString sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET ) );
+ ::dbtools::throwSQLException( sError, StandardSQLState::GENERAL_ERROR, *this );
+ }
+
+ Reference< XDatabaseMetaData > xDBMeta( m_xConnection->getMetaData(), UNO_SET_THROW );
+ ::rtl::Reference< OSQLColumns > aParseColumns(
+ ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, xDBMeta,xColumnDefinitions ) );
+ xColumns = OPrivateColumns::createWithIntrinsicNames(
+ aParseColumns, xDBMeta->supportsMixedCaseQuotedIdentifiers(), *this, m_aMutex ).release();
+ if ( !xColumns.is() )
+ throw RuntimeException();
+ }
+
+ const Sequence<OUString> aColNames = xColumns->getElementNames();
+ for ( const OUString& rName : aColNames )
+ {
+ Reference<XPropertySet> xSource(xColumns->getByName( rName ),UNO_QUERY);
+ OUString sLabel = rName;
+ if ( xColumnDefinitions.is() && xColumnDefinitions->hasByName(rName) )
+ {
+ Reference<XPropertySet> xCommandColumn(xColumnDefinitions->getByName( rName ),UNO_QUERY);
+ xCommandColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
+ }
+ rtl::Reference<OQueryColumn> pColumn = new OQueryColumn( xSource, m_xConnection, sLabel);
+ pColumn->setParent( *this );
+
+ implAppendColumn( rName, pColumn.get() );
+ Reference< XPropertySet > xDest( *pColumn, UNO_QUERY_THROW );
+ if ( m_pColumnMediator.is() )
+ m_pColumnMediator->notifyElementCreated( rName, xDest );
+ }
+ }
+ catch( const SQLContext& e )
+ {
+ if ( m_pWarnings )
+ m_pWarnings->appendWarning( e );
+ }
+ catch( const SQLWarning& e )
+ {
+ if ( m_pWarnings )
+ m_pWarnings->appendWarning( e );
+ }
+ catch( const SQLException& e )
+ {
+ if ( m_pWarnings )
+ m_pWarnings->appendWarning( e );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+// XServiceInfo
+OUString SAL_CALL OQuery::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OQuery";
+ }
+sal_Bool SAL_CALL OQuery::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OQuery::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_DATASETTINGS, SERVICE_SDB_QUERY, "com.sun.star.sdb.QueryDefinition" };
+}
+
+// css::beans::XPropertyChangeListener
+void SAL_CALL OQuery::propertyChange( const PropertyChangeEvent& _rSource )
+{
+ sal_Int32 nOwnHandle = -1;
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ OSL_ENSURE(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
+ "OQuery::propertyChange : where did this call come from ?");
+
+ if (m_eDoingCurrently == AggregateAction::SettingProperties)
+ // we're setting the property ourself, so we will do the necessary notifications later
+ return;
+
+ // forward this to our own member holding a copy of the property value
+ if (getArrayHelper()->hasPropertyByName(_rSource.PropertyName))
+ {
+ Property aOwnProp = getArrayHelper()->getPropertyByName(_rSource.PropertyName);
+ nOwnHandle = aOwnProp.Handle;
+ ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle, _rSource.NewValue);
+ // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
+ // again
+ // and don't use the "real" setPropertyValue, this is too expensive and not sure to succeed
+ }
+ else
+ {
+ OSL_FAIL("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
+ }
+ }
+
+ fire(&nOwnHandle, &_rSource.NewValue, &_rSource.OldValue, 1, false);
+}
+
+void SAL_CALL OQuery::disposing( const EventObject& _rSource )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ OSL_ENSURE(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
+ "OQuery::disposing : where did this call come from ?");
+
+ m_xCommandDefinition->removePropertyChangeListener(OUString(), this);
+ m_xCommandDefinition = nullptr;
+}
+
+// XDataDescriptorFactory
+Reference< XPropertySet > SAL_CALL OQuery::createDataDescriptor( )
+{
+ return new OQueryDescriptor(*this);
+}
+
+// pseudo-XComponent
+void SAL_CALL OQuery::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+ if (m_xCommandDefinition.is())
+ {
+ m_xCommandDefinition->removePropertyChangeListener(OUString(), this);
+ m_xCommandDefinition = nullptr;
+ }
+ disposeColumns();
+
+ m_pWarnings = nullptr;
+}
+
+void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
+{
+ ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
+ OUString sAggPropName;
+ sal_Int16 nAttr = 0;
+ if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName,&nAttr,_nHandle) &&
+ m_xCommandPropInfo.is() &&
+ m_xCommandPropInfo->hasPropertyByName(sAggPropName))
+ { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
+
+ m_eDoingCurrently = AggregateAction::SettingProperties;
+ OAutoActionReset aAutoReset(*this);
+ m_xCommandDefinition->setPropertyValue(sAggPropName, _rValue);
+
+ if ( PROPERTY_ID_COMMAND == _nHandle )
+ // the columns are out of date if we are based on a new statement...
+ setColumnsOutOfDate();
+ }
+}
+
+Reference< XPropertySetInfo > SAL_CALL OQuery::getPropertySetInfo( )
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+::cppu::IPropertyArrayHelper& OQuery::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OQuery::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ // our own props
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+rtl::Reference<OColumn> OQuery::createColumn(const OUString& /*_rName*/) const
+{
+ return nullptr;
+}
+
+void SAL_CALL OQuery::rename( const OUString& newName )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference<XRename> xRename(m_xCommandDefinition,UNO_QUERY);
+ OSL_ENSURE(xRename.is(),"No XRename interface!");
+ if(xRename.is())
+ xRename->rename(newName);
+}
+
+void OQuery::registerProperties()
+{
+ // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
+ // an OPropertyStateContainer)
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND|PropertyAttribute::CONSTRAINED,
+ &m_sElementName, cppu::UnoType<decltype(m_sElementName)>::get());
+
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
+ &m_sCommand, cppu::UnoType<decltype(m_sCommand)>::get());
+
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND,
+ &m_bEscapeProcessing, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND,
+ &m_sUpdateTableName, cppu::UnoType<decltype(m_sUpdateTableName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND,
+ &m_sUpdateSchemaName, cppu::UnoType<decltype(m_sUpdateSchemaName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND,
+ &m_sUpdateCatalogName, cppu::UnoType<decltype(m_sUpdateCatalogName)>::get());
+
+ registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND,
+ &m_aLayoutInformation, cppu::UnoType<decltype(m_aLayoutInformation)>::get());
+}
+
+OUString OQuery::determineContentType() const
+{
+ return "application/vnd.org.openoffice.DatabaseQuery";
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/query.hxx b/dbaccess/source/core/api/query.hxx
new file mode 100644
index 000000000..fefcb94b4
--- /dev/null
+++ b/dbaccess/source/core/api/query.hxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "querydescriptor.hxx"
+#include <cppuhelper/implbase3.hxx>
+#include <rtl/ref.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <ContentHelper.hxx>
+
+#include <map>
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+
+// OQuery - an object implementing the sdb.Query service
+typedef ::cppu::ImplHelper3 < css::sdbcx::XDataDescriptorFactory,
+ css::beans::XPropertyChangeListener,
+ css::sdbcx::XRename
+ > OQuery_Base;
+class OQuery;
+class OColumn;
+typedef ::comphelper::OPropertyArrayUsageHelper< OQuery > OQuery_ArrayHelperBase;
+
+class OQuery :public OContentHelper
+ ,public OQueryDescriptor_Base
+ ,public OQuery_Base
+ ,public OQuery_ArrayHelperBase
+ ,public ODataSettings
+{
+ friend struct TRelease;
+
+protected:
+ css::uno::Reference< css::beans::XPropertySet > m_xCommandDefinition;
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::beans::XPropertySetInfo > m_xCommandPropInfo;
+ ::rtl::Reference< OContainerMediator > m_pColumnMediator;
+ ::dbtools::WarningsContainer* m_pWarnings;
+
+ // possible actions on our "aggregate"
+ enum class AggregateAction { NONE, SettingProperties };
+ AggregateAction m_eDoingCurrently;
+
+ /** a class which automatically resets m_eDoingCurrently in its destructor
+ */
+ class OAutoActionReset; // just for the following friend declaration
+ friend class OAutoActionReset;
+ class OAutoActionReset
+ {
+ OQuery& m_rActor;
+ public:
+ explicit OAutoActionReset(OQuery& _rActor) : m_rActor(_rActor) { }
+ ~OAutoActionReset() { m_rActor.m_eDoingCurrently = AggregateAction::NONE; }
+ };
+
+protected:
+ virtual ~OQuery() override;
+
+// OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ using OQuery_ArrayHelperBase::getArrayHelper;
+
+public:
+ OQuery(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxCommandDefinition,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+// OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+// css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+// css::sdbcx::XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+// css::beans::XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+// css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& _rSource ) override;
+
+// OPropertySetHelper
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+public:
+ // the caller is responsible for the lifetime!
+ void setWarningsContainer( ::dbtools::WarningsContainer* _pWarnings ) { m_pWarnings = _pWarnings; }
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+
+ virtual void rebuildColumns( ) override;
+
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+private:
+ void registerProperties();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querycomposer.cxx b/dbaccess/source/core/api/querycomposer.cxx
new file mode 100644
index 000000000..8bab87187
--- /dev/null
+++ b/dbaccess/source/core/api/querycomposer.cxx
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/configmgr.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <querycomposer.hxx>
+#include <strings.hxx>
+#include <composertools.hxx>
+#include <algorithm>
+
+using namespace dbaccess;
+using namespace comphelper;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::utl;
+
+
+OQueryComposer::OQueryComposer(const Reference< XConnection>& _xConnection)
+ : OSubComponent(m_aMutex,_xConnection)
+{
+ OSL_ENSURE(_xConnection.is()," Connection can't be null!");
+
+ Reference<XMultiServiceFactory> xFac( _xConnection, UNO_QUERY_THROW );
+ m_xComposer.set( xFac->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+ m_xComposerHelper.set( xFac->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+}
+
+OQueryComposer::~OQueryComposer()
+{
+}
+
+void SAL_CALL OQueryComposer::disposing()
+{
+ ::comphelper::disposeComponent(m_xComposerHelper);
+ ::comphelper::disposeComponent(m_xComposer);
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > SAL_CALL OQueryComposer::getTypes()
+{
+ return ::comphelper::concatSequences(OSubComponent::getTypes(),OQueryComposer_BASE::getTypes());
+}
+
+Sequence< sal_Int8 > SAL_CALL OQueryComposer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any SAL_CALL OQueryComposer::queryInterface( const Type & rType )
+{
+ Any aRet = OSubComponent::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OQueryComposer_BASE::queryInterface(rType);
+ return aRet;
+}
+
+// XServiceInfo
+OUString OQueryComposer::getImplementationName( )
+{
+ return "com.sun.star.sdb.dbaccess.OQueryComposer";
+}
+
+sal_Bool OQueryComposer::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OQueryComposer::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_SQLQUERYCOMPOSER };
+}
+
+// XSQLQueryComposer
+OUString SAL_CALL OQueryComposer::getQuery( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference<XPropertySet> xProp(m_xComposer,UNO_QUERY);
+ OUString sQuery;
+ if ( xProp.is() )
+ xProp->getPropertyValue(PROPERTY_ORIGINAL) >>= sQuery;
+ return sQuery;
+}
+
+void SAL_CALL OQueryComposer::setQuery( const OUString& command )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_aFilters.clear();
+ m_xComposer->setQuery(command);
+ m_sOrgFilter = m_xComposer->getFilter();
+ m_sOrgOrder = m_xComposer->getOrder();
+}
+
+OUString SAL_CALL OQueryComposer::getComposedQuery( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ MutexGuard aGuard(m_aMutex);
+
+ return m_xComposer->getQuery();
+}
+
+OUString SAL_CALL OQueryComposer::getFilter( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ FilterCreator aFilterCreator;
+ aFilterCreator = std::for_each(m_aFilters.begin(),m_aFilters.end(),aFilterCreator);
+ return aFilterCreator.getComposedAndClear();
+}
+
+Sequence< Sequence< PropertyValue > > SAL_CALL OQueryComposer::getStructuredFilter( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ MutexGuard aGuard(m_aMutex);
+ return m_xComposer->getStructuredFilter();
+}
+
+OUString SAL_CALL OQueryComposer::getOrder( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OrderCreator aOrderCreator;
+ aOrderCreator = std::for_each(m_aOrders.begin(),m_aOrders.end(),aOrderCreator);
+ return aOrderCreator.getComposedAndClear();
+}
+
+void SAL_CALL OQueryComposer::appendFilterByColumn( const Reference< XPropertySet >& column )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_xComposerHelper->setQuery(getQuery());
+ m_xComposerHelper->setFilter(OUString());
+ m_xComposerHelper->appendFilterByColumn(column, true, SQLFilterOperator::EQUAL);
+
+ FilterCreator aFilterCreator;
+ aFilterCreator.append(getFilter());
+ aFilterCreator.append(m_xComposerHelper->getFilter());
+
+ setFilter( aFilterCreator.getComposedAndClear() );
+}
+
+void SAL_CALL OQueryComposer::appendOrderByColumn( const Reference< XPropertySet >& column, sal_Bool ascending )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_xComposerHelper->setQuery(getQuery());
+ m_xComposerHelper->setOrder(OUString());
+ m_xComposerHelper->appendOrderByColumn(column,ascending);
+
+ OrderCreator aOrderCreator;
+ aOrderCreator.append(getOrder());
+ aOrderCreator.append(m_xComposerHelper->getOrder());
+
+ setOrder(aOrderCreator.getComposedAndClear());
+}
+
+void SAL_CALL OQueryComposer::setFilter( const OUString& filter )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ FilterCreator aFilterCreator;
+ aFilterCreator.append(m_sOrgFilter);
+ aFilterCreator.append(filter);
+
+ m_aFilters.clear();
+ if ( !filter.isEmpty() )
+ m_aFilters.push_back(filter);
+
+ m_xComposer->setFilter( aFilterCreator.getComposedAndClear() );
+}
+
+void SAL_CALL OQueryComposer::setOrder( const OUString& order )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OrderCreator aOrderCreator;
+ aOrderCreator.append(m_sOrgOrder);
+ aOrderCreator.append(order);
+
+ m_aOrders.clear();
+ if ( !order.isEmpty() )
+ m_aOrders.push_back(order);
+
+ m_xComposer->setOrder(aOrderCreator.getComposedAndClear());
+}
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL OQueryComposer::getTables( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return Reference<XTablesSupplier>(m_xComposer,UNO_QUERY_THROW)->getTables();
+}
+
+// XColumnsSupplier
+Reference< XNameAccess > SAL_CALL OQueryComposer::getColumns( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return Reference<XColumnsSupplier>(m_xComposer,UNO_QUERY_THROW)->getColumns();
+}
+
+Reference< XIndexAccess > SAL_CALL OQueryComposer::getParameters( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return Reference<XParametersSupplier>(m_xComposer,UNO_QUERY_THROW)->getParameters();
+}
+
+void SAL_CALL OQueryComposer::acquire() noexcept
+{
+ OSubComponent::acquire();
+}
+
+void SAL_CALL OQueryComposer::release() noexcept
+{
+ OSubComponent::release();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querycontainer.cxx b/dbaccess/source/core/api/querycontainer.cxx
new file mode 100644
index 000000000..583cab373
--- /dev/null
+++ b/dbaccess/source/core/api/querycontainer.cxx
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <querycontainer.hxx>
+#include "query.hxx"
+#include <strings.hxx>
+#include <objectnameapproval.hxx>
+#include <veto.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/QueryDefinition.hpp>
+
+#include <osl/diagnose.h>
+#include <comphelper/uno3.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OQueryContainer
+
+OQueryContainer::OQueryContainer(
+ const Reference< XNameContainer >& _rxCommandDefinitions
+ , const Reference< XConnection >& _rxConn
+ , const Reference< XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings)
+ :ODefinitionContainer(_rxORB,nullptr,std::make_shared<ODefinitionContainer_Impl>())
+ ,m_pWarnings( _pWarnings )
+ ,m_xCommandDefinitions(_rxCommandDefinitions)
+ ,m_xConnection(_rxConn)
+ ,m_eDoingCurrently(AggregateAction::NONE)
+{
+}
+
+void OQueryContainer::init()
+{
+ Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY_THROW );
+ xContainer->addContainerListener( this );
+
+ Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY_THROW );
+ xContainerApprove->addContainerApproveListener( this );
+
+ // fill my structures
+ ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ Sequence< OUString > sDefinitionNames = m_xCommandDefinitions->getElementNames();
+ const OUString* pDefinitionName = sDefinitionNames.getConstArray();
+ const OUString* pEnd = pDefinitionName + sDefinitionNames.getLength();
+ for ( ; pDefinitionName != pEnd; ++pDefinitionName )
+ {
+ rDefinitions.insert( *pDefinitionName, TContentPtr() );
+ m_aDocuments.push_back(m_aDocumentMap.emplace( *pDefinitionName,Documents::mapped_type()).first);
+ }
+
+ setElementApproval( std::make_shared<ObjectNameApproval>( m_xConnection, ObjectNameApproval::TypeQuery ) );
+}
+
+rtl::Reference<OQueryContainer> OQueryContainer::create(
+ const Reference< XNameContainer >& _rxCommandDefinitions
+ , const Reference< XConnection >& _rxConn
+ , const Reference< XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings)
+{
+ rtl::Reference c(
+ new OQueryContainer(
+ _rxCommandDefinitions, _rxConn, _rxORB, _pWarnings));
+ c->init();
+ return c;
+}
+
+OQueryContainer::~OQueryContainer()
+{
+ // dispose();
+ // maybe we're already disposed, but this should be uncritical
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
+
+void OQueryContainer::disposing()
+{
+ ODefinitionContainer::disposing();
+ MutexGuard aGuard(m_aMutex);
+ if ( !m_xCommandDefinitions.is() )
+ // already disposed
+ return;
+
+ Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY );
+ xContainer->removeContainerListener( this );
+ Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY );
+ xContainerApprove->removeContainerApproveListener( this );
+
+ m_xCommandDefinitions = nullptr;
+ m_xConnection = nullptr;
+}
+
+// XServiceInfo
+OUString SAL_CALL OQueryContainer::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OQueryContainer";
+ }
+sal_Bool SAL_CALL OQueryContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OQueryContainer::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_CONTAINER, SERVICE_SDB_QUERIES };
+}
+
+// XDataDescriptorFactory
+Reference< XPropertySet > SAL_CALL OQueryContainer::createDataDescriptor( )
+{
+ return new OQueryDescriptor();
+}
+
+// XAppend
+void SAL_CALL OQueryContainer::appendByDescriptor( const Reference< XPropertySet >& _rxDesc )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+ if ( !m_xCommandDefinitions.is() )
+ throw DisposedException( OUString(), *this );
+
+ // first clone this object's CommandDefinition part
+ Reference< css::sdb::XQueryDefinition > xCommandDefinitionPart = css::sdb::QueryDefinition::create(m_aContext);
+
+ ::comphelper::copyProperties( _rxDesc, Reference<XPropertySet>(xCommandDefinitionPart, UNO_QUERY_THROW) );
+ // TODO : the columns part of the descriptor has to be copied
+
+ // create a wrapper for the object (*before* inserting into our command definition container)
+ Reference< XContent > xNewObject( implCreateWrapper( Reference< XContent>( xCommandDefinitionPart, UNO_QUERY_THROW ) ) );
+
+ OUString sNewObjectName;
+ _rxDesc->getPropertyValue(PROPERTY_NAME) >>= sNewObjectName;
+
+ try
+ {
+ notifyByName( aGuard, sNewObjectName, xNewObject, nullptr, E_INSERTED, ApproveListeners );
+ }
+ catch (const WrappedTargetException& e)
+ {
+ disposeComponent( xNewObject );
+ disposeComponent( xCommandDefinitionPart );
+ throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
+ }
+ catch (const Exception&)
+ {
+ disposeComponent( xNewObject );
+ disposeComponent( xCommandDefinitionPart );
+ throw;
+ }
+
+ // insert the basic object into the definition container
+ {
+ m_eDoingCurrently = AggregateAction::Inserting;
+ OAutoActionReset aAutoReset(*this);
+ m_xCommandDefinitions->insertByName(sNewObjectName, Any(xCommandDefinitionPart));
+ }
+
+ implAppend( sNewObjectName, xNewObject );
+ try
+ {
+ notifyByName( aGuard, sNewObjectName, xNewObject, nullptr, E_INSERTED, ContainerListemers );
+ }
+ catch (const WrappedTargetException& e)
+ {
+ throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
+ }
+}
+
+// XDrop
+void SAL_CALL OQueryContainer::dropByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+ if ( !checkExistence(_rName) )
+ throw NoSuchElementException(_rName,*this);
+
+ if ( !m_xCommandDefinitions.is() )
+ throw DisposedException( OUString(), *this );
+
+ // now simply forward the remove request to the CommandDefinition container, we're a listener for the removal
+ // and thus we do everything necessary in ::elementRemoved
+ m_xCommandDefinitions->removeByName(_rName);
+}
+
+void SAL_CALL OQueryContainer::dropByIndex( sal_Int32 _nIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ if ((_nIndex<0) || (_nIndex>getCount()))
+ throw IndexOutOfBoundsException();
+
+ if ( !m_xCommandDefinitions.is() )
+ throw DisposedException( OUString(), *this );
+
+ OUString sName;
+ Reference<XPropertySet> xProp(Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY_THROW)->getByIndex(_nIndex),UNO_QUERY);
+ if ( xProp.is() )
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
+
+ dropByName(sName);
+}
+
+void SAL_CALL OQueryContainer::elementInserted( const css::container::ContainerEvent& _rEvent )
+{
+ Reference< XContent > xNewElement;
+ OUString sElementName;
+ _rEvent.Accessor >>= sElementName;
+ {
+ MutexGuard aGuard(m_aMutex);
+ if (AggregateAction::Inserting == m_eDoingCurrently)
+ // nothing to do, we're inserting via an "appendByDescriptor"
+ return;
+
+ OSL_ENSURE(!sElementName.isEmpty(), "OQueryContainer::elementInserted : invalid name !");
+ OSL_ENSURE(m_aDocumentMap.find(sElementName) == m_aDocumentMap.end(), "OQueryContainer::elementInserted : oops... we're inconsistent with our master container !");
+ if (sElementName.isEmpty() || hasByName(sElementName))
+ return;
+
+ // insert an own new element
+ xNewElement = implCreateWrapper(sElementName);
+ }
+ insertByName(sElementName,Any(xNewElement));
+}
+
+void SAL_CALL OQueryContainer::elementRemoved( const css::container::ContainerEvent& _rEvent )
+{
+ OUString sAccessor;
+ _rEvent.Accessor >>= sAccessor;
+ {
+ OSL_ENSURE(!sAccessor.isEmpty(), "OQueryContainer::elementRemoved : invalid name !");
+ OSL_ENSURE(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementRemoved : oops... we're inconsistent with our master container !");
+ if ( sAccessor.isEmpty() || !hasByName(sAccessor) )
+ return;
+ }
+ removeByName(sAccessor);
+}
+
+void SAL_CALL OQueryContainer::elementReplaced( const css::container::ContainerEvent& _rEvent )
+{
+ Reference< XContent > xNewElement;
+ OUString sAccessor;
+ _rEvent.Accessor >>= sAccessor;
+
+ {
+ MutexGuard aGuard(m_aMutex);
+ OSL_ENSURE(!sAccessor.isEmpty(), "OQueryContainer::elementReplaced : invalid name !");
+ OSL_ENSURE(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementReplaced : oops... we're inconsistent with our master container !");
+ if (sAccessor.isEmpty() || !hasByName(sAccessor))
+ return;
+
+ xNewElement = implCreateWrapper(sAccessor);
+ }
+
+ replaceByName(sAccessor,Any(xNewElement));
+}
+
+Reference< XVeto > SAL_CALL OQueryContainer::approveInsertElement( const ContainerEvent& Event )
+{
+ OUString sName;
+ OSL_VERIFY( Event.Accessor >>= sName );
+ Reference< XContent > xElement( Event.Element, UNO_QUERY_THROW );
+
+ Reference< XVeto > xReturn;
+ try
+ {
+ getElementApproval()->approveElement( sName );
+ }
+ catch( const Exception& )
+ {
+ xReturn = new Veto( ::cppu::getCaughtException() );
+ }
+ return xReturn;
+}
+
+Reference< XVeto > SAL_CALL OQueryContainer::approveReplaceElement( const ContainerEvent& /*Event*/ )
+{
+ return nullptr;
+}
+
+Reference< XVeto > SAL_CALL OQueryContainer::approveRemoveElement( const ContainerEvent& /*Event*/ )
+{
+ return nullptr;
+}
+
+void SAL_CALL OQueryContainer::disposing( const css::lang::EventObject& _rSource )
+{
+ if (_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinitions, UNO_QUERY).get())
+ { // our "master container" (with the command definitions) is being disposed
+ OSL_FAIL("OQueryContainer::disposing : nobody should dispose the CommandDefinition container before disposing my connection !");
+ dispose();
+ }
+ else
+ {
+ Reference< XContent > xSource(_rSource.Source, UNO_QUERY);
+ // it's one of our documents...
+ for (auto const& document : m_aDocumentMap)
+ {
+ if ( xSource == document.second.get() )
+ {
+ m_xCommandDefinitions->removeByName(document.first);
+ break;
+ }
+ }
+ ODefinitionContainer::disposing(_rSource);
+ }
+}
+
+OUString OQueryContainer::determineContentType() const
+{
+ return "application/vnd.org.openoffice.DatabaseQueryContainer";
+}
+
+Reference< XContent > OQueryContainer::implCreateWrapper(const OUString& _rName)
+{
+ Reference< XContent > xObject(m_xCommandDefinitions->getByName(_rName),UNO_QUERY);
+ return implCreateWrapper(xObject);
+}
+
+Reference< XContent > OQueryContainer::implCreateWrapper(const Reference< XContent >& _rxCommandDesc)
+{
+ Reference<XNameContainer> xContainer(_rxCommandDesc,UNO_QUERY);
+ Reference< XContent > xReturn;
+ if ( xContainer .is() )
+ {
+ xReturn = create( xContainer, m_xConnection, m_aContext, m_pWarnings ).
+ get();
+ }
+ else
+ {
+ rtl::Reference<OQuery> pNewObject = new OQuery( Reference< XPropertySet >( _rxCommandDesc, UNO_QUERY ), m_xConnection, m_aContext );
+ xReturn = pNewObject;
+
+ pNewObject->setWarningsContainer( m_pWarnings );
+// pNewObject->getColumns();
+ // Why? This is expensive. If you comment this in 'cause you really need it, be sure to run the
+ // QueryInQuery test in dbaccess/qa/complex/dbaccess ...
+ }
+
+ return xReturn;
+}
+
+Reference< XContent > OQueryContainer::createObject( const OUString& _rName)
+{
+ return implCreateWrapper(_rName);
+}
+
+bool OQueryContainer::checkExistence(const OUString& _rName)
+{
+ bool bRet = false;
+ if ( !m_bInPropertyChange )
+ {
+ bRet = m_xCommandDefinitions->hasByName(_rName);
+ Documents::const_iterator aFind = m_aDocumentMap.find(_rName);
+ if ( !bRet && aFind != m_aDocumentMap.end() )
+ {
+ m_aDocuments.erase( std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind));
+ m_aDocumentMap.erase(aFind);
+ }
+ else if ( bRet && aFind == m_aDocumentMap.end() )
+ {
+ implAppend(_rName,nullptr);
+ }
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL OQueryContainer::hasElements( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_xCommandDefinitions->hasElements();
+}
+
+sal_Int32 SAL_CALL OQueryContainer::getCount( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY_THROW)->getCount();
+}
+
+Sequence< OUString > SAL_CALL OQueryContainer::getElementNames( )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ return m_xCommandDefinitions->getElementNames();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querydescriptor.cxx b/dbaccess/source/core/api/querydescriptor.cxx
new file mode 100644
index 000000000..0ac6d76e3
--- /dev/null
+++ b/dbaccess/source/core/api/querydescriptor.cxx
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "querydescriptor.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OQueryDescriptor
+
+OQueryDescriptor::OQueryDescriptor()
+ :OQueryDescriptor_Base(m_aMutex,*this)
+ ,ODataSettings(m_aBHelper,true)
+{
+ registerProperties();
+ ODataSettings::registerPropertiesFor(this);
+}
+
+OQueryDescriptor::OQueryDescriptor(const OQueryDescriptor_Base& _rSource)
+ :OQueryDescriptor_Base(_rSource,*this)
+ ,ODataSettings(m_aBHelper,true)
+{
+ registerProperties();
+ ODataSettings::registerPropertiesFor(this);
+}
+
+OQueryDescriptor::~OQueryDescriptor()
+{
+}
+
+css::uno::Sequence<sal_Int8> OQueryDescriptor::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OQueryDescriptor::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OQueryDescriptor_Base::getTypes( ),
+ ODataSettings::getTypes( )
+ );
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3( OQueryDescriptor,OWeakObject,OQueryDescriptor_Base,ODataSettings)
+
+void OQueryDescriptor::registerProperties()
+{
+ // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
+ // an OPropertyStateContainer)
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND|PropertyAttribute::CONSTRAINED,
+ &m_sElementName, cppu::UnoType<decltype(m_sElementName)>::get());
+
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
+ &m_sCommand, cppu::UnoType<decltype(m_sCommand)>::get());
+
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND,
+ &m_bEscapeProcessing, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND,
+ &m_sUpdateTableName, cppu::UnoType<decltype(m_sUpdateTableName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND,
+ &m_sUpdateSchemaName, cppu::UnoType<decltype(m_sUpdateSchemaName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND,
+ &m_sUpdateCatalogName, cppu::UnoType<decltype(m_sUpdateCatalogName)>::get());
+
+ registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND,
+ &m_aLayoutInformation, cppu::UnoType<decltype(m_aLayoutInformation)>::get());
+}
+
+Reference< XPropertySetInfo > SAL_CALL OQueryDescriptor::getPropertySetInfo( )
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+::cppu::IPropertyArrayHelper& OQueryDescriptor::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OQueryDescriptor::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+OQueryDescriptor_Base::OQueryDescriptor_Base(::osl::Mutex& _rMutex,::cppu::OWeakObject& _rMySelf)
+ :m_bColumnsOutOfDate(true)
+ ,m_rMutex(_rMutex)
+{
+ m_pColumns.reset( new OColumns(_rMySelf, m_rMutex, true,std::vector< OUString>(), this,this) );
+}
+
+OQueryDescriptor_Base::OQueryDescriptor_Base(const OQueryDescriptor_Base& _rSource,::cppu::OWeakObject& _rMySelf)
+ :m_bColumnsOutOfDate(true)
+ ,m_rMutex(_rSource.m_rMutex)
+{
+ m_pColumns.reset( new OColumns(_rMySelf, m_rMutex, true,std::vector< OUString>(), this,this) );
+
+ m_sCommand = _rSource.m_sCommand;
+ m_bEscapeProcessing = _rSource.m_bEscapeProcessing;
+ m_sUpdateTableName = _rSource.m_sUpdateTableName;
+ m_sUpdateSchemaName = _rSource.m_sUpdateSchemaName;
+ m_sUpdateCatalogName = _rSource.m_sUpdateCatalogName;
+ m_aLayoutInformation = _rSource.m_aLayoutInformation;
+}
+
+OQueryDescriptor_Base::~OQueryDescriptor_Base()
+{
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+}
+
+sal_Int64 SAL_CALL OQueryDescriptor_Base::getSomething( const Sequence< sal_Int8 >& _rIdentifier )
+{
+ return comphelper::getSomethingImpl(_rIdentifier, this);
+}
+
+const css::uno::Sequence<sal_Int8> & OQueryDescriptor_Base::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit aId;
+ return aId.getSeq();
+}
+
+css::uno::Sequence<sal_Int8> OQueryDescriptor_Base::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void OQueryDescriptor_Base::setColumnsOutOfDate( bool _bOutOfDate )
+{
+ m_bColumnsOutOfDate = _bOutOfDate;
+ if ( !m_bColumnsOutOfDate )
+ m_pColumns->setInitialized();
+}
+
+void OQueryDescriptor_Base::implAppendColumn( const OUString& _rName, OColumn* _pColumn )
+{
+ m_pColumns->append( _rName, _pColumn );
+}
+
+void OQueryDescriptor_Base::clearColumns( )
+{
+ m_pColumns->clearColumns();
+
+ setColumnsOutOfDate();
+}
+
+Reference< XNameAccess > SAL_CALL OQueryDescriptor_Base::getColumns( )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if ( m_bColumnsOutOfDate )
+ {
+ // clear the current columns
+ clearColumns();
+
+ // do this before rebuildColumns. This prevents recursion, e.g. in the case where we
+ // have queries with cyclic references:
+ // foo := SELECT * FROM bar
+ // bar := SELECT * FROM foo
+ setColumnsOutOfDate( false );
+
+ // rebuild them
+ try
+ {
+ rebuildColumns();
+ }
+ catch ( const Exception& )
+ {
+ setColumnsOutOfDate();
+ throw;
+ }
+ }
+
+ return m_pColumns.get();
+}
+
+OUString SAL_CALL OQueryDescriptor_Base::getImplementationName( )
+{
+ return "com.sun.star.sdb.OQueryDescriptor";
+}
+
+sal_Bool SAL_CALL OQueryDescriptor_Base::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL OQueryDescriptor_Base::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_DATASETTINGS, SERVICE_SDB_QUERYDESCRIPTOR };
+}
+
+void OQueryDescriptor_Base::disposeColumns()
+{
+ m_pColumns->disposing();
+}
+
+void OQueryDescriptor_Base::columnAppended( const Reference< XPropertySet >& /*_rxSourceDescriptor*/ )
+{
+ // not interested in
+}
+
+void OQueryDescriptor_Base::columnDropped(const OUString& /*_sName*/)
+{
+ // not interested in
+}
+
+Reference< XPropertySet > OQueryDescriptor_Base::createColumnDescriptor()
+{
+ OSL_FAIL( "OQueryDescriptor_Base::createColumnDescriptor: called why?" );
+ return nullptr;
+}
+
+void OQueryDescriptor_Base::rebuildColumns( )
+{
+}
+
+// IRefreshableColumns
+void OQueryDescriptor_Base::refreshColumns()
+{
+ MutexGuard aGuard( m_rMutex );
+
+ clearColumns();
+ rebuildColumns();
+}
+
+rtl::Reference<OColumn> OQueryDescriptor_Base::createColumn( const OUString& /*_rName*/ ) const
+{
+ // creating a column/descriptor for a query/descriptor does not make sense at all
+ return nullptr;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querydescriptor.hxx b/dbaccess/source/core/api/querydescriptor.hxx
new file mode 100644
index 000000000..e78b035da
--- /dev/null
+++ b/dbaccess/source/core/api/querydescriptor.hxx
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+
+#include <apitools.hxx>
+#include <column.hxx>
+#include <datasettings.hxx>
+#include <commandbase.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/uno3.hxx>
+
+namespace dbaccess
+{
+
+// OQueryDescriptor_Base - a query descriptor (as the name suggests :)
+typedef ::cppu::ImplHelper3<
+ css::sdbcx::XColumnsSupplier,
+ css::lang::XUnoTunnel,
+ css::lang::XServiceInfo > OQueryDescriptor_BASE;
+
+class OQueryDescriptor_Base
+ :public OQueryDescriptor_BASE
+ ,public OCommandBase
+ ,public IColumnFactory
+ ,public ::connectivity::sdbcx::IRefreshableColumns
+{
+private:
+ bool m_bColumnsOutOfDate : 1; // the columns have to be rebuild on the next getColumns ?
+ ::osl::Mutex& m_rMutex;
+
+protected:
+ std::unique_ptr<OColumns> m_pColumns; // our column descriptions
+ OUString m_sElementName;
+ virtual ~OQueryDescriptor_Base();
+
+ void setColumnsOutOfDate( bool _bOutOfDate = true );
+
+ sal_Int32 getColumnCount() const { return m_pColumns ? m_pColumns->getCount() : 0; }
+ void clearColumns( );
+
+ void implAppendColumn( const OUString& _rName, OColumn* _pColumn );
+
+public:
+ OQueryDescriptor_Base(::osl::Mutex& _rMutex,::cppu::OWeakObject& _rMySelf);
+ /** constructs the object with a UNO QueryDescriptor. If you use this ctor, the resulting object
+ won't have any column information (the column container will be empty)
+ */
+ OQueryDescriptor_Base(const OQueryDescriptor_Base& _rSource,::cppu::OWeakObject& _rMySelf);
+
+// css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+// css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+protected:
+
+// IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+
+ /** rebuild our columns set
+
+ clearColumns has already been called before, do <em>NOT</em> call it, again
+ */
+ virtual void rebuildColumns( );
+
+ void disposeColumns();
+
+ // IRefreshableColumns overridables
+ virtual void refreshColumns() override;
+};
+
+class OQueryDescriptor : public comphelper::OMutexAndBroadcastHelper
+ ,public ::cppu::OWeakObject
+ ,public OQueryDescriptor_Base
+ ,public ::comphelper::OPropertyArrayUsageHelper< OQueryDescriptor_Base >
+ ,public ODataSettings
+{
+ OQueryDescriptor(const OQueryDescriptor&) = delete;
+ void operator =(const OQueryDescriptor&) = delete;
+ // helper
+ void registerProperties();
+protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual ~OQueryDescriptor() override;
+public:
+ OQueryDescriptor();
+ explicit OQueryDescriptor(const OQueryDescriptor_Base& _rSource);
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+};
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultcolumn.cxx b/dbaccess/source/core/api/resultcolumn.cxx
new file mode 100644
index 000000000..938e7d1d3
--- /dev/null
+++ b/dbaccess/source/core/api/resultcolumn.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "resultcolumn.hxx"
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <tools/diagnose_ex.h>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace dbaccess;
+
+
+OResultColumn::OResultColumn( const Reference < XResultSetMetaData >& _xMetaData, sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta )
+ :OColumn( true )
+ ,m_xMetaData( _xMetaData )
+ ,m_xDBMetaData( _rxDBMeta )
+ ,m_nPos( _nPos )
+{
+}
+
+void OResultColumn::impl_determineIsRowVersion_nothrow()
+{
+ if ( m_aIsRowVersion.hasValue() )
+ return;
+ m_aIsRowVersion <<= false;
+
+ OSL_ENSURE( m_xDBMetaData.is(), "OResultColumn::impl_determineIsRowVersion_nothrow: no DBMetaData!" );
+ if ( !m_xDBMetaData.is() )
+ return;
+
+ try
+ {
+ OUString sCatalog, sSchema, sTable, sColumnName;
+ getPropertyValue( PROPERTY_CATALOGNAME ) >>= sCatalog;
+ getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema;
+ getPropertyValue( PROPERTY_TABLENAME ) >>= sTable;
+ getPropertyValue( PROPERTY_NAME ) >>= sColumnName;
+
+ try
+ {
+ Reference< XResultSet > xVersionColumns = m_xDBMetaData->getVersionColumns(
+ Any( sCatalog ), sSchema, sTable );
+ if ( xVersionColumns.is() ) // allowed to be NULL
+ {
+ Reference< XRow > xResultRow( xVersionColumns, UNO_QUERY_THROW );
+ while ( xVersionColumns->next() )
+ {
+ if ( xResultRow->getString( 2 ) == sColumnName )
+ {
+ m_aIsRowVersion <<= true;
+ break;
+ }
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OResultColumn::~OResultColumn()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< sal_Int8 > OResultColumn::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+OUString OResultColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.OResultColumn";
+}
+
+Sequence< OUString > OResultColumn::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN, SERVICE_SDB_RESULTCOLUMN };
+}
+
+// OComponentHelper
+void OResultColumn::disposing()
+{
+ OColumn::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+ m_xMetaData = nullptr;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OResultColumn::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OResultColumn::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< OResultColumn >* >(this)->getArrayHelper();
+}
+
+namespace
+{
+ template< typename T >
+ void obtain( Any& _out_rValue, ::std::optional< T > & _rCache, const sal_Int32 _nPos, const Reference < XResultSetMetaData >& _rxResultMeta, T (SAL_CALL XResultSetMetaData::*Getter)( sal_Int32 ) )
+ {
+ if ( !_rCache )
+ _rCache = (_rxResultMeta.get()->*Getter)(_nPos);
+ _out_rValue <<= *_rCache;
+ }
+}
+
+void OResultColumn::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ try
+ {
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ OColumn::getFastPropertyValue( rValue, nHandle );
+ }
+ else
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISROWVERSION:
+ const_cast< OResultColumn* >( this )->impl_determineIsRowVersion_nothrow();
+ rValue = m_aIsRowVersion;
+ break;
+ case PROPERTY_ID_TABLENAME:
+ rValue <<= m_xMetaData->getTableName(m_nPos);
+ break;
+ case PROPERTY_ID_SCHEMANAME:
+ rValue <<= m_xMetaData->getSchemaName(m_nPos);
+ break;
+ case PROPERTY_ID_CATALOGNAME:
+ rValue <<= m_xMetaData->getCatalogName(m_nPos);
+ break;
+ case PROPERTY_ID_ISSIGNED:
+ obtain( rValue, m_isSigned, m_nPos, m_xMetaData, &XResultSetMetaData::isSigned );
+ break;
+ case PROPERTY_ID_ISCURRENCY:
+ obtain( rValue, m_isCurrency, m_nPos, m_xMetaData, &XResultSetMetaData::isCurrency );
+ break;
+ case PROPERTY_ID_ISSEARCHABLE:
+ obtain( rValue, m_bSearchable, m_nPos, m_xMetaData, &XResultSetMetaData::isSearchable );
+ break;
+ case PROPERTY_ID_ISCASESENSITIVE:
+ obtain( rValue, m_isCaseSensitive, m_nPos, m_xMetaData, &XResultSetMetaData::isCaseSensitive );
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ obtain( rValue, m_isReadOnly, m_nPos, m_xMetaData, &XResultSetMetaData::isReadOnly );
+ break;
+ case PROPERTY_ID_ISWRITABLE:
+ obtain( rValue, m_isWritable, m_nPos, m_xMetaData, &XResultSetMetaData::isWritable );
+ break;
+ case PROPERTY_ID_ISDEFINITELYWRITABLE:
+ obtain( rValue, m_isDefinitelyWritable, m_nPos, m_xMetaData, &XResultSetMetaData::isDefinitelyWritable );
+ break;
+ case PROPERTY_ID_ISAUTOINCREMENT:
+ obtain( rValue, m_isAutoIncrement, m_nPos, m_xMetaData, &XResultSetMetaData::isAutoIncrement );
+ break;
+ case PROPERTY_ID_SERVICENAME:
+ rValue <<= m_xMetaData->getColumnServiceName(m_nPos);
+ break;
+ case PROPERTY_ID_LABEL:
+ obtain( rValue, m_sColumnLabel, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnLabel );
+ break;
+ case PROPERTY_ID_DISPLAYSIZE:
+ obtain( rValue, m_nColumnDisplaySize, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnDisplaySize );
+ break;
+ case PROPERTY_ID_TYPE:
+ obtain( rValue, m_nColumnType, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnType );
+ break;
+ case PROPERTY_ID_PRECISION:
+ obtain( rValue, m_nPrecision, m_nPos, m_xMetaData, &XResultSetMetaData::getPrecision );
+ break;
+ case PROPERTY_ID_SCALE:
+ obtain( rValue, m_nScale, m_nPos, m_xMetaData, &XResultSetMetaData::getScale );
+ break;
+ case PROPERTY_ID_ISNULLABLE:
+ obtain( rValue, m_isNullable, m_nPos, m_xMetaData, &XResultSetMetaData::isNullable );
+ break;
+ case PROPERTY_ID_TYPENAME:
+ rValue <<= m_xMetaData->getColumnTypeName(m_nPos);
+ break;
+ default:
+ OSL_FAIL( "OResultColumn::getFastPropertyValue: unknown property handle!" );
+ break;
+ }
+ }
+ }
+ catch (SQLException& )
+ {
+ // default handling if we caught an exception
+ switch (nHandle)
+ {
+ case PROPERTY_ID_LABEL:
+ case PROPERTY_ID_TYPENAME:
+ case PROPERTY_ID_SERVICENAME:
+ case PROPERTY_ID_TABLENAME:
+ case PROPERTY_ID_SCHEMANAME:
+ case PROPERTY_ID_CATALOGNAME:
+ // empty string'S
+ rValue <<= OUString();
+ break;
+ case PROPERTY_ID_ISROWVERSION:
+ case PROPERTY_ID_ISAUTOINCREMENT:
+ case PROPERTY_ID_ISWRITABLE:
+ case PROPERTY_ID_ISDEFINITELYWRITABLE:
+ case PROPERTY_ID_ISCASESENSITIVE:
+ case PROPERTY_ID_ISSEARCHABLE:
+ case PROPERTY_ID_ISCURRENCY:
+ case PROPERTY_ID_ISSIGNED:
+ {
+ rValue <<= false;
+ } break;
+ case PROPERTY_ID_ISREADONLY:
+ {
+ rValue <<= true;
+ } break;
+ case PROPERTY_ID_SCALE:
+ case PROPERTY_ID_PRECISION:
+ case PROPERTY_ID_DISPLAYSIZE:
+ rValue <<= sal_Int32(0);
+ break;
+ case PROPERTY_ID_TYPE:
+ rValue <<= sal_Int32(DataType::SQLNULL);
+ break;
+ case PROPERTY_ID_ISNULLABLE:
+ rValue <<= ColumnValue::NULLABLE_UNKNOWN;
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultcolumn.hxx b/dbaccess/source/core/api/resultcolumn.hxx
new file mode 100644
index 000000000..53803bac8
--- /dev/null
+++ b/dbaccess/source/core/api/resultcolumn.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <column.hxx>
+#include <optional>
+#include <comphelper/proparrhlp.hxx>
+namespace dbaccess
+{
+
+ // OResultColumn
+
+ class OResultColumn : public OColumn,
+ public ::comphelper::OPropertyArrayUsageHelper < OResultColumn >
+ {
+ protected:
+ css::uno::Reference < css::sdbc::XResultSetMetaData > m_xMetaData;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xDBMetaData;
+ sal_Int32 m_nPos;
+ css::uno::Any m_aIsRowVersion;
+ mutable ::std::optional< sal_Bool > m_isSigned;
+ mutable ::std::optional< sal_Bool > m_isCurrency;
+ mutable ::std::optional< sal_Bool > m_bSearchable;
+ mutable ::std::optional< sal_Bool > m_isCaseSensitive;
+ mutable ::std::optional< sal_Bool > m_isReadOnly;
+ mutable ::std::optional< sal_Bool > m_isWritable;
+ mutable ::std::optional< sal_Bool > m_isDefinitelyWritable;
+ mutable ::std::optional< sal_Bool > m_isAutoIncrement;
+ mutable ::std::optional< sal_Int32 > m_isNullable;
+ mutable ::std::optional< OUString > m_sColumnLabel;
+ mutable ::std::optional< sal_Int32 > m_nColumnDisplaySize;
+ mutable ::std::optional< sal_Int32 > m_nColumnType;
+ mutable ::std::optional< sal_Int32 > m_nPrecision;
+ mutable ::std::optional< sal_Int32 > m_nScale;
+
+ virtual ~OResultColumn() override;
+ public:
+ OResultColumn(
+ const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ private:
+ void impl_determineIsRowVersion_nothrow();
+
+ protected:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultset.cxx b/dbaccess/source/core/api/resultset.cxx
new file mode 100644
index 000000000..2fe6cf355
--- /dev/null
+++ b/dbaccess/source/core/api/resultset.cxx
@@ -0,0 +1,994 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "resultset.hxx"
+#include <sal/log.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/types.hxx>
+#include <tools/diagnose_ex.h>
+#include "datacolumn.hxx"
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace dbaccess;
+using namespace dbtools;
+
+
+OResultSet::OResultSet(const css::uno::Reference< css::sdbc::XResultSet >& _xResultSet,
+ const css::uno::Reference< css::uno::XInterface >& _xStatement,
+ bool _bCaseSensitive)
+ :OResultSetBase(m_aMutex)
+ ,OPropertySetHelper(OResultSetBase::rBHelper)
+ ,m_xDelegatorResultSet(_xResultSet)
+ ,m_aWarnings( Reference< XWarningsSupplier >( _xResultSet, UNO_QUERY ) )
+ ,m_nResultSetConcurrency(0)
+ ,m_bIsBookmarkable(false)
+{
+ m_pColumns.reset( new OColumns(*this, m_aMutex, _bCaseSensitive, std::vector< OUString>(), nullptr,nullptr) );
+
+ try
+ {
+ m_aStatement = _xStatement;
+ m_xDelegatorResultSetUpdate.set(m_xDelegatorResultSet, css::uno::UNO_QUERY);
+ m_xDelegatorRow.set(m_xDelegatorResultSet, css::uno::UNO_QUERY);
+ m_xDelegatorRowUpdate.set(m_xDelegatorResultSet, css::uno::UNO_QUERY);
+
+ Reference< XPropertySet > xSet(m_xDelegatorResultSet, UNO_QUERY);
+ sal_Int32 nResultSetType(0);
+ xSet->getPropertyValue(PROPERTY_RESULTSETTYPE) >>= nResultSetType;
+ xSet->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY) >>= m_nResultSetConcurrency;
+
+ // test for Bookmarks
+ if (ResultSetType::FORWARD_ONLY != nResultSetType)
+ {
+ Reference <XPropertySetInfo > xInfo(xSet->getPropertySetInfo());
+ if (xInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE))
+ {
+ m_bIsBookmarkable = ::comphelper::getBOOL(xSet->getPropertyValue(PROPERTY_ISBOOKMARKABLE));
+ OSL_ENSURE( !m_bIsBookmarkable || Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY).is(),
+ "OResultSet::OResultSet: aggregate is inconsistent in its bookmarkable attribute!" );
+ m_bIsBookmarkable = m_bIsBookmarkable && Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY).is();
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+OResultSet::~OResultSet()
+{
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OResultSet::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XPropertySet>::get(),
+ OResultSetBase::getTypes());
+
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > OResultSet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OResultSet::queryInterface( const Type & rType )
+{
+ Any aIface = OResultSetBase::queryInterface( rType );
+ if (!aIface.hasValue())
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XPropertySet * >( this ));
+
+ return aIface;
+}
+
+void OResultSet::acquire() noexcept
+{
+ OResultSetBase::acquire();
+}
+
+void OResultSet::release() noexcept
+{
+ OResultSetBase::release();
+}
+
+
+// OResultSetBase
+void OResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ // free the columns
+ m_pColumns->disposing();
+
+ // close the pending result set
+ Reference< XCloseable > (m_xDelegatorResultSet, UNO_QUERY_THROW)->close();
+
+ m_xDelegatorResultSet = nullptr;
+ m_xDelegatorRow = nullptr;
+ m_xDelegatorRowUpdate = nullptr;
+
+ m_aStatement.clear();
+}
+
+// XCloseable
+void OResultSet::close()
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+// XServiceInfo
+OUString OResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdb.OResultSet";
+}
+
+sal_Bool OResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OResultSet::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_RESULTSET, SERVICE_SDB_RESULTSET };
+}
+
+// css::beans::XPropertySet
+Reference< XPropertySetInfo > OResultSet::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OResultSet::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_CURSORNAME, PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OResultSet::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ // be lazy ...
+ rConvertedValue = rValue;
+ getFastPropertyValue( rOldValue, nHandle );
+ return true;
+}
+
+void OResultSet::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ // set it for the driver result set
+ Reference< XPropertySet > xSet(m_xDelegatorResultSet, UNO_QUERY);
+ switch (nHandle)
+ {
+ case PROPERTY_ID_FETCHDIRECTION:
+ xSet->setPropertyValue(PROPERTY_FETCHDIRECTION, rValue);
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ xSet->setPropertyValue(PROPERTY_FETCHSIZE, rValue);
+ break;
+ default:
+ SAL_WARN("dbaccess", "unknown Property");
+ }
+}
+
+void OResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ {
+ rValue <<= m_bIsBookmarkable;
+ } break;
+ default:
+ {
+ // get the property name
+ OUString aPropName;
+ sal_Int16 nAttributes;
+ const_cast<OResultSet*>(this)->getInfoHelper().
+ fillPropertyMembersByHandle(&aPropName, &nAttributes, nHandle);
+ OSL_ENSURE(!aPropName.isEmpty(), "property not found?");
+
+ // now read the value
+ rValue = Reference< XPropertySet >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getPropertyValue(aPropName);
+ }
+ }
+}
+
+// XWarningsSupplier
+Any OResultSet::getWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+ return m_aWarnings.getWarnings();
+}
+
+void OResultSet::clearWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+ m_aWarnings.clearWarnings();
+}
+
+// css::sdbc::XResultSetMetaDataSupplier
+Reference< XResultSetMetaData > OResultSet::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return Reference< XResultSetMetaDataSupplier >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getMetaData();
+}
+
+// css::sdbc::XColumnLocate
+sal_Int32 OResultSet::findColumn(const OUString& columnName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return Reference< XColumnLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->findColumn(columnName);
+}
+
+namespace
+{
+ Reference< XDatabaseMetaData > lcl_getDBMetaDataFromStatement_nothrow( const Reference< XInterface >& _rxStatement )
+ {
+ Reference< XDatabaseMetaData > xDBMetaData;
+ try
+ {
+ Reference< XStatement > xStatement( _rxStatement, UNO_QUERY );
+ Reference< XPreparedStatement > xPreparedStatement( _rxStatement, UNO_QUERY );
+ Reference< XConnection > xConn;
+ if ( xStatement.is() )
+ xConn = xStatement->getConnection();
+ else if ( xPreparedStatement.is() )
+ xConn = xPreparedStatement->getConnection();
+ if ( xConn.is() )
+ xDBMetaData = xConn->getMetaData();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xDBMetaData;
+ }
+}
+
+// css::sdbcx::XColumnsSupplier
+Reference< css::container::XNameAccess > OResultSet::getColumns()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ // do we have to populate the columns
+ if (!m_pColumns->isInitialized())
+ {
+ // get the metadata
+ Reference< XResultSetMetaData > xMetaData = Reference< XResultSetMetaDataSupplier >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getMetaData();
+
+ sal_Int32 nColCount = 0;
+ // do we have columns
+ try
+ {
+ Reference< XDatabaseMetaData > xDBMetaData( lcl_getDBMetaDataFromStatement_nothrow( getStatement() ) );
+ nColCount = xMetaData->getColumnCount();
+
+ for ( sal_Int32 i = 0; i < nColCount; ++i)
+ {
+ // retrieve the name of the column
+ OUString sName = xMetaData->getColumnName(i + 1);
+ rtl::Reference<ODataColumn> pColumn = new ODataColumn(xMetaData, m_xDelegatorRow, m_xDelegatorRowUpdate, i + 1, xDBMetaData);
+
+ // don't silently assume that the name is unique - result set implementations
+ // are allowed to return duplicate names, but we are required to have
+ // unique column names
+ if ( m_pColumns->hasByName( sName ) )
+ sName = ::dbtools::createUniqueName( m_pColumns.get(), sName );
+
+ m_pColumns->append( sName, pColumn.get() );
+ }
+ }
+ catch ( const SQLException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_pColumns->setInitialized();
+
+ #if OSL_DEBUG_LEVEL > 0
+ // some sanity checks. Especially in case we auto-adjusted the column names above,
+ // this might be reasonable
+ try
+ {
+ const Reference< XNameAccess > xColNames( static_cast< XNameAccess* >( m_pColumns.get() ), UNO_SET_THROW );
+ const Sequence< OUString > aNames( xColNames->getElementNames() );
+ SAL_WARN_IF( aNames.getLength() != nColCount, "dbaccess",
+ "OResultSet::getColumns: invalid column count!" );
+ for ( auto const & name : aNames )
+ {
+ Reference< XPropertySet > xColProps( xColNames->getByName( name ), UNO_QUERY_THROW );
+ OUString sName;
+ OSL_VERIFY( xColProps->getPropertyValue( PROPERTY_NAME ) >>= sName );
+ SAL_WARN_IF( sName != name, "dbaccess", "OResultSet::getColumns: invalid column name!" );
+ }
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ #endif
+ }
+ return m_pColumns.get();
+}
+
+// css::sdbc::XRow
+sal_Bool OResultSet::wasNull()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->wasNull();
+}
+
+OUString OResultSet::getString(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getString(columnIndex);
+}
+
+sal_Bool OResultSet::getBoolean(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBoolean(columnIndex);
+}
+
+sal_Int8 OResultSet::getByte(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getByte(columnIndex);
+}
+
+sal_Int16 OResultSet::getShort(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getShort(columnIndex);
+}
+
+sal_Int32 OResultSet::getInt(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getInt(columnIndex);
+}
+
+sal_Int64 OResultSet::getLong(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getLong(columnIndex);
+}
+
+float OResultSet::getFloat(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getFloat(columnIndex);
+}
+
+double OResultSet::getDouble(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getDouble(columnIndex);
+}
+
+Sequence< sal_Int8 > OResultSet::getBytes(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBytes(columnIndex);
+}
+
+css::util::Date OResultSet::getDate(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getDate(columnIndex);
+}
+
+css::util::Time OResultSet::getTime(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getTime(columnIndex);
+}
+
+css::util::DateTime OResultSet::getTimestamp(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getTimestamp(columnIndex);
+}
+
+Reference< css::io::XInputStream > OResultSet::getBinaryStream(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > OResultSet::getCharacterStream(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getCharacterStream(columnIndex);
+}
+
+Any OResultSet::getObject(sal_Int32 columnIndex, const Reference< css::container::XNameAccess > & typeMap)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getObject(columnIndex, typeMap);
+}
+
+Reference< XRef > OResultSet::getRef(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getRef(columnIndex);
+}
+
+Reference< XBlob > OResultSet::getBlob(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBlob(columnIndex);
+}
+
+Reference< XClob > OResultSet::getClob(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getClob(columnIndex);
+}
+
+Reference< XArray > OResultSet::getArray(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getArray(columnIndex);
+}
+
+// css::sdbc::XRowUpdate
+void OResultSet::updateNull(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateNull(columnIndex);
+}
+
+void OResultSet::updateBoolean(sal_Int32 columnIndex, sal_Bool x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateBoolean(columnIndex, x);
+}
+
+void OResultSet::updateByte(sal_Int32 columnIndex, sal_Int8 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateByte(columnIndex, x);
+}
+
+void OResultSet::updateShort(sal_Int32 columnIndex, sal_Int16 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateShort(columnIndex, x);
+}
+
+void OResultSet::updateInt(sal_Int32 columnIndex, sal_Int32 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateInt(columnIndex, x);
+}
+
+void OResultSet::updateLong(sal_Int32 columnIndex, sal_Int64 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateLong(columnIndex, x);
+}
+
+void OResultSet::updateFloat(sal_Int32 columnIndex, float x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateFloat(columnIndex, x);
+}
+
+void OResultSet::updateDouble(sal_Int32 columnIndex, double x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateDouble(columnIndex, x);
+}
+
+void OResultSet::updateString(sal_Int32 columnIndex, const OUString& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateString(columnIndex, x);
+}
+
+void OResultSet::updateBytes(sal_Int32 columnIndex, const Sequence< sal_Int8 >& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateBytes(columnIndex, x);
+}
+
+void OResultSet::updateDate(sal_Int32 columnIndex, const css::util::Date& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateDate(columnIndex, x);
+}
+
+void OResultSet::updateTime(sal_Int32 columnIndex, const css::util::Time& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateTime(columnIndex, x);
+}
+
+void OResultSet::updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateTimestamp(columnIndex, x);
+}
+
+void OResultSet::updateBinaryStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateBinaryStream(columnIndex, x, length);
+}
+
+void OResultSet::updateCharacterStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateCharacterStream(columnIndex, x, length);
+}
+
+void OResultSet::updateNumericObject(sal_Int32 columnIndex, const Any& x, sal_Int32 scale)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateNumericObject(columnIndex, x, scale);
+}
+
+void OResultSet::updateObject(sal_Int32 columnIndex, const Any& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateObject(columnIndex, x);
+}
+
+// css::sdbc::XResultSet
+sal_Bool OResultSet::next()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->next();
+}
+
+sal_Bool OResultSet::isBeforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isBeforeFirst();
+}
+
+sal_Bool OResultSet::isAfterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isAfterLast();
+}
+
+sal_Bool OResultSet::isFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isFirst();
+}
+
+sal_Bool OResultSet::isLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isLast();
+}
+
+void OResultSet::beforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ m_xDelegatorResultSet->beforeFirst();
+}
+
+void OResultSet::afterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ m_xDelegatorResultSet->afterLast();
+}
+
+sal_Bool OResultSet::first()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->first();
+}
+
+sal_Bool OResultSet::last()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->last();
+}
+
+sal_Int32 OResultSet::getRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->getRow();
+}
+
+sal_Bool OResultSet::absolute(sal_Int32 row)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->absolute(row);
+}
+
+sal_Bool OResultSet::relative(sal_Int32 rows)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->relative(rows);
+}
+
+sal_Bool OResultSet::previous()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->previous();
+}
+
+void OResultSet::refreshRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ m_xDelegatorResultSet->refreshRow();
+}
+
+sal_Bool OResultSet::rowUpdated()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->rowUpdated();
+}
+
+sal_Bool OResultSet::rowInserted()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->rowInserted();
+}
+
+sal_Bool OResultSet::rowDeleted()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->rowDeleted();
+}
+
+Reference< XInterface > OResultSet::getStatement()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_aStatement;
+}
+
+// css::sdbcx::XRowLocate
+Any OResultSet::getBookmark()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getBookmark();
+}
+
+sal_Bool OResultSet::moveToBookmark(const Any& bookmark)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->moveToBookmark(bookmark);
+}
+
+sal_Bool OResultSet::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->moveRelativeToBookmark(bookmark, rows);
+}
+
+sal_Int32 OResultSet::compareBookmarks(const Any& _first, const Any& _second)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->compareBookmarks(_first, _second);
+}
+
+sal_Bool OResultSet::hasOrderedBookmarks()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->hasOrderedBookmarks();
+}
+
+sal_Int32 OResultSet::hashBookmark(const Any& bookmark)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->hashBookmark(bookmark);
+}
+
+// css::sdbc::XResultSetUpdate
+void OResultSet::insertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->insertRow();
+}
+
+void OResultSet::updateRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->updateRow();
+}
+
+void OResultSet::deleteRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->deleteRow();
+}
+
+void OResultSet::cancelRowUpdates()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->cancelRowUpdates();
+}
+
+void OResultSet::moveToInsertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->moveToInsertRow();
+}
+
+void OResultSet::moveToCurrentRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->moveToCurrentRow();
+}
+
+void OResultSet::checkReadOnly() const
+{
+ if ( ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ || !m_xDelegatorResultSetUpdate.is()
+ )
+ throwSQLException( "The result set is read-only.", StandardSQLState::GENERAL_ERROR, *const_cast< OResultSet* >( this ) );
+}
+
+void OResultSet::checkBookmarkable() const
+{
+ if ( !m_bIsBookmarkable )
+ throwSQLException( "The result set does not have bookmark support.", StandardSQLState::GENERAL_ERROR, *const_cast< OResultSet* >( this ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultset.hxx b/dbaccess/source/core/api/resultset.hxx
new file mode 100644
index 000000000..b2da0f248
--- /dev/null
+++ b/dbaccess/source/core/api/resultset.hxx
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <column.hxx>
+#include <connectivity/warningscontainer.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+
+#include <cppuhelper/propshlp.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+namespace dbaccess
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSet,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::sdbc::XRow,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XColumnsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::lang::XServiceInfo > OResultSetBase;
+
+ // OResultSet
+
+ class OResultSet final : public cppu::BaseMutex,
+ public OResultSetBase,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper < OResultSet >
+ {
+ css::uno::Reference< css::uno::XInterface> m_aStatement;
+
+ css::uno::Reference< css::sdbc::XResultSet > m_xDelegatorResultSet;
+ css::uno::Reference< css::sdbc::XResultSetUpdate > m_xDelegatorResultSetUpdate;
+ css::uno::Reference< css::sdbc::XRow > m_xDelegatorRow;
+ css::uno::Reference< css::sdbc::XRowUpdate > m_xDelegatorRowUpdate;
+
+ ::dbtools::WarningsContainer m_aWarnings;
+ std::unique_ptr<OColumns> m_pColumns;
+ sal_Int32 m_nResultSetConcurrency;
+ bool m_bIsBookmarkable : 1;
+
+ public:
+ OResultSet(const css::uno::Reference< css::sdbc::XResultSet >& _xResultSet,
+ const css::uno::Reference< css::uno::XInterface >& _xStatement,
+ bool _bCaseSensitive);
+ virtual ~OResultSet() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ // css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // css::sdbc::XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // css::sdbc::XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+
+ // css::sdbc::XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+ private:
+ void checkReadOnly() const;
+ void checkBookmarkable() const;
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/statement.cxx b/dbaccess/source/core/api/statement.cxx
new file mode 100644
index 000000000..3a67cbaeb
--- /dev/null
+++ b/dbaccess/source/core/api/statement.cxx
@@ -0,0 +1,591 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <statement.hxx>
+#include "resultset.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <tools/diagnose_ex.h>
+#include <connectivity/dbexception.hxx>
+
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace dbaccess;
+using namespace dbtools;
+
+
+OStatementBase::OStatementBase(const Reference< XConnection > & _xConn,
+ const Reference< XInterface > & _xStatement)
+ :OSubComponent(m_aMutex, _xConn)
+ ,OPropertySetHelper(OComponentHelper::rBHelper)
+ ,m_bUseBookmarks( false )
+ ,m_bEscapeProcessing( true )
+
+{
+ OSL_ENSURE(_xStatement.is() ,"Statement is NULL!");
+ m_xAggregateAsSet.set(_xStatement,UNO_QUERY);
+ m_xAggregateAsCancellable.set(m_xAggregateAsSet, UNO_QUERY);
+}
+
+OStatementBase::~OStatementBase()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OStatementBase::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XWarningsSupplier>::get(),
+ cppu::UnoType<XCloseable>::get(),
+ cppu::UnoType<XMultipleResults>::get(),
+ cppu::UnoType<css::util::XCancellable>::get(),
+ OSubComponent::getTypes() );
+ Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY);
+ if ( xGRes.is() )
+ aTypes = OTypeCollection(cppu::UnoType<XGeneratedResultSet>::get(),aTypes.getTypes());
+ Reference< XPreparedBatchExecution > xPreparedBatchExecution(m_xAggregateAsSet, UNO_QUERY);
+ if ( xPreparedBatchExecution.is() )
+ aTypes = OTypeCollection(cppu::UnoType<XPreparedBatchExecution>::get(),aTypes.getTypes());
+
+ return aTypes.getTypes();
+}
+
+// css::uno::XInterface
+Any OStatementBase::queryInterface( const Type & rType )
+{
+ Any aIface = OSubComponent::queryInterface( rType );
+ if (!aIface.hasValue())
+ {
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XPropertySet * >( this ),
+ static_cast< XWarningsSupplier * >( this ),
+ static_cast< XCloseable * >( this ),
+ static_cast< XMultipleResults * >( this ),
+ static_cast< css::util::XCancellable * >( this ));
+ if ( !aIface.hasValue() )
+ {
+ Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY);
+ if ( cppu::UnoType<XGeneratedResultSet>::get()== rType && xGRes.is() )
+ aIface = ::cppu::queryInterface(rType,static_cast< XGeneratedResultSet * >( this ));
+ }
+ if ( !aIface.hasValue() )
+ {
+ Reference< XPreparedBatchExecution > xGRes(m_xAggregateAsSet, UNO_QUERY);
+ if ( cppu::UnoType<XPreparedBatchExecution>::get()== rType && xGRes.is() )
+ aIface = ::cppu::queryInterface(rType,static_cast< XPreparedBatchExecution * >( this ));
+ }
+ }
+ return aIface;
+}
+
+void OStatementBase::acquire() noexcept
+{
+ OSubComponent::acquire();
+}
+
+void OStatementBase::release() noexcept
+{
+ OSubComponent::release();
+}
+
+void OStatementBase::disposeResultSet()
+{
+ // free the cursor if alive
+ Reference< XComponent > xComp(m_aResultSet.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_aResultSet.clear();
+}
+
+// OComponentHelper
+void OStatementBase::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ // free pending results
+ disposeResultSet();
+
+ // free the original statement
+ {
+ MutexGuard aCancelGuard(m_aCancelMutex);
+ m_xAggregateAsCancellable = nullptr;
+ }
+
+ if ( m_xAggregateAsSet.is() )
+ {
+ try
+ {
+ Reference< XCloseable > (m_xAggregateAsSet, UNO_QUERY_THROW)->close();
+ }
+ catch(RuntimeException& )
+ {// don't care for anymore
+ }
+ }
+ m_xAggregateAsSet = nullptr;
+
+ // free the parent at last
+ OSubComponent::disposing();
+}
+
+// XCloseable
+void OStatementBase::close()
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+// OPropertySetHelper
+Reference< XPropertySetInfo > OStatementBase::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OStatementBase::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_CURSORNAME, PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0 },
+ { PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, cppu::UnoType<bool>::get(), 0 },
+ { PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_MAXFIELDSIZE, PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_MAXROWS, PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_QUERYTIMEOUT, PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_USEBOOKMARKS, PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0 }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OStatementBase::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OStatementBase::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bModified(false);
+ switch (nHandle)
+ {
+ case PROPERTY_ID_USEBOOKMARKS:
+ bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bUseBookmarks );
+ break;
+
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bEscapeProcessing );
+ break;
+
+ default:
+ if ( m_xAggregateAsSet.is() )
+ {
+ // get the property name
+ OUString sPropName;
+ getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
+
+ // now set the value
+ Any aCurrentValue = m_xAggregateAsSet->getPropertyValue( sPropName );
+ if ( aCurrentValue != rValue )
+ {
+ rOldValue = aCurrentValue;
+ rConvertedValue = rValue;
+ bModified = true;
+ }
+ }
+ break;
+ }
+ return bModified;
+}
+
+void OStatementBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ switch ( nHandle )
+ {
+ case PROPERTY_ID_USEBOOKMARKS:
+ {
+ m_bUseBookmarks = ::comphelper::getBOOL( rValue );
+ if ( m_xAggregateAsSet.is() && m_xAggregateAsSet->getPropertySetInfo()->hasPropertyByName( PROPERTY_USEBOOKMARKS ) )
+ m_xAggregateAsSet->setPropertyValue( PROPERTY_USEBOOKMARKS, rValue );
+ }
+ break;
+
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ m_bEscapeProcessing = ::comphelper::getBOOL( rValue );
+ if ( m_xAggregateAsSet.is() )
+ m_xAggregateAsSet->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, rValue );
+ break;
+
+ default:
+ if ( m_xAggregateAsSet.is() )
+ {
+ OUString sPropName;
+ getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
+ m_xAggregateAsSet->setPropertyValue( sPropName, rValue );
+ }
+ break;
+ }
+}
+
+void OStatementBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_USEBOOKMARKS:
+ rValue <<= m_bUseBookmarks;
+ break;
+
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ // don't rely on our aggregate - if it implements this wrong, and always returns
+ // TRUE here, then we would loop in impl_doEscapeProcessing_nothrow
+ rValue <<= m_bEscapeProcessing;
+ break;
+
+ default:
+ if ( m_xAggregateAsSet.is() )
+ {
+ OUString sPropName;
+ const_cast< OStatementBase* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
+ rValue = m_xAggregateAsSet->getPropertyValue( sPropName );
+ }
+ break;
+ }
+}
+
+// XWarningsSupplier
+Any OStatementBase::getWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XWarningsSupplier >(m_xAggregateAsSet, UNO_QUERY_THROW)->getWarnings();
+}
+
+void OStatementBase::clearWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ Reference< XWarningsSupplier >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearWarnings();
+}
+
+// css::util::XCancellable
+void OStatementBase::cancel()
+{
+ // no blocking as cancel is typically called from a different thread
+ MutexGuard aCancelGuard(m_aCancelMutex);
+ if (m_xAggregateAsCancellable.is())
+ m_xAggregateAsCancellable->cancel();
+ // else do nothing
+}
+
+// XMultipleResults
+Reference< XResultSet > SAL_CALL OStatementBase::getResultSet( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsMultipleResultSets())
+ throwFunctionSequenceException(*this);
+
+ return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getResultSet();
+}
+
+sal_Int32 SAL_CALL OStatementBase::getUpdateCount( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsMultipleResultSets())
+ throwFunctionSequenceException(*this);
+
+ return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getUpdateCount();
+}
+
+sal_Bool SAL_CALL OStatementBase::getMoreResults( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsMultipleResultSets())
+ throwFunctionSequenceException(*this);
+
+ // free the previous results
+ disposeResultSet();
+
+ return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getMoreResults();
+}
+
+// XPreparedBatchExecution
+void SAL_CALL OStatementBase::addBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->addBatch();
+}
+
+void SAL_CALL OStatementBase::clearBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearBatch();
+}
+
+Sequence< sal_Int32 > SAL_CALL OStatementBase::executeBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ // free the previous results
+ disposeResultSet();
+
+ return Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->executeBatch();
+}
+
+Reference< XResultSet > SAL_CALL OStatementBase::getGeneratedValues( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY);
+
+ if ( xGRes.is() )
+ return xGRes->getGeneratedValues( );
+ return Reference< XResultSet >();
+}
+
+
+// OStatement
+
+OStatement::OStatement( const Reference< XConnection >& _xConn, const Reference< XInterface > & _xStatement )
+ :OStatementBase( _xConn, _xStatement )
+ ,m_bAttemptedComposerCreation( false )
+{
+ m_xAggregateStatement.set( _xStatement, UNO_QUERY_THROW );
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( OStatement, OStatementBase, OStatement_IFACE );
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement, OStatementBase, OStatement_IFACE );
+
+// XServiceInfo
+OUString OStatement::getImplementationName( )
+{
+ return "com.sun.star.sdb.OStatement";
+}
+
+sal_Bool OStatement::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OStatement::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_STATEMENT };
+}
+
+// XStatement
+Reference< XResultSet > OStatement::executeQuery( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+ Reference< XResultSet > xResultSet;
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+
+ Reference< XResultSet > xInnerResultSet = m_xAggregateStatement->executeQuery( sSQL );
+ Reference< XConnection > xConnection( m_xParent, UNO_QUERY_THROW );
+
+ if ( xInnerResultSet.is() )
+ {
+ Reference< XDatabaseMetaData > xMeta = xConnection->getMetaData();
+ bool bCaseSensitive = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ xResultSet = new OResultSet( xInnerResultSet, *this, bCaseSensitive );
+
+ // keep the resultset weak
+ m_aResultSet = xResultSet;
+ }
+
+ return xResultSet;
+}
+
+sal_Int32 OStatement::executeUpdate( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+ return m_xAggregateStatement->executeUpdate( sSQL );
+}
+
+sal_Bool OStatement::execute( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+ return m_xAggregateStatement->execute( sSQL );
+}
+
+void OStatement::addBatch( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+ Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->addBatch( sSQL );
+}
+
+void OStatement::clearBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearBatch();
+}
+
+Sequence< sal_Int32 > OStatement::executeBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+ return Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->executeBatch( );
+}
+
+
+Reference< XConnection > OStatement::getConnection()
+{
+ return Reference< XConnection >( m_xParent, UNO_QUERY );
+}
+
+void SAL_CALL OStatement::disposing()
+{
+ OStatementBase::disposing();
+ m_xComposer.clear();
+ m_xAggregateStatement.clear();
+}
+
+OUString OStatement::impl_doEscapeProcessing_nothrow( const OUString& _rSQL ) const
+{
+ if ( !m_bEscapeProcessing )
+ return _rSQL;
+ try
+ {
+ if ( !impl_ensureComposer_nothrow() )
+ return _rSQL;
+
+ bool bParseable = false;
+ try { m_xComposer->setQuery( _rSQL ); bParseable = true; }
+ catch( const SQLException& ) { }
+
+ if ( !bParseable )
+ // if we cannot parse it, silently accept this. The driver is probably able to cope with it then
+ return _rSQL;
+
+ OUString sLowLevelSQL = m_xComposer->getQueryWithSubstitution();
+ return sLowLevelSQL;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return _rSQL;
+}
+
+bool OStatement::impl_ensureComposer_nothrow() const
+{
+ if ( m_bAttemptedComposerCreation )
+ return m_xComposer.is();
+
+ const_cast< OStatement* >( this )->m_bAttemptedComposerCreation = true;
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( m_xParent, UNO_QUERY_THROW );
+ const_cast< OStatement* >( this )->m_xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return m_xComposer.is();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/table.cxx b/dbaccess/source/core/api/table.cxx
new file mode 100644
index 000000000..f9a1dffb9
--- /dev/null
+++ b/dbaccess/source/core/api/table.cxx
@@ -0,0 +1,352 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <table.hxx>
+#include <definitioncolumn.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include "CIndexes.hxx"
+
+#include <osl/diagnose.h>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdb/tools/XTableRename.hpp>
+#include <com/sun/star/sdb/tools/XTableAlteration.hpp>
+
+#include <connectivity/TKeys.hxx>
+#include <connectivity/dbtools.hxx>
+
+#include <ContainerMediator.hxx>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+// ODBTable
+
+ODBTable::ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const Reference< XConnection >& _rxConn
+ ,const OUString& _rCatalog
+ ,const OUString& _rSchema
+ ,const OUString& _rName
+ ,const OUString& _rType
+ ,const OUString& _rDesc
+ ,const Reference< XNameAccess >& _xColumnDefinitions)
+ :OTable_Base(_pTables,_rxConn,_rxConn->getMetaData().is() && _rxConn->getMetaData()->supportsMixedCaseQuotedIdentifiers(), _rName, _rType, _rDesc, _rSchema, _rCatalog )
+ ,m_xColumnDefinitions(_xColumnDefinitions)
+ ,m_nPrivileges(0)
+{
+ OSL_ENSURE(getMetaData().is(), "ODBTable::ODBTable : invalid conn !");
+ OSL_ENSURE(!_rName.isEmpty(), "ODBTable::ODBTable : name !");
+ // TODO : think about collecting the privileges here, as we can't ensure that in getFastPropertyValue, where
+ // we do this at the moment, the statement needed can be supplied by the connection (for example the SQL-Server
+ // ODBC driver does not allow more than one statement per connection, and in getFastPropertyValue it's more
+ // likely that it's already used up than it's here.)
+}
+
+ODBTable::ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const Reference< XConnection >& _rxConn)
+ :OTable_Base(_pTables,_rxConn, _rxConn->getMetaData().is() && _rxConn->getMetaData()->supportsMixedCaseQuotedIdentifiers())
+ ,m_nPrivileges(-1)
+{
+}
+
+ODBTable::~ODBTable()
+{
+}
+
+rtl::Reference<OColumn> ODBTable::createColumn(const OUString& _rName) const
+{
+ Reference<XPropertySet> xProp;
+ if ( m_xDriverColumns.is() && m_xDriverColumns->hasByName(_rName) )
+ {
+ xProp.set(m_xDriverColumns->getByName(_rName),UNO_QUERY);
+ }
+ else
+ {
+ OColumns* pColumns = static_cast<OColumns*>(m_xColumns.get());
+ xProp.set(pColumns->createBaseObject(_rName),UNO_QUERY);
+ }
+
+ Reference<XPropertySet> xColumnDefinition;
+ if ( m_xColumnDefinitions.is() && m_xColumnDefinitions->hasByName(_rName) )
+ xColumnDefinition.set(m_xColumnDefinitions->getByName(_rName),UNO_QUERY);
+ return new OTableColumnWrapper( xProp, xColumnDefinition, false );
+}
+
+void ODBTable::columnAppended( const Reference< XPropertySet >& /*_rxSourceDescriptor*/ )
+{
+ // not interested in
+}
+
+void ODBTable::columnDropped(const OUString& _sName)
+{
+ Reference<XDrop> xDrop(m_xColumnDefinitions,UNO_QUERY);
+ if ( xDrop.is() && m_xColumnDefinitions->hasByName(_sName) )
+ {
+ xDrop->dropByName(_sName);
+ }
+}
+
+Sequence< sal_Int8 > ODBTable::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// OComponentHelper
+void SAL_CALL ODBTable::disposing()
+{
+ OPropertySetHelper::disposing();
+ OTable_Base::disposing();
+ m_xColumnDefinitions = nullptr;
+ m_xDriverColumns = nullptr;
+ m_pColumnMediator = nullptr;
+}
+
+void ODBTable::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
+{
+ if ((PROPERTY_ID_PRIVILEGES == _nHandle) && (-1 == m_nPrivileges))
+ { // somebody is asking for the privileges and we do not know them, yet
+ const_cast<ODBTable*>(this)->m_nPrivileges = ::dbtools::getTablePrivileges(getMetaData(),m_CatalogName,m_SchemaName, m_Name);
+ }
+
+ OTable_Base::getFastPropertyValue(_rValue, _nHandle);
+}
+
+void ODBTable::construct()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // we don't collect the privileges here, this is potentially expensive. Instead we determine them on request.
+ // (see getFastPropertyValue)
+ m_nPrivileges = -1;
+
+ OTable_Base::construct();
+
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND,
+ &m_sFilter, cppu::UnoType<OUString>::get());
+
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND,
+ &m_sOrder, cppu::UnoType<OUString>::get());
+
+ registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND,
+ &m_bApplyFilter, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_FONT, PROPERTY_ID_FONT, PropertyAttribute::BOUND,
+ &m_aFont, cppu::UnoType<css::awt::FontDescriptor>::get());
+
+ registerMayBeVoidProperty(PROPERTY_ROW_HEIGHT, PROPERTY_ID_ROW_HEIGHT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &m_aRowHeight, cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_AUTOGROW, PROPERTY_ID_AUTOGROW, PropertyAttribute::BOUND,
+ &m_bAutoGrow, cppu::UnoType<bool>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTCOLOR, PROPERTY_ID_TEXTCOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &m_aTextColor, cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ &m_nPrivileges, cppu::UnoType<sal_Int32>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTLINECOLOR, PROPERTY_ID_TEXTLINECOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &m_aTextLineColor, cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_TEXTEMPHASIS, PROPERTY_ID_TEXTEMPHASIS, PropertyAttribute::BOUND,
+ &m_nFontEmphasis, cppu::UnoType<sal_Int16>::get());
+
+ registerProperty(PROPERTY_TEXTRELIEF, PROPERTY_ID_TEXTRELIEF, PropertyAttribute::BOUND,
+ &m_nFontRelief, cppu::UnoType<sal_Int16>::get());
+
+ registerProperty(PROPERTY_FONTNAME, PROPERTY_ID_FONTNAME, PropertyAttribute::BOUND,&m_aFont.Name, cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_FONTHEIGHT, PROPERTY_ID_FONTHEIGHT, PropertyAttribute::BOUND,&m_aFont.Height, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTWIDTH, PROPERTY_ID_FONTWIDTH, PropertyAttribute::BOUND,&m_aFont.Width, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTSTYLENAME, PROPERTY_ID_FONTSTYLENAME, PropertyAttribute::BOUND,&m_aFont.StyleName, cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_FONTFAMILY, PROPERTY_ID_FONTFAMILY, PropertyAttribute::BOUND,&m_aFont.Family, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTCHARSET, PROPERTY_ID_FONTCHARSET, PropertyAttribute::BOUND,&m_aFont.CharSet, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTPITCH, PROPERTY_ID_FONTPITCH, PropertyAttribute::BOUND,&m_aFont.Pitch, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTCHARWIDTH, PROPERTY_ID_FONTCHARWIDTH, PropertyAttribute::BOUND,&m_aFont.CharacterWidth, cppu::UnoType<float>::get());
+ registerProperty(PROPERTY_FONTWEIGHT, PROPERTY_ID_FONTWEIGHT, PropertyAttribute::BOUND,&m_aFont.Weight, cppu::UnoType<float>::get());
+ registerProperty(PROPERTY_FONTSLANT, PROPERTY_ID_FONTSLANT, PropertyAttribute::BOUND,&m_aFont.Slant, cppu::UnoType<css::awt::FontSlant>::get());
+ registerProperty(PROPERTY_FONTUNDERLINE, PROPERTY_ID_FONTUNDERLINE, PropertyAttribute::BOUND,&m_aFont.Underline, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTSTRIKEOUT, PROPERTY_ID_FONTSTRIKEOUT, PropertyAttribute::BOUND,&m_aFont.Strikeout, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTORIENTATION, PROPERTY_ID_FONTORIENTATION, PropertyAttribute::BOUND,&m_aFont.Orientation, cppu::UnoType<float>::get());
+ registerProperty(PROPERTY_FONTKERNING, PROPERTY_ID_FONTKERNING, PropertyAttribute::BOUND,&m_aFont.Kerning, cppu::UnoType<sal_Bool>::get());
+ registerProperty(PROPERTY_FONTWORDLINEMODE, PROPERTY_ID_FONTWORDLINEMODE,PropertyAttribute::BOUND,&m_aFont.WordLineMode, cppu::UnoType<sal_Bool>::get());
+ registerProperty(PROPERTY_FONTTYPE, PROPERTY_ID_FONTTYPE, PropertyAttribute::BOUND,&m_aFont.Type, cppu::UnoType<sal_Int16>::get());
+
+ refreshColumns();
+}
+
+::cppu::IPropertyArrayHelper* ODBTable::createArrayHelper( sal_Int32 _nId) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ if(!_nId)
+ {
+ for(Property & prop : asNonConstRange(aProps))
+ {
+ if (prop.Name == PROPERTY_CATALOGNAME)
+ prop.Attributes = PropertyAttribute::READONLY;
+ else if (prop.Name == PROPERTY_SCHEMANAME)
+ prop.Attributes = PropertyAttribute::READONLY;
+ else if (prop.Name == PROPERTY_DESCRIPTION)
+ prop.Attributes = PropertyAttribute::READONLY;
+ else if (prop.Name == PROPERTY_NAME)
+ prop.Attributes = PropertyAttribute::READONLY;
+ }
+ }
+
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL ODBTable::getInfoHelper()
+{
+ return *ODBTable_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+// XServiceInfo
+OUString SAL_CALL ODBTable::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.ODBTable";
+ }
+sal_Bool SAL_CALL ODBTable::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL ODBTable::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_TABLE };
+}
+
+
+Any SAL_CALL ODBTable::queryInterface( const Type & rType )
+{
+ if(rType == cppu::UnoType<XRename>::get()&& !getRenameService().is() )
+ return Any();
+ if(rType == cppu::UnoType<XAlterTable>::get()&& !getAlterService().is() )
+ return Any();
+ return OTable_Base::queryInterface( rType);
+}
+
+Sequence< Type > SAL_CALL ODBTable::getTypes( )
+{
+ Type aRenameType = cppu::UnoType<XRename>::get();
+ Type aAlterType = cppu::UnoType<XAlterTable>::get();
+
+ Sequence< Type > aTypes(OTable_Base::getTypes());
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+
+ const Type* pIter = aTypes.getConstArray();
+ const Type* pEnd = pIter + aTypes.getLength();
+ for(;pIter != pEnd ;++pIter)
+ {
+ if( (*pIter != aRenameType || getRenameService().is()) && (*pIter != aAlterType || getAlterService().is()))
+ aOwnTypes.push_back(*pIter);
+ }
+
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+// XRename,
+void SAL_CALL ODBTable::rename( const OUString& _rNewName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed);
+ if ( !getRenameService().is() )
+ throw SQLException(DBA_RES(RID_STR_NO_TABLE_RENAME),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ Reference<XPropertySet> xTable(this);
+ getRenameService()->rename(xTable,_rNewName);
+ ::connectivity::OTable_TYPEDEF::rename(_rNewName);
+}
+
+// XAlterTable,
+void SAL_CALL ODBTable::alterColumnByName( const OUString& _rName, const Reference< XPropertySet >& _rxDescriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed);
+ if ( !getAlterService().is() )
+ throw SQLException(DBA_RES(RID_STR_NO_TABLE_RENAME),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ if ( !m_xColumns->hasByName(_rName) )
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ Reference<XPropertySet> xTable(this);
+ getAlterService()->alterColumnByName(xTable,_rName,_rxDescriptor);
+ m_xColumns->refresh();
+}
+
+sal_Int64 SAL_CALL ODBTable::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OTable_Base>{});
+}
+
+const Sequence< sal_Int8 > & ODBTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit s_Id;
+ return s_Id.getSeq();
+}
+
+Reference< XPropertySet > ODBTable::createColumnDescriptor()
+{
+ return new OTableColumnDescriptor( true );
+}
+
+sdbcx::OCollection* ODBTable::createColumns(const ::std::vector< OUString>& _rNames)
+{
+ Reference<XDatabaseMetaData> xMeta = getMetaData();
+ OColumns* pCol = new OColumns(*this, m_aMutex, nullptr, isCaseSensitive(), _rNames, this,this,
+ getAlterService().is() || (xMeta.is() && xMeta->supportsAlterTableWithAddColumn()),
+ getAlterService().is() || (xMeta.is() && xMeta->supportsAlterTableWithDropColumn()));
+ static_cast<OColumnsHelper*>(pCol)->setParent(this);
+ pCol->setParent(*this);
+ m_pColumnMediator = new OContainerMediator( pCol, m_xColumnDefinitions );
+ pCol->setMediator( m_pColumnMediator.get() );
+ return pCol;
+}
+
+sdbcx::OCollection* ODBTable::createKeys(const ::std::vector< OUString>& _rNames)
+{
+ return new connectivity::OKeysHelper(this,m_aMutex,_rNames);
+}
+
+sdbcx::OCollection* ODBTable::createIndexes(const ::std::vector< OUString>& _rNames)
+{
+ return new OIndexes(this,m_aMutex,_rNames,nullptr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/tablecontainer.cxx b/dbaccess/source/core/api/tablecontainer.cxx
new file mode 100644
index 000000000..3971dd154
--- /dev/null
+++ b/dbaccess/source/core/api/tablecontainer.cxx
@@ -0,0 +1,456 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tablecontainer.hxx>
+#include <table.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/processfactory.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/sdb/TableDefinition.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <TableDeco.hxx>
+#include <sdbcoretools.hxx>
+#include <ContainerMediator.hxx>
+#include <objectnameapproval.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace dbaccess;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::connectivity::sdbcx;
+
+namespace
+{
+ bool lcl_isPropertySetDefaulted(const Sequence< OUString>& _aNames,const Reference<XPropertySet>& _xProp)
+ {
+ Reference<XPropertyState> xState(_xProp,UNO_QUERY);
+ if ( !xState )
+ return false;
+ const OUString* pIter = _aNames.getConstArray();
+ const OUString* pEnd = pIter + _aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ try
+ {
+ PropertyState aState = xState->getPropertyState(*pIter);
+ if ( aState != PropertyState_DEFAULT_VALUE )
+ break;
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "" );
+ }
+ }
+ return ( pIter == pEnd );
+ }
+}
+
+// OTableContainer
+
+OTableContainer::OTableContainer(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const Reference< XConnection >& _xCon,
+ bool _bCase,
+ const Reference< XNameContainer >& _xTableDefinitions,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend)
+ :OFilteredContainer(_rParent,_rMutex,_xCon,_bCase,_pRefreshListener,_nInAppend)
+ ,m_xTableDefinitions(_xTableDefinitions)
+{
+}
+
+OTableContainer::~OTableContainer()
+{
+}
+
+void OTableContainer::removeMasterContainerListener()
+{
+ try
+ {
+ Reference<XContainer> xCont( m_xMasterContainer, UNO_QUERY_THROW );
+ xCont->removeContainerListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OUString OTableContainer::getTableTypeRestriction() const
+{
+ // no restriction at all (other than the ones provided externally)
+ return OUString();
+}
+
+// XServiceInfo
+OUString SAL_CALL OTableContainer::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OTableContainer";
+ }
+sal_Bool SAL_CALL OTableContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OTableContainer::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES };
+}
+
+
+namespace
+{
+void lcl_createDefinitionObject(const OUString& _rName
+ ,const Reference< XNameContainer >& _xTableDefinitions
+ ,Reference<XPropertySet>& _xTableDefinition
+ ,Reference<XNameAccess>& _xColumnDefinitions)
+{
+ if ( !_xTableDefinitions.is() )
+ return;
+
+ if ( _xTableDefinitions->hasByName(_rName) )
+ _xTableDefinition.set(_xTableDefinitions->getByName(_rName),UNO_QUERY);
+ else
+ {
+ // set as folder
+ _xTableDefinition = TableDefinition::createWithName( ::comphelper::getProcessComponentContext(), _rName );
+ _xTableDefinitions->insertByName(_rName,Any(_xTableDefinition));
+ }
+ Reference<XColumnsSupplier> xColumnsSupplier(_xTableDefinition,UNO_QUERY);
+ if ( xColumnsSupplier.is() )
+ _xColumnDefinitions = xColumnsSupplier->getColumns();
+}
+
+}
+
+connectivity::sdbcx::ObjectType OTableContainer::createObject(const OUString& _rName)
+{
+ Reference<XColumnsSupplier > xSup;
+ if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(_rName))
+ xSup.set(m_xMasterContainer->getByName(_rName),UNO_QUERY);
+
+ connectivity::sdbcx::ObjectType xRet;
+ if ( m_xMetaData.is() )
+ {
+ Reference<XPropertySet> xTableDefinition;
+ Reference<XNameAccess> xColumnDefinitions;
+ lcl_createDefinitionObject(_rName,m_xTableDefinitions,xTableDefinition,xColumnDefinitions);
+
+ if ( xSup.is() )
+ {
+ rtl::Reference<ODBTableDecorator> pTable = new ODBTableDecorator( m_xConnection, xSup, ::dbtools::getNumberFormats( m_xConnection ) ,xColumnDefinitions);
+ xRet = pTable;
+ pTable->construct();
+ }
+ else
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,
+ _rName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ Any aCatalog;
+ if(!sCatalog.isEmpty())
+ aCatalog <<= sCatalog;
+ OUString sType,sDescription;
+ Sequence< OUString> aTypeFilter;
+ getAllTableTypeFilter( aTypeFilter );
+
+ Reference< XResultSet > xRes;
+ if ( m_xMetaData.is() )
+ xRes = m_xMetaData->getTables(aCatalog,sSchema,sTable,aTypeFilter);
+ if(xRes.is() && xRes->next())
+ {
+ Reference< XRow > xRow(xRes,UNO_QUERY);
+ if(xRow.is())
+ {
+ sType = xRow->getString(4);
+ sDescription = xRow->getString(5);
+ }
+ }
+ ::comphelper::disposeComponent(xRes);
+ rtl::Reference<ODBTable> pTable = new ODBTable(this
+ ,m_xConnection
+ ,sCatalog
+ ,sSchema
+ ,sTable
+ ,sType
+ ,sDescription
+ ,xColumnDefinitions);
+ xRet = pTable;
+ pTable->construct();
+ }
+ Reference<XPropertySet> xDest(xRet,UNO_QUERY);
+ if ( xTableDefinition.is() )
+ ::comphelper::copyProperties(xTableDefinition,xDest);
+
+ if ( !m_pTableMediator.is() )
+ m_pTableMediator = new OContainerMediator(
+ this, m_xTableDefinitions );
+ if ( m_pTableMediator.is() )
+ m_pTableMediator->notifyElementCreated(_rName,xDest);
+ }
+
+ return xRet;
+}
+
+Reference< XPropertySet > OTableContainer::createDescriptor()
+{
+ Reference< XPropertySet > xRet;
+
+ // first we have to look if the master tables support this
+ // and if so then create a table object as well with the master tables
+ Reference<XColumnsSupplier > xMasterColumnsSup;
+ Reference<XDataDescriptorFactory> xDataFactory(m_xMasterContainer,UNO_QUERY);
+ if ( xDataFactory.is() && m_xMetaData.is() )
+ {
+ xMasterColumnsSup.set( xDataFactory->createDataDescriptor(), UNO_QUERY );
+ rtl::Reference<ODBTableDecorator> pTable = new ODBTableDecorator( m_xConnection, xMasterColumnsSup, ::dbtools::getNumberFormats( m_xConnection ) ,nullptr);
+ xRet = pTable;
+ pTable->construct();
+ }
+ else
+ {
+ rtl::Reference<ODBTable> pTable = new ODBTable(this, m_xConnection);
+ xRet = pTable;
+ pTable->construct();
+ }
+ return xRet;
+}
+
+// XAppend
+ObjectType OTableContainer::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ // append the new table with a create stmt
+ OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME));
+ if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(aName))
+ {
+ OUString sMessage(DBA_RES(RID_STR_TABLE_IS_FILTERED));
+ throw SQLException(sMessage.replaceAll("$name$", aName),static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)),SQLSTATE_GENERAL,1000,Any());
+ }
+
+ Reference< XConnection > xConnection( m_xConnection.get(), UNO_QUERY );
+ PContainerApprove pApprove = std::make_shared<ObjectNameApproval>( xConnection, ObjectNameApproval::TypeTable );
+ pApprove->approveElement( aName );
+
+ {
+ EnsureReset aReset(m_nInAppend);
+ Reference<XAppend> xAppend(m_xMasterContainer,UNO_QUERY);
+ if(xAppend.is())
+ {
+ xAppend->appendByDescriptor(descriptor);
+ }
+ else
+ {
+ OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,m_xConnection);
+
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ Reference< XStatement > xStmt = xCon->createStatement( );
+ if ( xStmt.is() )
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+ }
+
+ Reference<XPropertySet> xTableDefinition;
+ Reference<XNameAccess> xColumnDefinitions;
+ lcl_createDefinitionObject(getNameForObject(descriptor),m_xTableDefinitions,xTableDefinition,xColumnDefinitions);
+ Reference<XColumnsSupplier> xSup(descriptor,UNO_QUERY);
+ Reference<XDataDescriptorFactory> xFac(xColumnDefinitions,UNO_QUERY);
+ Reference<XAppend> xAppend(xColumnDefinitions,UNO_QUERY);
+ bool bModified = false;
+ if ( xSup.is() && xColumnDefinitions.is() && xFac.is() && xAppend.is() )
+ {
+ Reference<XNameAccess> xNames = xSup->getColumns();
+ if ( xNames.is() )
+ {
+ Reference<XPropertySet> xProp = xFac->createDataDescriptor();
+ Sequence< OUString> aSeq = xNames->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( !xColumnDefinitions->hasByName(*pIter) )
+ {
+ Reference<XPropertySet> xColumn(xNames->getByName(*pIter),UNO_QUERY);
+ if ( !OColumnSettings::hasDefaultSettings( xColumn ) )
+ {
+ ::comphelper::copyProperties( xColumn, xProp );
+ xAppend->appendByDescriptor( xProp );
+ bModified = true;
+ }
+ }
+ }
+ }
+ }
+ Sequence< OUString> aNames{
+ PROPERTY_FILTER, PROPERTY_ORDER, PROPERTY_APPLYFILTER, PROPERTY_FONT,
+ PROPERTY_ROW_HEIGHT, PROPERTY_TEXTCOLOR, PROPERTY_TEXTLINECOLOR,
+ PROPERTY_TEXTEMPHASIS, PROPERTY_TEXTRELIEF};
+ if ( bModified || !lcl_isPropertySetDefaulted(aNames,xTableDefinition) )
+ ::dbaccess::notifyDataSourceModified(m_xTableDefinitions);
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OTableContainer::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference< XDrop > xDrop(m_xMasterContainer,UNO_QUERY);
+ if(xDrop.is())
+ xDrop->dropByName(_sElementName);
+ else
+ {
+ OUString sComposedName;
+
+ bool bIsView = false;
+ Reference<XPropertySet> xTable(getObject(_nPos),UNO_QUERY);
+ if ( xTable.is() && m_xMetaData.is() )
+ {
+ OUString sSchema,sCatalog,sTable;
+ if (m_xMetaData->supportsCatalogsInTableDefinitions())
+ xTable->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog;
+ if (m_xMetaData->supportsSchemasInTableDefinitions())
+ xTable->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema;
+ xTable->getPropertyValue(PROPERTY_NAME) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+
+ OUString sType;
+ xTable->getPropertyValue(PROPERTY_TYPE) >>= sType;
+ bIsView = sType.equalsIgnoreAsciiCase("VIEW");
+ }
+
+ if(sComposedName.isEmpty())
+ ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)));
+
+ OUString aSql("DROP ");
+
+ if ( bIsView ) // here we have a view
+ aSql += "VIEW ";
+ else
+ aSql += "TABLE ";
+ aSql += sComposedName;
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ Reference< XStatement > xStmt = xCon->createStatement( );
+ if(xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+
+ if ( m_xTableDefinitions.is() && m_xTableDefinitions->hasByName(_sElementName) )
+ {
+ m_xTableDefinitions->removeByName(_sElementName);
+ }
+}
+
+void SAL_CALL OTableContainer::elementInserted( const ContainerEvent& Event )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OUString sName;
+ Event.Accessor >>= sName;
+ if ( !m_nInAppend && !hasByName(sName) )
+ {
+ if(!m_xMasterContainer.is() || m_xMasterContainer->hasByName(sName))
+ {
+ ObjectType xName = createObject(sName);
+ insertElement(sName,xName);
+ // and notify our listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(sName), Any(xName), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+ }
+ }
+}
+
+void SAL_CALL OTableContainer::elementRemoved( const ContainerEvent& /*Event*/ )
+{
+}
+
+void SAL_CALL OTableContainer::elementReplaced( const ContainerEvent& Event )
+{
+ // create a new config entry
+ OUString sOldComposedName,sNewComposedName;
+ Event.ReplacedElement >>= sOldComposedName;
+ Event.Accessor >>= sNewComposedName;
+
+ renameObject(sOldComposedName,sNewComposedName);
+}
+
+void OTableContainer::disposing()
+{
+ OFilteredContainer::disposing();
+ // say goodbye to our listeners
+ m_xTableDefinitions = nullptr;
+ m_pTableMediator = nullptr;
+}
+
+void SAL_CALL OTableContainer::disposing( const css::lang::EventObject& /*Source*/ )
+{
+}
+
+void OTableContainer::addMasterContainerListener()
+{
+ try
+ {
+ Reference< XContainer > xCont( m_xMasterContainer, UNO_QUERY_THROW );
+ xCont->addContainerListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/viewcontainer.cxx b/dbaccess/source/core/api/viewcontainer.cxx
new file mode 100644
index 000000000..462a3b1d0
--- /dev/null
+++ b/dbaccess/source/core/api/viewcontainer.cxx
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hxx>
+#include <viewcontainer.hxx>
+#include <View.hxx>
+
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+using namespace dbaccess;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::connectivity::sdbcx;
+
+// OViewContainer
+
+OViewContainer::OViewContainer(::cppu::OWeakObject& _rParent
+ ,::osl::Mutex& _rMutex
+ ,const Reference< XConnection >& _xCon
+ ,bool _bCase
+ ,IRefreshListener* _pRefreshListener
+ ,std::atomic<std::size_t>& _nInAppend)
+ :OFilteredContainer(_rParent,_rMutex,_xCon,_bCase,_pRefreshListener,_nInAppend)
+ ,m_bInElementRemoved(false)
+{
+}
+
+OViewContainer::~OViewContainer()
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL OViewContainer::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OViewContainer";
+ }
+sal_Bool SAL_CALL OViewContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OViewContainer::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES };
+}
+
+
+ObjectType OViewContainer::createObject(const OUString& _rName)
+{
+ ObjectType xProp;
+ if ( m_xMasterContainer.is() && m_xMasterContainer->hasByName(_rName) )
+ xProp.set(m_xMasterContainer->getByName(_rName),UNO_QUERY);
+
+ if ( !xProp.is() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,
+ _rName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ return new View(m_xConnection,
+ isCaseSensitive(),
+ sCatalog,
+ sSchema,
+ sTable
+ );
+ }
+
+ return xProp;
+}
+
+Reference< XPropertySet > OViewContainer::createDescriptor()
+{
+ Reference< XPropertySet > xRet;
+ // first we have to look if the master tables support this
+ // and if so then create a table object as well with the master tables
+ Reference<XDataDescriptorFactory> xDataFactory(m_xMasterContainer,UNO_QUERY);
+ if(xDataFactory.is())
+ xRet = xDataFactory->createDataDescriptor();
+ else
+ xRet = new ::connectivity::sdbcx::OView(isCaseSensitive(),m_xMetaData);
+
+ return xRet;
+}
+
+// XAppend
+ObjectType OViewContainer::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ // append the new table with a create stmt
+ OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME));
+
+ Reference<XAppend> xAppend(m_xMasterContainer,UNO_QUERY);
+ Reference< XPropertySet > xProp = descriptor;
+ if(xAppend.is())
+ {
+ EnsureReset aReset(m_nInAppend);
+
+ xAppend->appendByDescriptor(descriptor);
+ if(m_xMasterContainer->hasByName(aName))
+ xProp.set(m_xMasterContainer->getByName(aName),UNO_QUERY);
+ }
+ else
+ {
+ OUString sComposedName = ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InTableDefinitions, true );
+ if(sComposedName.isEmpty())
+ ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)));
+
+ OUString sCommand;
+ descriptor->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
+
+ OUString aSQL = "CREATE VIEW " + sComposedName + " AS " + sCommand;
+
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ ::utl::SharedUNOComponent< XStatement > xStmt( xCon->createStatement() );
+ if ( xStmt.is() )
+ xStmt->execute( aSQL );
+ }
+ }
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OViewContainer::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ if ( m_bInElementRemoved )
+ return;
+
+ Reference< XDrop > xDrop(m_xMasterContainer,UNO_QUERY);
+ if(xDrop.is())
+ xDrop->dropByName(_sElementName);
+ else
+ {
+ OUString sComposedName;
+
+ Reference<XPropertySet> xTable(getObject(_nPos),UNO_QUERY);
+ if ( xTable.is() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ xTable->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog;
+ xTable->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema;
+ xTable->getPropertyValue(PROPERTY_NAME) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+ }
+
+ if(sComposedName.isEmpty())
+ ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)));
+
+ OUString aSql = "DROP VIEW " + sComposedName;
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ Reference< XStatement > xStmt = xCon->createStatement( );
+ if(xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+}
+
+void SAL_CALL OViewContainer::elementInserted( const ContainerEvent& Event )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OUString sName;
+ if ( ( Event.Accessor >>= sName )
+ && ( !m_nInAppend )
+ && ( !hasByName( sName ) )
+ )
+ {
+ Reference<XPropertySet> xProp(Event.Element,UNO_QUERY);
+ OUString sType;
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= sType;
+ if ( sType == "VIEW" )
+ insertElement(sName,createObject(sName));
+ }
+}
+
+void SAL_CALL OViewContainer::elementRemoved( const ContainerEvent& Event )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OUString sName;
+ if ( !((Event.Accessor >>= sName) && hasByName(sName)) )
+ return;
+
+ m_bInElementRemoved = true;
+ try
+ {
+ dropByName(sName);
+ }
+ catch(Exception&)
+ {
+ m_bInElementRemoved = false;
+ throw;
+ }
+ m_bInElementRemoved = false;
+}
+
+void SAL_CALL OViewContainer::disposing( const css::lang::EventObject& /*Source*/ )
+{
+}
+
+void SAL_CALL OViewContainer::elementReplaced( const ContainerEvent& /*Event*/ )
+{
+}
+
+OUString OViewContainer::getTableTypeRestriction() const
+{
+ // no restriction at all (other than the ones provided externally)
+ return "VIEW";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ComponentDefinition.cxx b/dbaccess/source/core/dataaccess/ComponentDefinition.cxx
new file mode 100644
index 000000000..a3a645982
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ComponentDefinition.cxx
@@ -0,0 +1,285 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ComponentDefinition.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <osl/diagnose.h>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+//#include <cppuhelper/interfacecontainer.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <definitioncolumn.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+/// helper class for column property change events which holds the OComponentDefinition weak
+class OColumnPropertyListener:
+ public ::cppu::WeakImplHelper< XPropertyChangeListener >
+{
+ OComponentDefinition* m_pComponent;
+protected:
+ virtual ~OColumnPropertyListener() override {}
+public:
+ explicit OColumnPropertyListener(OComponentDefinition* _pComponent) : m_pComponent(_pComponent){}
+ OColumnPropertyListener(const OColumnPropertyListener&) = delete;
+ const OColumnPropertyListener& operator=(const OColumnPropertyListener&) = delete;
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const PropertyChangeEvent& /*_rEvent*/ ) override
+ {
+ if ( m_pComponent )
+ m_pComponent->notifyDataSourceModified();
+ }
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) override
+ {
+ }
+ void clear() { m_pComponent = nullptr; }
+};
+
+OComponentDefinition_Impl::OComponentDefinition_Impl()
+{
+}
+
+OComponentDefinition_Impl::~OComponentDefinition_Impl()
+{
+}
+
+// OComponentDefinition
+
+
+void OComponentDefinition::initialize( const Sequence< Any >& aArguments )
+{
+ OUString rName;
+ if( (aArguments.getLength() == 1) && (aArguments[0] >>= rName) )
+ {
+ Sequence<Any> aNewArgs(comphelper::InitAnyPropertySequence(
+ {
+ {PROPERTY_NAME, Any(rName)}
+ }));
+ OContentHelper::initialize(aNewArgs);
+ }
+ else
+ OContentHelper::initialize(aArguments);
+}
+
+void OComponentDefinition::registerProperties()
+{
+ m_xColumnPropertyListener = new OColumnPropertyListener(this);
+ OComponentDefinition_Impl& rDefinition( getDefinition() );
+ ODataSettings::registerPropertiesFor( &rDefinition );
+
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY|PropertyAttribute::CONSTRAINED,
+ &rDefinition.m_aProps.aTitle, cppu::UnoType<decltype(rDefinition.m_aProps.aTitle)>::get());
+
+ if ( m_bTable )
+ {
+ registerProperty(PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, PropertyAttribute::BOUND,
+ &rDefinition.m_sSchemaName, cppu::UnoType<decltype(rDefinition.m_sSchemaName)>::get());
+
+ registerProperty(PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, PropertyAttribute::BOUND,
+ &rDefinition.m_sCatalogName, cppu::UnoType<decltype(rDefinition.m_sCatalogName)>::get());
+ }
+}
+
+OComponentDefinition::OComponentDefinition(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ ,bool _bTable)
+ :OContentHelper(_xORB,_xParentContainer,_pImpl)
+ ,ODataSettings(OContentHelper::rBHelper,!_bTable)
+ ,m_bTable(_bTable)
+{
+ registerProperties();
+}
+
+OComponentDefinition::~OComponentDefinition()
+{
+}
+
+OComponentDefinition::OComponentDefinition( const Reference< XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const Reference< XComponentContext >& _xORB
+ ,const TContentPtr& _pImpl
+ ,bool _bTable)
+ :OContentHelper(_xORB,_rxContainer,_pImpl)
+ ,ODataSettings(OContentHelper::rBHelper,!_bTable)
+ ,m_bTable(_bTable)
+{
+ registerProperties();
+
+ m_pImpl->m_aProps.aTitle = _rElementName;
+ OSL_ENSURE(!m_pImpl->m_aProps.aTitle.isEmpty(), "OComponentDefinition::OComponentDefinition : invalid name !");
+}
+
+css::uno::Sequence<sal_Int8> OComponentDefinition::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OComponentDefinition::getTypes()
+{
+ return ::comphelper::concatSequences(
+ ODataSettings::getTypes( ),
+ OContentHelper::getTypes( ),
+ OComponentDefinition_BASE::getTypes( )
+ );
+}
+IMPLEMENT_FORWARD_XINTERFACE3( OComponentDefinition,OContentHelper,ODataSettings,OComponentDefinition_BASE)
+
+OUString SAL_CALL OComponentDefinition::getImplementationName()
+{
+ return "com.sun.star.comp.dba.OComponentDefinition";
+}
+
+Sequence< OUString > SAL_CALL OComponentDefinition::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.TableDefinition", "com.sun.star.ucb.Content" };
+}
+
+void SAL_CALL OComponentDefinition::disposing()
+{
+ OContentHelper::disposing();
+ if (m_pColumns)
+ {
+ m_pColumns->disposing();
+ }
+ m_xColumnPropertyListener->clear();
+ m_xColumnPropertyListener.clear();
+}
+
+IPropertyArrayHelper& OComponentDefinition::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+IPropertyArrayHelper* OComponentDefinition::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new OPropertyArrayHelper(aProps);
+}
+
+Reference< XPropertySetInfo > SAL_CALL OComponentDefinition::getPropertySetInfo( )
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+OUString OComponentDefinition::determineContentType() const
+{
+ return m_bTable
+ ? OUString( "application/vnd.org.openoffice.DatabaseTable" )
+ : OUString( "application/vnd.org.openoffice.DatabaseCommandDefinition" );
+}
+
+Reference< XNameAccess> OComponentDefinition::getColumns()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OContentHelper::rBHelper.bDisposed);
+
+ if (!m_pColumns)
+ {
+ std::vector< OUString> aNames;
+
+ const OComponentDefinition_Impl& rDefinition( getDefinition() );
+ aNames.reserve( rDefinition.size() );
+
+ for (auto const& definition : rDefinition)
+ aNames.push_back(definition.first);
+
+ m_pColumns.reset(new OColumns(*this, m_aMutex, true, aNames, this, nullptr, true, false, false));
+ m_pColumns->setParent(*this);
+ }
+ // see OCollection::acquire
+ return m_pColumns.get();
+}
+
+rtl::Reference<OColumn> OComponentDefinition::createColumn(const OUString& _rName) const
+{
+ const OComponentDefinition_Impl& rDefinition( getDefinition() );
+ OComponentDefinition_Impl::const_iterator aFind = rDefinition.find( _rName );
+ if ( aFind != rDefinition.end() )
+ {
+ aFind->second->addPropertyChangeListener(OUString(),m_xColumnPropertyListener);
+ return new OTableColumnWrapper( aFind->second, aFind->second, true );
+ }
+ OSL_FAIL( "OComponentDefinition::createColumn: is this a valid case?" );
+ // This here is the last place creating a OTableColumn, and somehow /me thinks it is not needed ...
+ return new OTableColumn( _rName );
+}
+
+Reference< XPropertySet > OComponentDefinition::createColumnDescriptor()
+{
+ return new OTableColumnDescriptor( true );
+}
+
+void OComponentDefinition::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ ODataSettings::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ notifyDataSourceModified();
+}
+
+void OComponentDefinition::columnDropped(const OUString& _sName)
+{
+ getDefinition().erase( _sName );
+ notifyDataSourceModified();
+}
+
+void OComponentDefinition::columnAppended( const Reference< XPropertySet >& _rxSourceDescriptor )
+{
+ OUString sName;
+ _rxSourceDescriptor->getPropertyValue( PROPERTY_NAME ) >>= sName;
+
+ Reference<XPropertySet> xColDesc = new OTableColumnDescriptor( true );
+ ::comphelper::copyProperties( _rxSourceDescriptor, xColDesc );
+ getDefinition().insert( sName, xColDesc );
+
+ // formerly, here was a setParent at the xColDesc. The parent used was an adapter (ChildHelper_Impl)
+ // which held another XChild weak, and forwarded all getParent requests to this other XChild.
+ // m_pColumns was used for this. This was nonsense, since m_pColumns dies when our instance dies,
+ // but xColDesc will live longer than this. So effectively, the setParent call was pretty useless.
+ //
+ // The intention for this parenting was that the column descriptor is able to find the data source,
+ // by traveling up the parent hierarchy until there's an XDataSource. This didn't work (which
+ // for instance causes #i65023#). We need another way to properly ensure this.
+
+ notifyDataSourceModified();
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_OComponentDefinition(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new dbaccess::OComponentDefinition(
+ context, nullptr, std::make_shared<dbaccess::OComponentDefinition_Impl>()));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ComponentDefinition.hxx b/dbaccess/source/core/dataaccess/ComponentDefinition.hxx
new file mode 100644
index 000000000..4c10a5354
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ComponentDefinition.hxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <commandbase.hxx>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <rtl/ref.hxx>
+#include <datasettings.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <ContentHelper.hxx>
+#include <apitools.hxx>
+#include <column.hxx>
+
+#include <memory>
+namespace dbaccess
+{
+
+ typedef ::cppu::ImplHelper1< css::sdbcx::XColumnsSupplier > OComponentDefinition_BASE;
+
+ class OComponentDefinition_Impl : public OContentHelper_Impl
+ ,public ODataSettings_Base
+ {
+ public:
+ typedef std::map < OUString
+ , css::uno::Reference< css::beans::XPropertySet >
+ > Columns;
+ typedef Columns::iterator iterator;
+ typedef Columns::const_iterator const_iterator;
+
+ private:
+ Columns m_aColumns;
+
+ public:
+ OUString m_sSchemaName;
+ OUString m_sCatalogName;
+
+ public:
+ OComponentDefinition_Impl();
+ virtual ~OComponentDefinition_Impl() override;
+
+ size_t size() const { return m_aColumns.size(); }
+
+ const_iterator begin() const { return m_aColumns.begin(); }
+ const_iterator end() const { return m_aColumns.end(); }
+
+ const_iterator find( const OUString& _rName ) const { return m_aColumns.find( _rName ); }
+
+ void erase( const OUString& _rName ) { m_aColumns.erase( _rName ); }
+
+ void insert( const OUString& _rName, const css::uno::Reference< css::beans::XPropertySet >& _rxColumn )
+ {
+ OSL_PRECOND( m_aColumns.find( _rName ) == m_aColumns.end(), "OComponentDefinition_Impl::insert: there's already an element with this name!" );
+ m_aColumns.emplace( _rName, _rxColumn );
+ }
+ };
+
+class OColumnPropertyListener;
+// OComponentDefinition - a database "document" which describes a query
+class OComponentDefinition :public OContentHelper
+ ,public ODataSettings
+ ,public IColumnFactory
+ ,public OComponentDefinition_BASE
+ ,public ::comphelper::OPropertyArrayUsageHelper< OComponentDefinition >
+{
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OColumns> m_pColumns;
+ rtl::Reference<OColumnPropertyListener> m_xColumnPropertyListener;
+ bool m_bTable;
+
+protected:
+ virtual ~OComponentDefinition() override;
+ virtual void SAL_CALL disposing() override;
+
+ const OComponentDefinition_Impl& getDefinition() const { return dynamic_cast< const OComponentDefinition_Impl& >( *m_pImpl ); }
+ OComponentDefinition_Impl& getDefinition() { return dynamic_cast< OComponentDefinition_Impl& >( *m_pImpl ); }
+public:
+ OComponentDefinition(
+ const css::uno::Reference< css::uno::XComponentContext >&,
+ const css::uno::Reference< css::uno::XInterface >& _xParentContainer,
+ const TContentPtr& _pImpl,
+ bool _bTable = true);
+
+ OComponentDefinition(
+ const css::uno::Reference< css::uno::XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const css::uno::Reference< css::uno::XComponentContext >&
+ ,const TContentPtr& _pImpl
+ ,bool _bTable = true
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( css::uno::Sequence< css::uno::Any > const & rArguments) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+ using OContentHelper::notifyDataSourceModified;
+
+protected:
+// OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+private:
+ void registerProperties();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ContentHelper.cxx b/dbaccess/source/core/dataaccess/ContentHelper.cxx
new file mode 100644
index 000000000..558dd7450
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ContentHelper.cxx
@@ -0,0 +1,615 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ContentHelper.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <ucbhelper/propertyvalueset.hxx>
+#include <ucbhelper/contentidentifier.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <sdbcoretools.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <map>
+
+namespace dbaccess
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+
+OContentHelper_Impl::OContentHelper_Impl()
+ : m_pDataSource(nullptr)
+{
+}
+
+OContentHelper_Impl::~OContentHelper_Impl()
+{
+}
+
+OContentHelper::OContentHelper(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl)
+ : OContentHelper_COMPBASE(m_aMutex)
+ ,m_aContentListeners(m_aMutex)
+ ,m_aPropertyChangeListeners(m_aMutex)
+ ,m_xParentContainer( _xParentContainer )
+ ,m_aContext( _xORB )
+ ,m_pImpl(_pImpl)
+ ,m_nCommandId(0)
+{
+}
+
+void SAL_CALL OContentHelper::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // say goodbye to our listeners
+ EventObject aEvt(*this);
+ m_aContentListeners.disposeAndClear(aEvt);
+
+ m_xParentContainer = nullptr;
+}
+
+OUString SAL_CALL OContentHelper::getImplementationName()
+ {
+ return "com.sun.star.comp.sdb.Content";
+ }
+sal_Bool SAL_CALL OContentHelper::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OContentHelper::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.Content" };
+}
+
+
+const css::uno::Sequence<sal_Int8> & OContentHelper::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit aId;
+ return aId.getSeq();
+}
+
+css::uno::Sequence<sal_Int8> OContentHelper::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XContent
+Reference< XContentIdentifier > SAL_CALL OContentHelper::getIdentifier( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OUString aIdentifier( "private:" + impl_getHierarchicalName( true ) );
+ return new ::ucbhelper::ContentIdentifier( aIdentifier );
+}
+
+OUString OContentHelper::impl_getHierarchicalName( bool _includingRootContainer ) const
+{
+ OUStringBuffer aHierarchicalName( m_pImpl->m_aProps.aTitle );
+ Reference< XInterface > xParent = m_xParentContainer;
+ while( xParent.is() )
+ {
+ Reference<XPropertySet> xProp( xParent, UNO_QUERY );
+ Reference< XChild > xChild( xParent, UNO_QUERY );
+ xParent.set( xChild.is() ? xChild->getParent() : Reference< XInterface >(), UNO_QUERY );
+ if ( xProp.is() && xParent.is() )
+ {
+ OUString sName;
+ xProp->getPropertyValue( PROPERTY_NAME ) >>= sName;
+
+ OUString sPrevious = aHierarchicalName.makeStringAndClear();
+ aHierarchicalName.append( sName + "/" + sPrevious );
+ }
+ }
+ OUString sHierarchicalName( aHierarchicalName.makeStringAndClear() );
+ if ( !_includingRootContainer )
+ sHierarchicalName = sHierarchicalName.copy( sHierarchicalName.indexOf( '/' ) + 1 );
+ return sHierarchicalName;
+}
+
+OUString SAL_CALL OContentHelper::getContentType()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( !m_pImpl->m_aProps.aContentType )
+ { // content type not yet retrieved
+ m_pImpl->m_aProps.aContentType = determineContentType();
+ }
+
+ return *m_pImpl->m_aProps.aContentType;
+}
+
+void SAL_CALL OContentHelper::addContentEventListener( const Reference< XContentEventListener >& _rxListener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( _rxListener.is() )
+ m_aContentListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL OContentHelper::removeContentEventListener( const Reference< XContentEventListener >& _rxListener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (_rxListener.is())
+ m_aContentListeners.removeInterface(_rxListener);
+}
+
+// XCommandProcessor
+sal_Int32 SAL_CALL OContentHelper::createCommandIdentifier( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ // Just increase counter on every call to generate an identifier.
+ return ++m_nCommandId;
+}
+
+Any SAL_CALL OContentHelper::execute( const Command& aCommand, sal_Int32 /*CommandId*/, const Reference< XCommandEnvironment >& Environment )
+{
+ Any aRet;
+ if ( aCommand.Name == "getPropertyValues" )
+ {
+ // getPropertyValues
+
+ Sequence< Property > Properties;
+ if ( !( aCommand.Argument >>= Properties ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ aRet <<= getPropertyValues( Properties);
+ }
+ else if ( aCommand.Name == "setPropertyValues" )
+ {
+ // setPropertyValues
+
+ Sequence< PropertyValue > aProperties;
+ if ( !( aCommand.Argument >>= aProperties ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+
+ if ( !aProperties.hasElements() )
+ {
+ OSL_FAIL( "No properties!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+
+ aRet <<= setPropertyValues( aProperties );
+ }
+ else if ( aCommand.Name == "getPropertySetInfo" )
+ {
+ // getPropertySetInfo
+
+ Reference<XPropertySet> xProp(*this,UNO_QUERY);
+ if ( xProp.is() )
+ aRet <<= xProp->getPropertySetInfo();
+ // aRet <<= getPropertySetInfo(); // TODO
+ }
+ else
+ {
+ // Unsupported command
+
+ OSL_FAIL( "Content::execute - unsupported command!" );
+
+ ucbhelper::cancelCommandExecution(
+ Any( UnsupportedCommandException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ) ) ),
+ Environment );
+ // Unreachable
+ }
+
+ return aRet;
+}
+
+void SAL_CALL OContentHelper::abort( sal_Int32 /*CommandId*/ )
+{
+}
+
+// XPropertiesChangeNotifier
+void SAL_CALL OContentHelper::addPropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ sal_Int32 nCount = PropertyNames.getLength();
+ if ( !nCount )
+ {
+ // Note: An empty sequence means a listener for "all" properties.
+ m_aPropertyChangeListeners.addInterface(OUString(), Listener );
+ }
+ else
+ {
+ const OUString* pSeq = PropertyNames.getConstArray();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const OUString& rName = pSeq[ n ];
+ if ( !rName.isEmpty() )
+ m_aPropertyChangeListeners.addInterface(rName, Listener );
+ }
+ }
+}
+
+void SAL_CALL OContentHelper::removePropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ sal_Int32 nCount = PropertyNames.getLength();
+ if ( !nCount )
+ {
+ // Note: An empty sequence means a listener for "all" properties.
+ m_aPropertyChangeListeners.removeInterface( OUString(), Listener );
+ }
+ else
+ {
+ const OUString* pSeq = PropertyNames.getConstArray();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const OUString& rName = pSeq[ n ];
+ if ( !rName.isEmpty() )
+ m_aPropertyChangeListeners.removeInterface( rName, Listener );
+ }
+ }
+}
+
+// XPropertyContainer
+void SAL_CALL OContentHelper::addProperty( const OUString& /*Name*/, sal_Int16 /*Attributes*/, const Any& /*DefaultValue*/ )
+{
+ OSL_FAIL( "OContentHelper::addProperty: not implemented!" );
+}
+
+void SAL_CALL OContentHelper::removeProperty( const OUString& /*Name*/ )
+{
+ OSL_FAIL( "OContentHelper::removeProperty: not implemented!" );
+}
+
+// XInitialization
+void SAL_CALL OContentHelper::initialize( const Sequence< Any >& _aArguments )
+{
+ const Any* pBegin = _aArguments.getConstArray();
+ const Any* pEnd = pBegin + _aArguments.getLength();
+ PropertyValue aValue;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ *pBegin >>= aValue;
+ if ( aValue.Name == "Parent" )
+ {
+ m_xParentContainer.set(aValue.Value,UNO_QUERY);
+ }
+ else if ( aValue.Name == PROPERTY_NAME )
+ {
+ aValue.Value >>= m_pImpl->m_aProps.aTitle;
+ }
+ else if ( aValue.Name == PROPERTY_PERSISTENT_NAME )
+ {
+ aValue.Value >>= m_pImpl->m_aProps.sPersistentName;
+ }
+ }
+}
+
+Sequence< Any > OContentHelper::setPropertyValues(const Sequence< PropertyValue >& rValues )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
+
+ Sequence< Any > aRet( rValues.getLength() );
+ auto aRetRange = asNonConstRange(aRet);
+ Sequence< PropertyChangeEvent > aChanges( rValues.getLength() );
+ sal_Int32 nChanged = 0;
+
+ PropertyChangeEvent aEvent;
+ aEvent.Source = static_cast< cppu::OWeakObject * >( this );
+ aEvent.Further = false;
+ aEvent.PropertyHandle = -1;
+
+ const PropertyValue* pValues = rValues.getConstArray();
+ sal_Int32 nCount = rValues.getLength();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const PropertyValue& rValue = pValues[ n ];
+
+ if ( rValue.Name == "ContentType" || rValue.Name == "IsDocument" || rValue.Name == "IsFolder" )
+ {
+ // Read-only property!
+ aRetRange[ n ] <<= IllegalAccessException("Property is read-only!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+ else if ( rValue.Name == "Title" )
+ {
+ OUString aNewValue;
+ if ( rValue.Value >>= aNewValue )
+ {
+ if ( aNewValue != m_pImpl->m_aProps.aTitle )
+ {
+ aEvent.PropertyName = rValue.Name;
+ aEvent.OldValue <<= m_pImpl->m_aProps.aTitle;
+
+ try
+ {
+ impl_rename_throw( aNewValue ,false);
+ OSL_ENSURE( m_pImpl->m_aProps.aTitle == aNewValue, "OContentHelper::setPropertyValues('Title'): rename did not work!" );
+
+ aEvent.NewValue <<= aNewValue;
+ aChanges.getArray()[ nChanged ] = aEvent;
+ nChanged++;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "OContentHelper::setPropertyValues('Title'): caught an exception while renaming!" );
+ }
+ }
+ else
+ {
+ // Old value equals new value. No error!
+ }
+ }
+ else
+ {
+ aRetRange[ n ] <<= IllegalTypeException("Property value has wrong type!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+ }
+
+ else
+ {
+ aRetRange[ n ] <<= Exception("No property set for storing the value!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+ }
+
+ if ( nChanged > 0 )
+ {
+ notifyDataSourceModified();
+ aGuard.clear();
+ aChanges.realloc( nChanged );
+ notifyPropertiesChange( aChanges );
+ }
+
+ return aRet;
+}
+
+// static
+Reference< XRow > OContentHelper::getPropertyValues( const Sequence< Property >& rProperties)
+{
+ // Note: Empty sequence means "get values of all supported properties".
+
+ rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_aContext );
+
+ sal_Int32 nCount = rProperties.getLength();
+ if ( nCount )
+ {
+ const Property* pProps = rProperties.getConstArray();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const Property& rProp = pProps[ n ];
+
+ // Process Core properties.
+
+ if ( rProp.Name == "ContentType" )
+ {
+ xRow->appendString ( rProp, getContentType() );
+ }
+ else if ( rProp.Name == "Title" )
+ {
+ xRow->appendString ( rProp, m_pImpl->m_aProps.aTitle );
+ }
+ else if ( rProp.Name == "IsDocument" )
+ {
+ xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsDocument );
+ }
+ else if ( rProp.Name == "IsFolder" )
+ {
+ xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsFolder );
+ }
+ else
+ xRow->appendVoid(rProp);
+ }
+ }
+ else
+ {
+ // Append all Core Properties.
+ xRow->appendString (
+ Property( "ContentType", -1,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::BOUND
+ | PropertyAttribute::READONLY ),
+ getContentType() );
+ xRow->appendString (
+ Property( "Title", -1,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::BOUND ),
+ m_pImpl->m_aProps.aTitle );
+ xRow->appendBoolean(
+ Property( "IsDocument", -1,
+ cppu::UnoType<bool>::get(),
+ PropertyAttribute::BOUND
+ | PropertyAttribute::READONLY ),
+ m_pImpl->m_aProps.bIsDocument );
+ xRow->appendBoolean(
+ Property( "IsFolder", -1,
+ cppu::UnoType<bool>::get(),
+ PropertyAttribute::BOUND
+ | PropertyAttribute::READONLY ),
+ m_pImpl->m_aProps.bIsFolder );
+
+ // @@@ Append other properties supported directly.
+ }
+
+ return xRow;
+}
+
+void OContentHelper::notifyPropertiesChange( const Sequence< PropertyChangeEvent >& evt ) const
+{
+
+ sal_Int32 nCount = evt.getLength();
+ if ( !nCount )
+ return;
+
+ // First, notify listeners interested in changes of every property.
+ comphelper::OInterfaceContainerHelper3<XPropertiesChangeListener>* pAllPropsContainer = m_aPropertyChangeListeners.getContainer( OUString() );
+ if ( pAllPropsContainer )
+ pAllPropsContainer->notifyEach( &XPropertiesChangeListener::propertiesChange, evt );
+
+ typedef std::map< XPropertiesChangeListener*, Sequence< PropertyChangeEvent > > PropertiesEventListenerMap;
+ PropertiesEventListenerMap aListeners;
+
+ const PropertyChangeEvent* propertyChangeEvent = evt.getConstArray();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n, ++propertyChangeEvent )
+ {
+ const PropertyChangeEvent& rEvent = *propertyChangeEvent;
+ const OUString& rName = rEvent.PropertyName;
+
+ comphelper::OInterfaceContainerHelper3<XPropertiesChangeListener>* pPropsContainer = m_aPropertyChangeListeners.getContainer( rName );
+ if ( pPropsContainer )
+ {
+ comphelper::OInterfaceIteratorHelper3 aIter( *pPropsContainer );
+ while ( aIter.hasMoreElements() )
+ {
+ Sequence< PropertyChangeEvent >* propertyEvents;
+
+ XPropertiesChangeListener* pListener = aIter.next().get();
+ PropertiesEventListenerMap::iterator it = aListeners.find( pListener );
+ if ( it == aListeners.end() )
+ {
+ // Not in map - create and insert new entry.
+ auto pair = aListeners.emplace( pListener, Sequence< PropertyChangeEvent >( nCount ));
+ propertyEvents = &pair.first->second;
+ }
+ else
+ propertyEvents = &(*it).second;
+
+ propertyEvents->getArray()[n] = rEvent;
+ }
+ }
+ }
+
+ // Notify listeners.
+ for (auto & rPair : aListeners)
+ {
+ XPropertiesChangeListener* pListener = rPair.first;
+ Sequence< PropertyChangeEvent >& rSeq = rPair.second;
+
+ // Propagate event.
+ pListener->propertiesChange( rSeq );
+ }
+}
+
+// css::lang::XUnoTunnel
+sal_Int64 OContentHelper::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+Reference< XInterface > SAL_CALL OContentHelper::getParent( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return m_xParentContainer;
+}
+
+void SAL_CALL OContentHelper::setParent( const Reference< XInterface >& _xParent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xParentContainer = _xParent;
+}
+
+void OContentHelper::impl_rename_throw(const OUString& _sNewName,bool _bNotify )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ if ( _sNewName == m_pImpl->m_aProps.aTitle )
+ return;
+ try
+ {
+ Sequence<PropertyChangeEvent> aChanges{
+ { /* Source */ static_cast<cppu::OWeakObject*>(this),
+ /* PropertyName */ PROPERTY_NAME,
+ /* Further */ false,
+ /* PropertyHandle */ PROPERTY_ID_NAME,
+ /* OldValue */ Any(m_pImpl->m_aProps.aTitle),
+ /* NewValue */ Any(_sNewName) }
+ };
+
+ aGuard.clear();
+
+ m_pImpl->m_aProps.aTitle = _sNewName;
+ if ( _bNotify )
+ notifyPropertiesChange( aChanges );
+ notifyDataSourceModified();
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(_sNewName,*this);
+ }
+}
+
+void SAL_CALL OContentHelper::rename( const OUString& newName )
+{
+
+ impl_rename_throw(newName);
+
+}
+
+void OContentHelper::notifyDataSourceModified()
+{
+ ::dbaccess::notifyDataSourceModified(m_xParentContainer);
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ModelImpl.cxx b/dbaccess/source/core/dataaccess/ModelImpl.cxx
new file mode 100644
index 000000000..5a4078fcc
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ModelImpl.cxx
@@ -0,0 +1,1432 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <databasecontext.hxx>
+#include "databasedocument.hxx"
+#include "datasource.hxx"
+#include <definitioncontainer.hxx>
+#include <ModelImpl.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyBag.hpp>
+#include <com/sun/star/container/XSet.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/XTransactionBroadcaster.hpp>
+#include <com/sun/star/embed/StorageFactory.hpp>
+#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
+#include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
+#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
+#include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/signaturestate.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/file.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/tempfile.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <algorithm>
+
+using namespace css;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::script;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::comphelper;
+
+namespace dbaccess
+{
+
+// DocumentStorageAccess
+class DocumentStorageAccess : public ::cppu::WeakImplHelper< XDocumentSubStorageSupplier
+ , XTransactionListener >
+{
+ typedef std::map< OUString, Reference< XStorage > > NamedStorages;
+
+ ::osl::Mutex m_aMutex;
+ /// all sub storages which we ever gave to the outer world
+ NamedStorages m_aExposedStorages;
+ ODatabaseModelImpl* m_pModelImplementation;
+ bool m_bPropagateCommitToRoot;
+ bool m_bDisposingSubStorages;
+
+public:
+ explicit DocumentStorageAccess( ODatabaseModelImpl& _rModelImplementation )
+ :m_pModelImplementation( &_rModelImplementation )
+ ,m_bPropagateCommitToRoot( true )
+ ,m_bDisposingSubStorages( false )
+ {
+ }
+
+protected:
+ virtual ~DocumentStorageAccess() override
+ {
+ }
+
+public:
+ void dispose();
+
+ // XDocumentSubStorageSupplier
+ virtual Reference< XStorage > SAL_CALL getDocumentSubStorage( const OUString& aStorageName, ::sal_Int32 _nMode ) override;
+ virtual Sequence< OUString > SAL_CALL getDocumentSubStoragesNames( ) override;
+
+ // XTransactionListener
+ virtual void SAL_CALL preCommit( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL commited( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL preRevert( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL reverted( const css::lang::EventObject& aEvent ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ /// disposes all storages managed by this instance
+ void disposeStorages();
+
+ /// disposes all known sub storages
+ void commitStorages();
+
+ /// commits the dedicated "database" storage
+ bool commitEmbeddedStorage( bool _bPreventRootCommits );
+
+private:
+ /** opens the sub storage with the given name, in the given mode
+ */
+ Reference< XStorage > impl_openSubStorage_nothrow( const OUString& _rStorageName, sal_Int32 _nMode );
+
+ void impl_suspendCommitPropagation()
+ {
+ OSL_ENSURE( m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_suspendCommitPropagation: already suspended" );
+ m_bPropagateCommitToRoot = false;
+ }
+ void impl_resumeCommitPropagation()
+ {
+ OSL_ENSURE( !m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_resumeCommitPropagation: not suspended" );
+ m_bPropagateCommitToRoot = true;
+ }
+
+};
+
+void DocumentStorageAccess::dispose()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ for (auto const& exposedStorage : m_aExposedStorages)
+ {
+ try
+ {
+ Reference< XTransactionBroadcaster > xBroadcaster(exposedStorage.second, UNO_QUERY);
+ if ( xBroadcaster.is() )
+ xBroadcaster->removeTransactionListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ m_aExposedStorages.clear();
+
+ m_pModelImplementation = nullptr;
+}
+
+Reference< XStorage > DocumentStorageAccess::impl_openSubStorage_nothrow( const OUString& _rStorageName, sal_Int32 _nDesiredMode )
+{
+ OSL_ENSURE( !_rStorageName.isEmpty(),"ODatabaseModelImpl::impl_openSubStorage_nothrow: Invalid storage name!" );
+
+ Reference< XStorage > xStorage;
+ try
+ {
+ Reference< XStorage > xRootStorage( m_pModelImplementation->getOrCreateRootStorage() );
+ if ( xRootStorage.is() )
+ {
+ sal_Int32 nRealMode = m_pModelImplementation->m_bDocumentReadOnly ? ElementModes::READ : _nDesiredMode;
+ if ( nRealMode == ElementModes::READ )
+ {
+ if ( xRootStorage.is() && !xRootStorage->hasByName( _rStorageName ) )
+ return xStorage;
+ }
+
+ xStorage = xRootStorage->openStorageElement( _rStorageName, nRealMode );
+
+ Reference< XTransactionBroadcaster > xBroad( xStorage, UNO_QUERY );
+ if ( xBroad.is() )
+ xBroad->addTransactionListener( this );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return xStorage;
+}
+
+void DocumentStorageAccess::disposeStorages()
+{
+ m_bDisposingSubStorages = true;
+
+ for (auto & exposedStorage : m_aExposedStorages)
+ {
+ try
+ {
+ ::comphelper::disposeComponent( exposedStorage.second );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ m_aExposedStorages.clear();
+
+ m_bDisposingSubStorages = false;
+}
+
+void DocumentStorageAccess::commitStorages()
+{
+ try
+ {
+ for (auto const& exposedStorage : m_aExposedStorages)
+ {
+ tools::stor::commitStorageIfWriteable( exposedStorage.second );
+ }
+ }
+ catch(const WrappedTargetException&)
+ {
+ // WrappedTargetException not allowed to leave
+ throw IOException();
+ }
+}
+
+bool DocumentStorageAccess::commitEmbeddedStorage( bool _bPreventRootCommits )
+{
+ if ( _bPreventRootCommits )
+ impl_suspendCommitPropagation();
+
+ bool bSuccess = false;
+ try
+ {
+ NamedStorages::const_iterator pos = m_aExposedStorages.find( "database" );
+ if ( pos != m_aExposedStorages.end() )
+ bSuccess = tools::stor::commitStorageIfWriteable( pos->second );
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( _bPreventRootCommits )
+ impl_resumeCommitPropagation();
+
+ return bSuccess;
+
+}
+
+Reference< XStorage > SAL_CALL DocumentStorageAccess::getDocumentSubStorage( const OUString& aStorageName, ::sal_Int32 _nDesiredMode )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ NamedStorages::const_iterator pos = m_aExposedStorages.find( aStorageName );
+ if ( pos == m_aExposedStorages.end() )
+ {
+ Reference< XStorage > xResult = impl_openSubStorage_nothrow( aStorageName, _nDesiredMode );
+ pos = m_aExposedStorages.emplace( aStorageName, xResult ).first;
+ }
+
+ return pos->second;
+}
+
+Sequence< OUString > SAL_CALL DocumentStorageAccess::getDocumentSubStoragesNames( )
+{
+ Reference< XStorage > xRootStor( m_pModelImplementation->getRootStorage() );
+ if ( !xRootStor.is() )
+ return Sequence< OUString >();
+
+ std::vector< OUString > aNames;
+
+ const Sequence< OUString > aElementNames( xRootStor->getElementNames() );
+ for ( OUString const & name : aElementNames )
+ {
+ if ( xRootStor->isStorageElement( name ) )
+ aNames.push_back( name );
+ }
+ return aNames.empty()
+ ? Sequence< OUString >()
+ : Sequence< OUString >( aNames.data(), aNames.size() );
+}
+
+void SAL_CALL DocumentStorageAccess::preCommit( const css::lang::EventObject& /*aEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL DocumentStorageAccess::commited( const css::lang::EventObject& aEvent )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pModelImplementation )
+ m_pModelImplementation->setModified( true );
+
+ if ( !(m_pModelImplementation && m_bPropagateCommitToRoot) )
+ return;
+
+ Reference< XStorage > xStorage( aEvent.Source, UNO_QUERY );
+
+ // check if this is the dedicated "database" sub storage
+ NamedStorages::const_iterator pos = m_aExposedStorages.find( "database" );
+ if ( ( pos != m_aExposedStorages.end() )
+ && ( pos->second == xStorage )
+ )
+ {
+ // if so, also commit the root storage
+ m_pModelImplementation->commitRootStorage();
+ }
+}
+
+void SAL_CALL DocumentStorageAccess::preRevert( const css::lang::EventObject& /*aEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL DocumentStorageAccess::reverted( const css::lang::EventObject& /*aEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL DocumentStorageAccess::disposing( const css::lang::EventObject& Source )
+{
+ OSL_ENSURE( Reference< XStorage >( Source.Source, UNO_QUERY ).is(), "DocumentStorageAccess::disposing: No storage? What's this?" );
+
+ if ( m_bDisposingSubStorages )
+ return;
+
+ auto find = std::find_if(m_aExposedStorages.begin(), m_aExposedStorages.end(),
+ [&Source](const NamedStorages::value_type& rEntry) { return rEntry.second == Source.Source; });
+ if (find != m_aExposedStorages.end())
+ m_aExposedStorages.erase( find );
+}
+
+// ODatabaseModelImpl
+
+ODatabaseModelImpl::ODatabaseModelImpl( const Reference< XComponentContext >& _rxContext, ODatabaseContext& _rDBContext )
+ :m_aContainer(4)
+ ,m_aMacroMode( *this )
+ ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE )
+ ,m_rDBContext( _rDBContext )
+ ,m_refCount(0)
+ ,m_bModificationLock( false )
+ ,m_bDocumentInitialized( false )
+ ,m_nScriptingSignatureState(SignatureState::UNKNOWN)
+ ,m_aContext( _rxContext )
+ ,m_nLoginTimeout(0)
+ ,m_bReadOnly(false)
+ ,m_bPasswordRequired(false)
+ ,m_bSuppressVersionColumns(true)
+ ,m_bModified(false)
+ ,m_bDocumentReadOnly(false)
+ ,m_bMacroCallsSeenWhileLoading(false)
+ ,m_pSharedConnectionManager(nullptr)
+ ,m_nControllerLockCount(0)
+{
+ // some kind of default
+ m_sConnectURL = "jdbc:";
+ m_aTableFilter = { "%" };
+ impl_construct_nothrow();
+}
+
+ODatabaseModelImpl::ODatabaseModelImpl(
+ const OUString& _rRegistrationName,
+ const Reference< XComponentContext >& _rxContext,
+ ODatabaseContext& _rDBContext
+ )
+ :m_aContainer(4)
+ ,m_aMacroMode( *this )
+ ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE )
+ ,m_rDBContext( _rDBContext )
+ ,m_refCount(0)
+ ,m_bModificationLock( false )
+ ,m_bDocumentInitialized( false )
+ ,m_nScriptingSignatureState(SignatureState::UNKNOWN)
+ ,m_aContext( _rxContext )
+ ,m_sName(_rRegistrationName)
+ ,m_nLoginTimeout(0)
+ ,m_bReadOnly(false)
+ ,m_bPasswordRequired(false)
+ ,m_bSuppressVersionColumns(true)
+ ,m_bModified(false)
+ ,m_bDocumentReadOnly(false)
+ ,m_bMacroCallsSeenWhileLoading(false)
+ ,m_pSharedConnectionManager(nullptr)
+ ,m_nControllerLockCount(0)
+{
+ impl_construct_nothrow();
+}
+
+ODatabaseModelImpl::~ODatabaseModelImpl()
+{
+}
+
+void ODatabaseModelImpl::impl_construct_nothrow()
+{
+ // create the property bag to hold the settings (also known as "Info" property)
+ try
+ {
+ // the set of property value types in the bag is limited:
+ Sequence< Type > aAllowedTypes({
+ cppu::UnoType<sal_Bool>::get(),
+ cppu::UnoType<double>::get(),
+ cppu::UnoType<OUString>::get(),
+ cppu::UnoType<sal_Int32>::get(),
+ cppu::UnoType<sal_Int16>::get(),
+ cppu::UnoType<Sequence< Any >>::get(),
+ });
+
+ m_xSettings = PropertyBag::createWithTypes( m_aContext, aAllowedTypes, false/*AllowEmptyPropertyName*/, true/*AutomaticAddition*/ );
+
+ // insert the default settings
+ Reference< XPropertyContainer > xContainer( m_xSettings, UNO_QUERY_THROW );
+ Reference< XSet > xSettingsSet( m_xSettings, UNO_QUERY_THROW );
+ const AsciiPropertyValue* pSettings = getDefaultDataSourceSettings();
+ for ( ; pSettings->AsciiName; ++pSettings )
+ {
+ if ( !pSettings->DefaultValue.hasValue() )
+ {
+ Property aProperty(
+ OUString::createFromAscii( pSettings->AsciiName ),
+ -1,
+ pSettings->ValueType,
+ PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT | PropertyAttribute::MAYBEVOID
+ );
+ xSettingsSet->insert( Any( aProperty ) );
+ }
+ else
+ {
+ xContainer->addProperty(
+ OUString::createFromAscii( pSettings->AsciiName ),
+ PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ pSettings->DefaultValue
+ );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_rDBContext.appendAtTerminateListener(*this);
+}
+
+namespace
+{
+ OUString lcl_getContainerStorageName_throw( ODatabaseModelImpl::ObjectType _eType )
+ {
+ const char* pAsciiName( nullptr );
+ switch ( _eType )
+ {
+ case ODatabaseModelImpl::E_FORM: pAsciiName = "forms"; break;
+ case ODatabaseModelImpl::E_REPORT: pAsciiName = "reports"; break;
+ case ODatabaseModelImpl::E_QUERY: pAsciiName = "queries"; break;
+ case ODatabaseModelImpl::E_TABLE: pAsciiName = "tables"; break;
+ default:
+ throw RuntimeException();
+ }
+ return OUString::createFromAscii( pAsciiName );
+ }
+
+ bool lcl_hasObjectWithMacros_throw( const ODefinitionContainer_Impl& _rObjectDefinitions, const Reference< XStorage >& _rxContainerStorage )
+ {
+ bool bSomeDocHasMacros = false;
+
+ for (auto const& objectDefinition : _rObjectDefinitions)
+ {
+ const TContentPtr& rDefinition( objectDefinition.second );
+ const OUString& rPersistentName( rDefinition->m_aProps.sPersistentName );
+
+ if ( rPersistentName.isEmpty() )
+ { // it's a logical sub folder used to organize the real objects
+ const ODefinitionContainer_Impl& rSubFoldersObjectDefinitions( dynamic_cast< const ODefinitionContainer_Impl& >( *rDefinition ) );
+ bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rSubFoldersObjectDefinitions, _rxContainerStorage );
+ if (bSomeDocHasMacros)
+ break;
+ continue;
+ }
+
+ bSomeDocHasMacros = ODatabaseModelImpl::objectHasMacros( _rxContainerStorage, rPersistentName );
+ if (bSomeDocHasMacros)
+ break;
+ }
+ return bSomeDocHasMacros;
+ }
+
+ bool lcl_hasObjectsWithMacros_nothrow( ODatabaseModelImpl& _rModel, const ODatabaseModelImpl::ObjectType _eType )
+ {
+ bool bSomeDocHasMacros = false;
+
+ const OContentHelper_Impl& rContainerData( *_rModel.getObjectContainer( _eType ) );
+ const ODefinitionContainer_Impl& rObjectDefinitions = dynamic_cast< const ODefinitionContainer_Impl& >( rContainerData );
+
+ try
+ {
+ Reference< XStorage > xContainerStorage( _rModel.getStorage( _eType ) );
+ // note the READWRITE here: If the storage already existed before, then the OpenMode will
+ // be ignored, anyway.
+ // If the storage did not yet exist, then it will be created. If the database document
+ // is read-only, the OpenMode will be automatically downgraded to READ. Otherwise,
+ // the storage will in fact be created as READWRITE. While this is not strictly necessary
+ // for this particular use case here, it is required since the storage is *cached*, and
+ // later use cases will need the READWRITE mode.
+
+ if ( xContainerStorage.is() )
+ bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rObjectDefinitions, xContainerStorage );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ // be on the safe side: If we can't reliably determine whether there are macros,
+ // assume there actually are. Better this way, than the other way round.
+ bSomeDocHasMacros = true;
+ }
+
+ return bSomeDocHasMacros;
+ }
+}
+
+bool ODatabaseModelImpl::objectHasMacros( const Reference< XStorage >& _rxContainerStorage, const OUString& _rPersistentName )
+{
+ OSL_PRECOND( _rxContainerStorage.is(), "ODatabaseModelImpl::objectHasMacros: this will crash!" );
+
+ bool bHasMacros = true;
+ try
+ {
+ if ( !_rxContainerStorage->hasByName( _rPersistentName ) )
+ return false;
+
+ Reference< XStorage > xObjectStor( _rxContainerStorage->openStorageElement(
+ _rPersistentName, ElementModes::READ ) );
+
+ bHasMacros = ::sfx2::DocumentMacroMode::storageHasMacros( xObjectStor );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bHasMacros;
+}
+
+void ODatabaseModelImpl::reset()
+{
+ m_bReadOnly = false;
+ std::vector<TContentPtr>(4).swap(m_aContainer);
+
+ if ( m_pStorageAccess.is() )
+ {
+ m_pStorageAccess->dispose();
+ m_pStorageAccess.clear();
+ }
+}
+
+void ODatabaseModelImpl::disposing( const css::lang::EventObject& Source )
+{
+ Reference<XConnection> xCon(Source.Source,UNO_QUERY);
+ if ( xCon.is() )
+ {
+ bool bStore = false;
+ for (OWeakConnectionArray::iterator i = m_aConnections.begin(); i != m_aConnections.end(); )
+ {
+ css::uno::Reference< css::sdbc::XConnection > xIterConn ( *i );
+ if ( !xIterConn.is())
+ {
+ i = m_aConnections.erase(i);
+ }
+ else if ( xCon == xIterConn )
+ {
+ *i = css::uno::WeakReference< css::sdbc::XConnection >();
+ bStore = true;
+ break;
+ } else
+ ++i;
+ }
+
+ if ( bStore )
+ commitRootStorage();
+ }
+ else
+ {
+ OSL_FAIL( "ODatabaseModelImpl::disposing: where does this come from?" );
+ }
+}
+
+void ODatabaseModelImpl::clearConnections()
+{
+ OWeakConnectionArray aConnections;
+ aConnections.swap( m_aConnections );
+
+ Reference< XConnection > xConn;
+ for (auto const& connection : aConnections)
+ {
+ xConn = connection;
+ if ( xConn.is() )
+ {
+ try
+ {
+ xConn->close();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ m_pSharedConnectionManager = nullptr;
+ m_xSharedConnectionManager = nullptr;
+}
+
+void ODatabaseModelImpl::dispose()
+{
+ // dispose the data source and the model
+ try
+ {
+ Reference< XDataSource > xDS( m_xDataSource );
+ ::comphelper::disposeComponent( xDS );
+
+ Reference< XModel > xModel( m_xModel );
+ ::comphelper::disposeComponent( xModel );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xDataSource = WeakReference<XDataSource>();
+ m_xModel = WeakReference< XModel >();
+
+ for (auto const& elem : m_aContainer)
+ {
+ if ( elem )
+ elem->m_pDataSource = nullptr;
+ }
+ m_aContainer.clear();
+
+ clearConnections();
+
+ m_xNumberFormatsSupplier = nullptr;
+
+ try
+ {
+ bool bCouldStore = commitEmbeddedStorage( true );
+ // "true" means that committing the embedded storage should not trigger committing the root
+ // storage. This is because we are going to commit the root storage ourself, anyway
+ disposeStorages();
+ if ( bCouldStore )
+ commitRootStorage();
+
+ impl_switchToStorage_throw( nullptr );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( m_pStorageAccess.is() )
+ {
+ m_pStorageAccess->dispose();
+ m_pStorageAccess.clear();
+ }
+}
+
+const Reference< XNumberFormatsSupplier > & ODatabaseModelImpl::getNumberFormatsSupplier()
+{
+ if (!m_xNumberFormatsSupplier.is())
+ {
+ // the arguments : the work locale of the current user
+ Locale aLocale( LanguageTag::convertToLocale( utl::ConfigManager::getWorkLocale(), false));
+
+ m_xNumberFormatsSupplier.set( NumberFormatsSupplier::createWithLocale( m_aContext, aLocale ) );
+ }
+ return m_xNumberFormatsSupplier;
+}
+
+void ODatabaseModelImpl::setDocFileLocation( const OUString& i_rLoadedFrom )
+{
+ ENSURE_OR_THROW( !i_rLoadedFrom.isEmpty(), "invalid URL" );
+ m_sDocFileLocation = i_rLoadedFrom;
+}
+
+void ODatabaseModelImpl::setResource( const OUString& i_rDocumentURL, const Sequence< PropertyValue >& _rArgs )
+{
+ ENSURE_OR_THROW( !i_rDocumentURL.isEmpty(), "invalid URL" );
+
+ ::comphelper::NamedValueCollection aMediaDescriptor( _rArgs );
+#if OSL_DEBUG_LEVEL > 0
+ if ( aMediaDescriptor.has( "SalvagedFile" ) )
+ {
+ OUString sSalvagedFile( aMediaDescriptor.getOrDefault( "SalvagedFile", OUString() ) );
+ // If SalvagedFile is an empty string, this indicates "the document is being recovered, but i_rDocumentURL already
+ // is the real document URL, not the temporary document location"
+ if ( sSalvagedFile.isEmpty() )
+ sSalvagedFile = i_rDocumentURL;
+
+ OSL_ENSURE( sSalvagedFile == i_rDocumentURL, "ODatabaseModelImpl::setResource: inconsistency!" );
+ // nowadays, setResource should only be called with the logical URL of the document
+ }
+#endif
+
+ m_aMediaDescriptor = stripLoadArguments( aMediaDescriptor );
+
+ impl_switchToLogicalURL( i_rDocumentURL );
+}
+
+::comphelper::NamedValueCollection ODatabaseModelImpl::stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments )
+{
+ OSL_ENSURE( !_rArguments.has( "Model" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (1)!" );
+ OSL_ENSURE( !_rArguments.has( "ViewName" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (2)!" );
+
+ ::comphelper::NamedValueCollection aMutableArgs( _rArguments );
+ aMutableArgs.remove( "Model" );
+ aMutableArgs.remove( "ViewName" );
+ return aMutableArgs;
+}
+
+void ODatabaseModelImpl::disposeStorages()
+{
+ getDocumentStorageAccess()->disposeStorages();
+}
+
+Reference< XSingleServiceFactory > ODatabaseModelImpl::createStorageFactory() const
+{
+ return StorageFactory::create( m_aContext );
+}
+
+void ODatabaseModelImpl::commitRootStorage()
+{
+ Reference< XStorage > xStorage( getOrCreateRootStorage() );
+ bool bSuccess = commitStorageIfWriteable_ignoreErrors( xStorage );
+ SAL_WARN_IF(!bSuccess && xStorage.is(), "dbaccess",
+ "ODatabaseModelImpl::commitRootStorage: could not commit the storage!");
+}
+
+Reference< XStorage > const & ODatabaseModelImpl::getOrCreateRootStorage()
+{
+ if ( !m_xDocumentStorage.is() )
+ {
+ Reference< XSingleServiceFactory> xStorageFactory = StorageFactory::create( m_aContext );
+ Any aSource = m_aMediaDescriptor.get( "Stream" );
+ if ( !aSource.hasValue() )
+ aSource = m_aMediaDescriptor.get( "InputStream" );
+ if ( !aSource.hasValue() && !m_sDocFileLocation.isEmpty() )
+ aSource <<= m_sDocFileLocation;
+ // TODO: shouldn't we also check URL?
+
+ OSL_ENSURE( aSource.hasValue(), "ODatabaseModelImpl::getOrCreateRootStorage: no source to create the storage from!" );
+
+ if ( aSource.hasValue() )
+ {
+ Sequence< Any > aStorageCreationArgs{ aSource, Any(ElementModes::READWRITE) };
+
+ Reference< XStorage > xDocumentStorage;
+ OUString sURL;
+ aSource >>= sURL;
+ // Don't try to load a meta-URL as-is.
+ if (!sURL.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:"))
+ {
+ try
+ {
+ xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ m_bDocumentReadOnly = true;
+ aStorageCreationArgs.getArray()[1] <<= ElementModes::READ;
+ try
+ {
+ xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ impl_switchToStorage_throw( xDocumentStorage );
+ }
+ }
+ return m_xDocumentStorage.getTyped();
+}
+
+DocumentStorageAccess* ODatabaseModelImpl::getDocumentStorageAccess()
+{
+ if ( !m_pStorageAccess.is() )
+ {
+ m_pStorageAccess = new DocumentStorageAccess( *this );
+ }
+ return m_pStorageAccess.get();
+}
+
+void ODatabaseModelImpl::modelIsDisposing( const bool _wasInitialized, ResetModelAccess )
+{
+ m_xModel.clear();
+
+ // Basic libraries and Dialog libraries are a model facet, though held at this impl class.
+ // They automatically dispose themself when the model they belong to is being disposed.
+ // So, to not be tempted to do anything with them, again, we reset them.
+ m_xBasicLibraries.clear();
+ m_xDialogLibraries.clear();
+
+ m_bDocumentInitialized = _wasInitialized;
+}
+
+Reference< XDocumentSubStorageSupplier > ODatabaseModelImpl::getDocumentSubStorageSupplier()
+{
+ return getDocumentStorageAccess();
+}
+
+bool ODatabaseModelImpl::commitEmbeddedStorage( bool _bPreventRootCommits )
+{
+ return getDocumentStorageAccess()->commitEmbeddedStorage( _bPreventRootCommits );
+}
+
+bool ODatabaseModelImpl::commitStorageIfWriteable_ignoreErrors( const Reference< XStorage >& _rxStorage )
+{
+ bool bTryToPreserveScriptSignature = false;
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ OUString sTmpFileUrl = aTempFile.GetURL();
+ SignatureState aSignatureState = getScriptingSignatureState();
+ OUString sLocation = getDocFileLocation();
+ bool bIsEmbedded = sLocation.startsWith("vnd.sun.star.pkg:") && sLocation.endsWith("/EmbeddedDatabase");
+ if (!bIsEmbedded && !sLocation.isEmpty()
+ && (aSignatureState == SignatureState::OK || aSignatureState == SignatureState::NOTVALIDATED
+ || aSignatureState == SignatureState::INVALID
+ || aSignatureState == SignatureState::UNKNOWN))
+ {
+ bTryToPreserveScriptSignature = true;
+ // We need to first save the file (which removes the macro signature), then add the macro signature again.
+ // For that, we need a temporary copy of the original file.
+ osl::File::RC rc = osl::File::copy(sLocation, sTmpFileUrl);
+ if (rc != osl::FileBase::E_None)
+ throw uno::RuntimeException("Could not create temp file");
+ }
+
+ bool bSuccess = false;
+ try
+ {
+ bSuccess = tools::stor::commitStorageIfWriteable( _rxStorage );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // Preserve script signature if the script has not changed
+ if (bTryToPreserveScriptSignature)
+ {
+ OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(_rxStorage));
+ uno::Reference<security::XDocumentDigitalSignatures> xDDSigns;
+ try
+ {
+ xDDSigns = security::DocumentDigitalSignatures::createWithVersion(
+ comphelper::getProcessComponentContext(), aODFVersion);
+
+ const OUString aScriptSignName
+ = xDDSigns->getScriptingContentSignatureDefaultStreamName();
+
+ if (!aScriptSignName.isEmpty())
+ {
+ Reference<XStorage> xReadOrig
+ = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
+ ZIP_STORAGE_FORMAT_STRING, sTmpFileUrl, ElementModes::READ);
+ if (!xReadOrig.is())
+ throw uno::RuntimeException("Could not read " + sTmpFileUrl);
+ uno::Reference<embed::XStorage> xMetaInf
+ = xReadOrig->openStorageElement("META-INF", embed::ElementModes::READ);
+
+ uno::Reference<embed::XStorage> xTargetMetaInf
+ = _rxStorage->openStorageElement("META-INF", embed::ElementModes::READWRITE);
+ if (xMetaInf.is() && xTargetMetaInf.is() && xMetaInf->hasByName(aScriptSignName))
+ {
+ xMetaInf->copyElementTo(aScriptSignName, xTargetMetaInf, aScriptSignName);
+
+ uno::Reference<embed::XTransactedObject> xTransact(xTargetMetaInf,
+ uno::UNO_QUERY);
+ if (xTransact.is())
+ xTransact->commit();
+
+ xTargetMetaInf->dispose();
+
+ // now check the copied signature
+ uno::Sequence<security::DocumentSignatureInformation> aInfos
+ = xDDSigns->verifyScriptingContentSignatures(
+ _rxStorage, uno::Reference<io::XInputStream>());
+ SignatureState nState = DocumentSignatures::getSignatureState(aInfos);
+ if (nState == SignatureState::OK || nState == SignatureState::NOTVALIDATED
+ || nState == SignatureState::PARTIAL_OK)
+ {
+ // commit the ZipStorage from target medium
+ xTransact.set(_rxStorage, uno::UNO_QUERY);
+ if (xTransact.is())
+ xTransact->commit();
+ }
+ else
+ {
+ SAL_WARN("dbaccess", "An invalid signature was copied!");
+ }
+ }
+ }
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "");
+ }
+ }
+
+ return bSuccess;
+}
+
+void ODatabaseModelImpl::setModified( bool _bModified )
+{
+ if ( isModifyLocked() )
+ return;
+
+ try
+ {
+ Reference< XModifiable > xModi( m_xModel.get(), UNO_QUERY );
+ if ( xModi.is() )
+ xModi->setModified( _bModified );
+ else
+ m_bModified = _bModified;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference<XDataSource> ODatabaseModelImpl::getOrCreateDataSource()
+{
+ Reference<XDataSource> xDs = m_xDataSource;
+ if ( !xDs.is() )
+ {
+ xDs = new ODatabaseSource(this);
+ m_xDataSource = xDs;
+ }
+ return xDs;
+}
+
+Reference< XModel> ODatabaseModelImpl::getModel_noCreate() const
+{
+ return m_xModel;
+}
+
+Reference< XModel > ODatabaseModelImpl::createNewModel_deliverOwnership()
+{
+ Reference< XModel > xModel( m_xModel );
+ OSL_PRECOND( !xModel.is(), "ODatabaseModelImpl::createNewModel_deliverOwnership: not to be called if there already is a model!" );
+ if ( !xModel.is() )
+ {
+ bool bHadModelBefore = m_bDocumentInitialized;
+
+ xModel = ODatabaseDocument::createDatabaseDocument( this, ODatabaseDocument::FactoryAccess() );
+ m_xModel = xModel;
+
+ try
+ {
+ Reference< XGlobalEventBroadcaster > xModelCollection = theGlobalEventBroadcaster::get( m_aContext );
+ xModelCollection->insert( Any( xModel ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( bHadModelBefore )
+ {
+ // do an attachResources
+ // In case the document is loaded regularly, this is not necessary, as our loader will do it.
+ // However, in case that the document is implicitly created by asking the data source for the document,
+ // then nobody would call the doc's attachResource. So, we do it here, to ensure it's in a proper
+ // state, fires all events, and so on.
+ // #i105505#
+ xModel->attachResource( xModel->getURL(), m_aMediaDescriptor.getPropertyValues() );
+ }
+ }
+ return xModel;
+}
+
+void ODatabaseModelImpl::acquire()
+{
+ osl_atomic_increment(&m_refCount);
+}
+
+void ODatabaseModelImpl::release()
+{
+ if ( osl_atomic_decrement(&m_refCount) == 0 )
+ {
+ acquire(); // prevent multiple releases
+ m_rDBContext.removeFromTerminateListener(*this);
+ dispose();
+ m_rDBContext.storeTransientProperties(*this);
+ if (!m_sDocumentURL.isEmpty())
+ m_rDBContext.revokeDatabaseDocument(*this);
+ delete this;
+ }
+}
+
+void ODatabaseModelImpl::commitStorages()
+{
+ getDocumentStorageAccess()->commitStorages();
+}
+
+Reference< XStorage > ODatabaseModelImpl::getStorage( const ObjectType _eType )
+{
+ return getDocumentStorageAccess()->getDocumentSubStorage( getObjectContainerStorageName( _eType ),
+ css::embed::ElementModes::READWRITE );
+}
+
+const AsciiPropertyValue* ODatabaseModelImpl::getDefaultDataSourceSettings()
+{
+ static const AsciiPropertyValue aKnownSettings[] =
+ {
+ // known JDBC settings
+ AsciiPropertyValue( "JavaDriverClass", Any( OUString() ) ),
+ AsciiPropertyValue( "JavaDriverClassPath", Any( OUString() ) ),
+ AsciiPropertyValue( "IgnoreCurrency", Any( false ) ),
+ // known settings for file-based drivers
+ AsciiPropertyValue( "Extension", Any( OUString() ) ),
+ AsciiPropertyValue( "CharSet", Any( OUString() ) ),
+ AsciiPropertyValue( "HeaderLine", Any( true ) ),
+ AsciiPropertyValue( "FieldDelimiter", Any( OUString( "," ) ) ),
+ AsciiPropertyValue( "StringDelimiter", Any( OUString( "\"" ) ) ),
+ AsciiPropertyValue( "DecimalDelimiter", Any( OUString( "." ) ) ),
+ AsciiPropertyValue( "ThousandDelimiter", Any( OUString() ) ),
+ AsciiPropertyValue( "ShowDeleted", Any( false ) ),
+ // known ODBC settings
+ AsciiPropertyValue( "SystemDriverSettings", Any( OUString() ) ),
+ AsciiPropertyValue( "UseCatalog", Any( false ) ),
+ AsciiPropertyValue( "TypeInfoSettings", Any( Sequence< Any >()) ),
+ // settings related to auto increment handling
+ AsciiPropertyValue( "AutoIncrementCreation", Any( OUString() ) ),
+ AsciiPropertyValue( "AutoRetrievingStatement", Any( OUString() ) ),
+ AsciiPropertyValue( "IsAutoRetrievingEnabled", Any( false ) ),
+ // known LDAP driver settings
+ AsciiPropertyValue( "HostName", Any( OUString() ) ),
+ AsciiPropertyValue( "PortNumber", Any( sal_Int32(389) ) ),
+ AsciiPropertyValue( "BaseDN", Any( OUString() ) ),
+ AsciiPropertyValue( "MaxRowCount", Any( sal_Int32(100) ) ),
+ // known MySQLNative driver settings
+ AsciiPropertyValue( "LocalSocket", Any( OUString() ) ),
+ AsciiPropertyValue( "NamedPipe", Any( OUString() ) ),
+ // misc known driver settings
+ AsciiPropertyValue( "ParameterNameSubstitution", Any( false ) ),
+ AsciiPropertyValue( "AddIndexAppendix", Any( true ) ),
+ AsciiPropertyValue( "IgnoreDriverPrivileges", Any( true ) ),
+ AsciiPropertyValue( "ImplicitCatalogRestriction", ::cppu::UnoType< OUString >::get() ),
+ AsciiPropertyValue( "ImplicitSchemaRestriction", ::cppu::UnoType< OUString >::get() ),
+ AsciiPropertyValue( "PrimaryKeySupport", ::cppu::UnoType< sal_Bool >::get() ),
+ AsciiPropertyValue( "ShowColumnDescription", Any( false ) ),
+ // known SDB level settings
+ AsciiPropertyValue( "NoNameLengthLimit", Any( false ) ),
+ AsciiPropertyValue( "AppendTableAliasName", Any( false ) ),
+ AsciiPropertyValue( "GenerateASBeforeCorrelationName", Any( false ) ),
+ AsciiPropertyValue( "ColumnAliasInOrderBy", Any( true ) ),
+ AsciiPropertyValue( "EnableSQL92Check", Any( false ) ),
+ AsciiPropertyValue( "BooleanComparisonMode", Any( BooleanComparisonMode::EQUAL_INTEGER ) ),
+ AsciiPropertyValue( "TableTypeFilterMode", Any( sal_Int32(3) ) ),
+ AsciiPropertyValue( "RespectDriverResultSetType", Any( false ) ),
+ AsciiPropertyValue( "UseSchemaInSelect", Any( true ) ),
+ AsciiPropertyValue( "UseCatalogInSelect", Any( true ) ),
+ AsciiPropertyValue( "EnableOuterJoinEscape", Any( true ) ),
+ AsciiPropertyValue( "PreferDosLikeLineEnds", Any( false ) ),
+ AsciiPropertyValue( "FormsCheckRequiredFields", Any( true ) ),
+ AsciiPropertyValue( "EscapeDateTime", Any( true ) ),
+
+ // known services to handle database tasks
+ AsciiPropertyValue( "TableAlterationServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "TableRenameServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "ViewAlterationServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "ViewAccessServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "CommandDefinitions", Any( OUString() ) ),
+ AsciiPropertyValue( "Forms", Any( OUString() ) ),
+ AsciiPropertyValue( "Reports", Any( OUString() ) ),
+ AsciiPropertyValue( "KeyAlterationServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "IndexAlterationServiceName", Any( OUString() ) ),
+
+ AsciiPropertyValue()
+ };
+ return aKnownSettings;
+}
+
+TContentPtr& ODatabaseModelImpl::getObjectContainer( ObjectType _eType )
+{
+ OSL_PRECOND( _eType >= E_FORM && _eType <= E_TABLE, "ODatabaseModelImpl::getObjectContainer: illegal index!" );
+ TContentPtr& rContentPtr = m_aContainer[ _eType ];
+
+ if ( !rContentPtr )
+ {
+ rContentPtr = std::make_shared<ODefinitionContainer_Impl>();
+ rContentPtr->m_pDataSource = this;
+ rContentPtr->m_aProps.aTitle = lcl_getContainerStorageName_throw( _eType );
+ }
+ return rContentPtr;
+}
+
+bool ODatabaseModelImpl::adjustMacroMode_AutoReject()
+{
+ return m_aMacroMode.adjustMacroMode( nullptr );
+}
+
+bool ODatabaseModelImpl::checkMacrosOnLoading()
+{
+ Reference< XInteractionHandler > xInteraction;
+ xInteraction = m_aMediaDescriptor.getOrDefault( "InteractionHandler", xInteraction );
+ return m_aMacroMode.checkMacrosOnLoading( xInteraction );
+}
+
+void ODatabaseModelImpl::resetMacroExecutionMode()
+{
+ m_aMacroMode = ::sfx2::DocumentMacroMode( *this );
+}
+
+Reference< XStorageBasedLibraryContainer > ODatabaseModelImpl::getLibraryContainer( bool _bScript )
+{
+ Reference< XStorageBasedLibraryContainer >& rxContainer( _bScript ? m_xBasicLibraries : m_xDialogLibraries );
+ if ( rxContainer.is() )
+ return rxContainer;
+
+ Reference< XStorageBasedDocument > xDocument( getModel_noCreate(), UNO_QUERY_THROW );
+ // this is only to be called if there already exists a document model - in fact, it is
+ // to be called by the document model only
+
+ try
+ {
+ Reference< XStorageBasedLibraryContainer > (*Factory)( const Reference< XComponentContext >&, const Reference< XStorageBasedDocument >&)
+ = _bScript ? &DocumentScriptLibraryContainer::create : &DocumentDialogLibraryContainer::create;
+
+ rxContainer.set(
+ (*Factory)( m_aContext, xDocument ),
+ UNO_SET_THROW
+ );
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ throw WrappedTargetRuntimeException(
+ OUString(),
+ xDocument,
+ ::cppu::getCaughtException()
+ );
+ }
+ return rxContainer;
+}
+
+void ODatabaseModelImpl::storeLibraryContainersTo( const Reference< XStorage >& _rxToRootStorage )
+{
+ if ( m_xBasicLibraries.is() )
+ m_xBasicLibraries->storeLibrariesToStorage( _rxToRootStorage );
+
+ if ( m_xDialogLibraries.is() )
+ m_xDialogLibraries->storeLibrariesToStorage( _rxToRootStorage );
+}
+
+Reference< XStorage > ODatabaseModelImpl::switchToStorage( const Reference< XStorage >& _rxNewRootStorage )
+{
+ if ( !_rxNewRootStorage.is() )
+ throw IllegalArgumentException();
+
+ return impl_switchToStorage_throw( _rxNewRootStorage );
+}
+
+namespace
+{
+ void lcl_modifyListening( ::sfx2::IModifiableDocument& _rDocument,
+ const Reference< XStorage >& _rxStorage, ::rtl::Reference< ::sfx2::DocumentStorageModifyListener >& _inout_rListener,
+ comphelper::SolarMutex& _rMutex, bool _bListen )
+ {
+ Reference< XModifiable > xModify( _rxStorage, UNO_QUERY );
+ OSL_ENSURE( xModify.is() || !_rxStorage.is(), "lcl_modifyListening: storage can't notify us!" );
+
+ if ( xModify.is() && !_bListen && _inout_rListener.is() )
+ {
+ xModify->removeModifyListener( _inout_rListener );
+ }
+
+ if ( _inout_rListener.is() )
+ {
+ _inout_rListener->dispose();
+ _inout_rListener = nullptr;
+ }
+
+ if ( xModify.is() && _bListen )
+ {
+ _inout_rListener = new ::sfx2::DocumentStorageModifyListener( _rDocument, _rMutex );
+ xModify->addModifyListener( _inout_rListener );
+ }
+ }
+}
+
+namespace
+{
+ void lcl_rebaseScriptStorage_throw( const Reference< XStorageBasedLibraryContainer >& _rxContainer,
+ const Reference< XStorage >& _rxNewRootStorage )
+ {
+ if ( _rxContainer.is() )
+ {
+ if ( _rxNewRootStorage.is() )
+ _rxContainer->setRootStorage( _rxNewRootStorage );
+// else
+ // TODO: what to do here? dispose the container?
+ }
+ }
+}
+
+Reference< XStorage > const & ODatabaseModelImpl::impl_switchToStorage_throw( const Reference< XStorage >& _rxNewRootStorage )
+{
+ // stop listening for modifications at the old storage
+ lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), false );
+
+ // set new storage
+ m_xDocumentStorage.reset( _rxNewRootStorage, SharedStorage::TakeOwnership );
+
+ // start listening for modifications
+ lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), true );
+
+ // forward new storage to Basic and Dialog library containers
+ lcl_rebaseScriptStorage_throw( m_xBasicLibraries, m_xDocumentStorage.getTyped() );
+ lcl_rebaseScriptStorage_throw( m_xDialogLibraries, m_xDocumentStorage.getTyped() );
+
+ m_bReadOnly = !tools::stor::storageIsWritable_nothrow( m_xDocumentStorage.getTyped() );
+ // TODO: our data source, if it exists, must broadcast the change of its ReadOnly property
+
+ return m_xDocumentStorage.getTyped();
+}
+
+void ODatabaseModelImpl::impl_switchToLogicalURL( const OUString& i_rDocumentURL )
+{
+ if ( i_rDocumentURL == m_sDocumentURL )
+ return;
+
+ const OUString sOldURL( m_sDocumentURL );
+ // update our name, if necessary
+ if ( ( m_sName == m_sDocumentURL ) // our name is our old URL
+ || ( m_sName.isEmpty() ) // we do not have a name, yet (i.e. are not registered at the database context)
+ )
+ {
+ INetURLObject aURL( i_rDocumentURL );
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ m_sName = i_rDocumentURL;
+ // TODO: our data source must broadcast the change of the Name property
+ }
+ }
+
+ // remember URL
+ m_sDocumentURL = i_rDocumentURL;
+
+ // update our location, if necessary
+ if ( m_sDocFileLocation.isEmpty() )
+ m_sDocFileLocation = m_sDocumentURL;
+
+ // register at the database context, or change registration
+ if (!sOldURL.isEmpty())
+ m_rDBContext.databaseDocumentURLChange( sOldURL, m_sDocumentURL );
+ else
+ m_rDBContext.registerDatabaseDocument( *this );
+}
+
+OUString ODatabaseModelImpl::getObjectContainerStorageName( const ObjectType _eType )
+{
+ return lcl_getContainerStorageName_throw( _eType );
+}
+
+sal_Int16 ODatabaseModelImpl::getCurrentMacroExecMode() const
+{
+ sal_Int16 nCurrentMode = MacroExecMode::NEVER_EXECUTE;
+ try
+ {
+ nCurrentMode = m_aMediaDescriptor.getOrDefault( "MacroExecutionMode", nCurrentMode );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return nCurrentMode;
+}
+
+void ODatabaseModelImpl::setCurrentMacroExecMode( sal_uInt16 nMacroMode )
+{
+ m_aMediaDescriptor.put( "MacroExecutionMode", nMacroMode );
+}
+
+OUString ODatabaseModelImpl::getDocumentLocation() const
+{
+ return getURL();
+ // formerly, we returned getDocFileLocation here, which is the location of the file from which we
+ // recovered the "real" document.
+ // However, during CWS autorecovery evolving, we clarified (with MAV/MT) the role of XModel::getURL and
+ // XStorable::getLocation. In this course, we agreed that for a macro security check, the *document URL*
+ // (not the recovery file URL) is to be used: The recovery file lies in the backup folder, and by definition,
+ // this folder is considered to be secure. So, the document URL needs to be used to decide about the security.
+}
+
+ODatabaseModelImpl::EmbeddedMacros ODatabaseModelImpl::determineEmbeddedMacros()
+{
+ if ( !m_aEmbeddedMacros )
+ {
+ if ( ::sfx2::DocumentMacroMode::storageHasMacros( getOrCreateRootStorage() ) )
+ {
+ m_aEmbeddedMacros = eDocumentWideMacros;
+ }
+ else if ( lcl_hasObjectsWithMacros_nothrow( *this, E_FORM )
+ || lcl_hasObjectsWithMacros_nothrow( *this, E_REPORT )
+ )
+ {
+ m_aEmbeddedMacros = eSubDocumentMacros;
+ }
+ else
+ {
+ m_aEmbeddedMacros = eNoMacros;
+ }
+ }
+ return *m_aEmbeddedMacros;
+}
+
+bool ODatabaseModelImpl::documentStorageHasMacros() const
+{
+ const_cast< ODatabaseModelImpl* >( this )->determineEmbeddedMacros();
+ return ( *m_aEmbeddedMacros != eNoMacros );
+}
+
+bool ODatabaseModelImpl::macroCallsSeenWhileLoading() const
+{
+ return m_bMacroCallsSeenWhileLoading;
+}
+
+Reference< XEmbeddedScripts > ODatabaseModelImpl::getEmbeddedDocumentScripts() const
+{
+ return Reference< XEmbeddedScripts >( getModel_noCreate(), UNO_QUERY );
+}
+
+SignatureState ODatabaseModelImpl::getScriptingSignatureState()
+{
+ return m_nScriptingSignatureState;
+}
+
+bool ODatabaseModelImpl::hasTrustedScriptingSignature(bool bAllowUIToAddAuthor)
+{
+ bool bResult = false;
+
+ try
+ {
+ // Don't use m_xDocumentStorage, that somehow has an incomplete storage representation
+ // which leads to signatures not being found
+ Reference<XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
+ ZIP_STORAGE_FORMAT_STRING, m_sDocFileLocation, ElementModes::READ);
+
+ OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(getOrCreateRootStorage()));
+ uno::Reference<security::XDocumentDigitalSignatures> xSigner(
+ security::DocumentDigitalSignatures::createWithVersion(
+ comphelper::getProcessComponentContext(), aODFVersion));
+ const uno::Sequence<security::DocumentSignatureInformation> aInfo
+ = xSigner->verifyScriptingContentSignatures(xStorage,
+ uno::Reference<io::XInputStream>());
+
+ if (!aInfo.hasElements())
+ return false;
+
+ m_nScriptingSignatureState = DocumentSignatures::getSignatureState(aInfo);
+ if (m_nScriptingSignatureState == SignatureState::OK
+ || m_nScriptingSignatureState == SignatureState::NOTVALIDATED)
+ {
+ bResult = std::any_of(aInfo.begin(), aInfo.end(),
+ [&xSigner](const security::DocumentSignatureInformation& rInfo) {
+ return xSigner->isAuthorTrusted(rInfo.Signer);
+ });
+ }
+
+ if (!bResult && bAllowUIToAddAuthor)
+ {
+ Reference<XInteractionHandler> xInteraction;
+ xInteraction = m_aMediaDescriptor.getOrDefault("InteractionHandler", xInteraction);
+ if (xInteraction.is())
+ {
+ task::DocumentMacroConfirmationRequest aRequest;
+ aRequest.DocumentURL = m_sDocFileLocation;
+ aRequest.DocumentStorage = xStorage;
+ aRequest.DocumentSignatureInformation = aInfo;
+ aRequest.DocumentVersion = aODFVersion;
+ aRequest.Classification = task::InteractionClassification_QUERY;
+ bResult = SfxMedium::CallApproveHandler(xInteraction, uno::Any(aRequest), true);
+ }
+ }
+ }
+ catch (uno::Exception&)
+ {
+ }
+
+ return bResult;
+}
+
+void ODatabaseModelImpl::storageIsModified()
+{
+ setModified( true );
+}
+
+ModelDependentComponent::ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model )
+ :m_pImpl( _model )
+{
+}
+
+ModelDependentComponent::~ModelDependentComponent()
+{
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/SharedConnection.cxx b/dbaccess/source/core/dataaccess/SharedConnection.cxx
new file mode 100644
index 000000000..31a8e68ba
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/SharedConnection.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SharedConnection.hxx"
+#include <comphelper/uno3.hxx>
+
+namespace dbaccess
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace connectivity;
+
+OSharedConnection::OSharedConnection(Reference<XAggregation>& _rxProxyConnection)
+ : OSharedConnection_BASE(m_aMutex)
+{
+ setDelegation(_rxProxyConnection, m_refCount);
+}
+
+OSharedConnection::~OSharedConnection() {}
+
+void SAL_CALL OSharedConnection::disposing()
+{
+ OSharedConnection_BASE::disposing();
+ OConnectionWrapper::disposing();
+}
+
+Reference<XStatement> SAL_CALL OSharedConnection::createStatement()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->createStatement();
+}
+
+Reference<XPreparedStatement> SAL_CALL OSharedConnection::prepareStatement(const OUString& sql)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->prepareStatement(sql);
+}
+
+Reference<XPreparedStatement> SAL_CALL OSharedConnection::prepareCall(const OUString& sql)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->prepareCall(sql);
+}
+
+OUString SAL_CALL OSharedConnection::nativeSQL(const OUString& sql)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->nativeSQL(sql);
+}
+
+sal_Bool SAL_CALL OSharedConnection::getAutoCommit()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getAutoCommit();
+}
+
+void SAL_CALL OSharedConnection::commit()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ m_xConnection->commit();
+}
+
+void SAL_CALL OSharedConnection::rollback()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ m_xConnection->rollback();
+}
+
+sal_Bool SAL_CALL OSharedConnection::isClosed()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (!m_xConnection.is())
+ return true;
+
+ return m_xConnection->isClosed();
+}
+
+Reference<XDatabaseMetaData> SAL_CALL OSharedConnection::getMetaData()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getMetaData();
+}
+
+sal_Bool SAL_CALL OSharedConnection::isReadOnly()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->isReadOnly();
+}
+
+OUString SAL_CALL OSharedConnection::getCatalog()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getCatalog();
+}
+
+sal_Int32 SAL_CALL OSharedConnection::getTransactionIsolation()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getTransactionIsolation();
+}
+
+Reference<css::container::XNameAccess> SAL_CALL OSharedConnection::getTypeMap()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getTypeMap();
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID(OSharedConnection)
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/SharedConnection.hxx b/dbaccess/source/core/dataaccess/SharedConnection.hxx
new file mode 100644
index 000000000..ea6e961cf
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/SharedConnection.hxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/ConnectionWrapper.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/sequence.hxx>
+
+namespace dbaccess
+{
+ // OSharedConnection: This class implements a simple forwarding of connection calls.
+ // All methods will be forwarded with exception of the set methods, which are not allowed
+ // to be called on shared connections. Instances of this class will be created when the
+ // datasource is asked for not isolated connection.
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection
+ > OSharedConnection_BASE;
+ typedef ::connectivity::OConnectionWrapper OSharedConnection_BASE2;
+
+ class OSharedConnection : public ::cppu::BaseMutex
+ , public OSharedConnection_BASE
+ , public OSharedConnection_BASE2
+ {
+ protected:
+ virtual void SAL_CALL disposing() override;
+ virtual ~OSharedConnection() override;
+ public:
+ explicit OSharedConnection(css::uno::Reference< css::uno::XAggregation >& _rxProxyConnection);
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ virtual void SAL_CALL acquire() noexcept override { OSharedConnection_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OSharedConnection_BASE::release(); }
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override
+ {
+ return ::comphelper::concatSequences(
+ OSharedConnection_BASE::getTypes(),
+ OSharedConnection_BASE2::getTypes()
+ );
+ }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& _rType ) override
+ {
+ css::uno::Any aReturn = OSharedConnection_BASE::queryInterface(_rType);
+ if ( !aReturn.hasValue() )
+ aReturn = OSharedConnection_BASE2::queryInterface(_rType);
+ return aReturn;
+ }
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override
+ {
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(rBHelper.bDisposed);
+ }
+ dispose();
+ }
+
+ // XConnection
+ virtual void SAL_CALL setAutoCommit( sal_Bool /*autoCommit*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setReadOnly( sal_Bool /*readOnly*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setCatalog( const OUString& /*catalog*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 /*level*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& /*typeMap*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx
new file mode 100644
index 000000000..a03caea57
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <bookmarkcontainer.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/enumhelper.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OBookmarkContainer
+
+OBookmarkContainer::OBookmarkContainer(OWeakObject& _rParent, Mutex& _rMutex)
+ :m_rParent(_rParent)
+ ,m_aContainerListeners(_rMutex)
+ ,m_rMutex(_rMutex)
+{
+}
+
+
+void SAL_CALL OBookmarkContainer::acquire( ) noexcept
+{
+ m_rParent.acquire();
+}
+
+void SAL_CALL OBookmarkContainer::release( ) noexcept
+{
+ m_rParent.release();
+}
+
+OBookmarkContainer::~OBookmarkContainer()
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL OBookmarkContainer::getImplementationName( )
+{
+ return "com.sun.star.comp.dba.OBookmarkContainer";
+}
+
+sal_Bool SAL_CALL OBookmarkContainer::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL OBookmarkContainer::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.DefinitionContainer" };
+}
+
+// XNameContainer
+void SAL_CALL OBookmarkContainer::insertByName( const OUString& _rName, const Any& aElement )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if (checkExistence(_rName))
+ throw ElementExistException();
+
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ // approve the new object
+ OUString sNewLink;
+ if (!(aElement >>= sNewLink))
+ throw IllegalArgumentException();
+
+ implAppend(_rName, sNewLink);
+
+ // notify the listeners
+ if (m_aContainerListeners.getLength())
+ {
+ ContainerEvent aEvent(*this, Any(_rName), Any(sNewLink), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+ }
+}
+
+void SAL_CALL OBookmarkContainer::removeByName( const OUString& _rName )
+{
+ OUString sOldBookmark;
+ {
+ MutexGuard aGuard(m_rMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException();
+
+ // the old element (for the notifications)
+ sOldBookmark = m_aBookmarks[_rName];
+
+ // do the removal
+ implRemove(_rName);
+ }
+
+ // notify the listeners
+ if (m_aContainerListeners.getLength())
+ {
+ ContainerEvent aEvent(*this, Any(_rName), Any(sOldBookmark), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
+ }
+}
+
+// XNameReplace
+void SAL_CALL OBookmarkContainer::replaceByName( const OUString& _rName, const Any& aElement )
+{
+ ClearableMutexGuard aGuard(m_rMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ // do we have such an element?
+ if (!checkExistence(_rName))
+ throw NoSuchElementException();
+
+ // approve the new object
+ OUString sNewLink;
+ if (!(aElement >>= sNewLink))
+ throw IllegalArgumentException();
+
+ // the old element (for the notifications)
+ OUString sOldLink = m_aBookmarks[_rName];
+
+ // do the replace
+ implReplace(_rName, sNewLink);
+
+ // notify the listeners
+ aGuard.clear();
+ if (m_aContainerListeners.getLength())
+ {
+ ContainerEvent aEvent(*this, Any(_rName), Any(sNewLink), Any(sOldLink));
+ m_aContainerListeners.notifyEach( &XContainerListener::elementReplaced, aEvent );
+ }
+}
+
+void SAL_CALL OBookmarkContainer::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ MutexGuard aGuard(m_rMutex);
+ if (_rxListener.is())
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL OBookmarkContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ MutexGuard aGuard(m_rMutex);
+ if (_rxListener.is())
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+// XElementAccess
+Type SAL_CALL OBookmarkContainer::getElementType( )
+{
+ return ::cppu::UnoType<OUString>::get();
+}
+
+sal_Bool SAL_CALL OBookmarkContainer::hasElements( )
+{
+ MutexGuard aGuard(m_rMutex);
+ return !m_aBookmarks.empty();
+}
+
+// XEnumerationAccess
+Reference< XEnumeration > SAL_CALL OBookmarkContainer::createEnumeration( )
+{
+ MutexGuard aGuard(m_rMutex);
+ return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this));
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL OBookmarkContainer::getCount( )
+{
+ MutexGuard aGuard(m_rMutex);
+ return m_aBookmarks.size();
+}
+
+Any SAL_CALL OBookmarkContainer::getByIndex( sal_Int32 _nIndex )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if ((_nIndex < 0) || (o3tl::make_unsigned(_nIndex) >= m_aBookmarksIndexed.size()))
+ throw IndexOutOfBoundsException();
+
+ return Any(m_aBookmarksIndexed[_nIndex]->second);
+}
+
+Any SAL_CALL OBookmarkContainer::getByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException();
+
+ return Any(m_aBookmarks[_rName]);
+}
+
+Sequence< OUString > SAL_CALL OBookmarkContainer::getElementNames( )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ Sequence< OUString > aNames(m_aBookmarks.size());
+ OUString* pNames = aNames.getArray();
+
+ for (auto const& bookmarkIndexed : m_aBookmarksIndexed)
+ {
+ *pNames = bookmarkIndexed->first;
+ ++pNames;
+ }
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL OBookmarkContainer::hasByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ return checkExistence(_rName);
+}
+
+void OBookmarkContainer::implRemove(const OUString& _rName)
+{
+ MutexGuard aGuard(m_rMutex);
+
+ // look for the name in the index access vector
+ MapString2String::const_iterator aMapPos = m_aBookmarks.end();
+ auto aSearch = std::find_if(m_aBookmarksIndexed.begin(), m_aBookmarksIndexed.end(),
+ [&_rName](const MapString2String::iterator& rIter) { return rIter->first == _rName; });
+ if (aSearch != m_aBookmarksIndexed.end())
+ {
+ aMapPos = *aSearch;
+ m_aBookmarksIndexed.erase(aSearch);
+ }
+
+ if (m_aBookmarks.end() == aMapPos)
+ {
+ OSL_FAIL("OBookmarkContainer::implRemove: inconsistence!");
+ return;
+ }
+
+ // remove the map entries
+ m_aBookmarks.erase(aMapPos);
+}
+
+void OBookmarkContainer::implAppend(const OUString& _rName, const OUString& _rDocumentLocation)
+{
+ MutexGuard aGuard(m_rMutex);
+
+ OSL_ENSURE(m_aBookmarks.find(_rName) == m_aBookmarks.end(),"Bookmark already known!");
+ m_aBookmarksIndexed.push_back(m_aBookmarks.emplace( _rName,_rDocumentLocation).first);
+}
+
+void OBookmarkContainer::implReplace(const OUString& _rName, const OUString& _rNewLink)
+{
+ MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(checkExistence(_rName), "OBookmarkContainer::implReplace : invalid name !");
+
+ m_aBookmarks[_rName] = _rNewLink;
+}
+
+Reference< XInterface > SAL_CALL OBookmarkContainer::getParent( )
+{
+ return m_rParent;
+}
+
+void SAL_CALL OBookmarkContainer::setParent( const Reference< XInterface >& /*Parent*/ )
+{
+ throw NoSupportException();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commandcontainer.cxx b/dbaccess/source/core/dataaccess/commandcontainer.cxx
new file mode 100644
index 000000000..8afb81520
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commandcontainer.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "commandcontainer.hxx"
+#include "commanddefinition.hxx"
+
+#include <com/sun/star/sdb/TableDefinition.hpp>
+#include <com/sun/star/sdb/CommandDefinition.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ucb;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OCommandContainer
+
+OCommandContainer::OCommandContainer( const Reference< css::uno::XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ ,bool _bTables
+ )
+ :ODefinitionContainer(_xORB,_xParentContainer,_pImpl,!_bTables)
+ ,m_bTables(_bTables)
+{
+}
+
+OCommandContainer::~OCommandContainer()
+{
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( OCommandContainer,ODefinitionContainer,OCommandContainer_BASE)
+css::uno::Sequence< css::uno::Type > OCommandContainer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ ODefinitionContainer::getTypes( ),
+ OCommandContainer_BASE::getTypes( )
+ );
+}
+
+css::uno::Sequence<sal_Int8> OCommandContainer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Reference< XContent > OCommandContainer::createObject( const OUString& _rName)
+{
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ OSL_ENSURE( rDefinitions.find(_rName) != rDefinitions.end(), "OCommandContainer::createObject: Invalid entry in map!" );
+
+ const TContentPtr& pElementContent( rDefinitions.find( _rName )->second );
+ if ( m_bTables )
+ return new OComponentDefinition( *this, _rName, m_aContext, pElementContent, m_bTables );
+ else
+ return static_cast< css::sdb::XQueryDefinition * > ( new OCommandDefinition( *this, _rName, m_aContext, pElementContent ) );
+}
+
+Reference< XInterface > SAL_CALL OCommandContainer::createInstanceWithArguments(const Sequence< Any >& /*aArguments*/ )
+{
+ return createInstance( );
+}
+
+Reference< XInterface > SAL_CALL OCommandContainer::createInstance( )
+{
+ if(m_bTables)
+ return css::sdb::TableDefinition::createDefault( m_aContext );
+ else
+ return css::sdb::CommandDefinition::create( m_aContext );
+}
+
+OUString OCommandContainer::determineContentType() const
+{
+ return "application/vnd.org.openoffice.DatabaseCommandDefinitionContainer";
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commandcontainer.hxx b/dbaccess/source/core/dataaccess/commandcontainer.hxx
new file mode 100644
index 000000000..3ea36f648
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commandcontainer.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <definitioncontainer.hxx>
+
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+// OCommandContainer
+
+typedef ::cppu::ImplHelper1 < css::lang::XSingleServiceFactory
+ > OCommandContainer_BASE;
+
+class OCommandContainer : public ODefinitionContainer
+ ,public OCommandContainer_BASE
+{
+ bool m_bTables;
+
+public:
+ /** constructs the container.<BR>
+ */
+ OCommandContainer(
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ ,const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ ,bool _bTables
+ );
+
+ DECLARE_XINTERFACE( )
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XSingleServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+protected:
+ virtual ~OCommandContainer() override;
+
+ // ODefinitionContainer
+ virtual css::uno::Reference< css::ucb::XContent > createObject(const OUString& _rName) override;
+
+protected:
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commanddefinition.cxx b/dbaccess/source/core/dataaccess/commanddefinition.cxx
new file mode 100644
index 000000000..f04c47228
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commanddefinition.cxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "commanddefinition.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+namespace dbaccess
+{
+
+void OCommandDefinition::registerProperties()
+{
+ OCommandDefinition_Impl& rCommandDefinition = dynamic_cast< OCommandDefinition_Impl& >( *m_pImpl );
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sCommand, cppu::UnoType<decltype(rCommandDefinition.m_sCommand)>::get());
+
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_bEscapeProcessing, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sUpdateTableName, cppu::UnoType<decltype(rCommandDefinition.m_sUpdateTableName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sUpdateSchemaName, cppu::UnoType<decltype(rCommandDefinition.m_sUpdateSchemaName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sUpdateCatalogName, cppu::UnoType<decltype(rCommandDefinition.m_sUpdateCatalogName)>::get());
+ registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_aLayoutInformation, cppu::UnoType<decltype(rCommandDefinition.m_aLayoutInformation)>::get());
+}
+
+OCommandDefinition::OCommandDefinition(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _rxContainer
+ ,const TContentPtr& _pImpl)
+ :OComponentDefinition(_xORB,_rxContainer,_pImpl,false)
+{
+ registerProperties();
+}
+
+OCommandDefinition::~OCommandDefinition()
+{
+}
+
+OCommandDefinition::OCommandDefinition( const Reference< XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const Reference< XComponentContext >& _xORB
+ ,const TContentPtr& _pImpl)
+ :OComponentDefinition(_rxContainer,_rElementName,_xORB,_pImpl,false)
+{
+ registerProperties();
+}
+
+css::uno::Sequence<sal_Int8> OCommandDefinition::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OCommandDefinition::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OCommandDefinition_Base::getTypes( ),
+ OComponentDefinition::getTypes( )
+ );
+}
+IMPLEMENT_FORWARD_XINTERFACE2( OCommandDefinition,OComponentDefinition,OCommandDefinition_Base)
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OCommandDefinition::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+::cppu::IPropertyArrayHelper& OCommandDefinition::getInfoHelper()
+{
+ return *OCommandDefinition_PROP::getArrayHelper();
+}
+::cppu::IPropertyArrayHelper* OCommandDefinition::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+OUString SAL_CALL OCommandDefinition::getImplementationName()
+{
+ return "com.sun.star.comp.dba.OCommandDefinition";
+}
+
+css::uno::Sequence<OUString> SAL_CALL OCommandDefinition::getSupportedServiceNames()
+{
+ return {
+ "com.sun.star.sdb.QueryDefinition",
+ "com.sun.star.sdb.CommandDefinition",
+ "com.sun.star.ucb.Content"
+ };
+}
+
+void SAL_CALL OCommandDefinition::rename( const OUString& newName )
+{
+ try
+ {
+ sal_Int32 nHandle = PROPERTY_ID_NAME;
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ Any aOld(m_pImpl->m_aProps.aTitle);
+ aGuard.clear();
+ Any aNew(newName);
+ fire(&nHandle, &aNew, &aOld, 1, true );
+
+ m_pImpl->m_aProps.aTitle = newName;
+ fire(&nHandle, &aNew, &aOld, 1, false );
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(newName,*this);
+ }
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_OCommandDefinition(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new dbaccess::OCommandDefinition(
+ context, nullptr, std::make_shared<dbaccess::OCommandDefinition_Impl>() ));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commanddefinition.hxx b/dbaccess/source/core/dataaccess/commanddefinition.hxx
new file mode 100644
index 000000000..ed348a889
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commanddefinition.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <commandbase.hxx>
+#include <apitools.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdb/XQueryDefinition.hpp>
+#include <datasettings.hxx>
+#include <ContentHelper.hxx>
+#include "ComponentDefinition.hxx"
+
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase2.hxx>
+
+namespace dbaccess
+{
+
+// OCommandDefinition - a database "document" which describes a query
+ class OCommandDefinition_Impl : public OComponentDefinition_Impl
+ ,public OCommandBase
+ {
+ public:
+ };
+
+typedef ::cppu::ImplHelper2 < css::sdbcx::XRename,
+ css::sdb::XQueryDefinition
+ > OCommandDefinition_Base;
+class OCommandDefinition;
+typedef ::comphelper::OPropertyArrayUsageHelper< OCommandDefinition >
+ OCommandDefinition_PROP;
+
+class OCommandDefinition : public OComponentDefinition
+ ,public OCommandDefinition_Base
+ ,public OCommandDefinition_PROP
+{
+protected:
+ virtual ~OCommandDefinition() override;
+
+public:
+ OCommandDefinition(const css::uno::Reference< css::uno::XComponentContext >& ,
+ const css::uno::Reference< css::uno::XInterface >& _xParentContainer,
+ const TContentPtr& _pImpl);
+
+ OCommandDefinition(
+ const css::uno::Reference< css::uno::XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const css::uno::Reference< css::uno::XComponentContext >&
+ ,const TContentPtr& _pImpl
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // overrides to resolve ambiguity
+ virtual void SAL_CALL setPropertyValue(const OUString& p1, const css::uno::Any& p2) override
+ { OComponentDefinition::setPropertyValue(p1, p2); }
+ virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& p1) override
+ { return OComponentDefinition::getPropertyValue(p1); }
+ virtual void SAL_CALL addPropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
+ { OComponentDefinition::addPropertyChangeListener(p1, p2); }
+ virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
+ { OComponentDefinition::removePropertyChangeListener(p1, p2); }
+ virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
+ { OComponentDefinition::addVetoableChangeListener(p1, p2); }
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
+ { OComponentDefinition::removeVetoableChangeListener(p1, p2); }
+ virtual css::uno::Reference<css::ucb::XContentIdentifier> SAL_CALL getIdentifier() override
+ { return OComponentDefinition::getIdentifier(); }
+ virtual OUString SAL_CALL getContentType() override
+ { return OComponentDefinition::getContentType(); }
+ virtual void SAL_CALL addContentEventListener(const css::uno::Reference<css::ucb::XContentEventListener>& p1) override
+ { OComponentDefinition::addContentEventListener(p1); }
+ virtual void SAL_CALL removeContentEventListener(const css::uno::Reference<css::ucb::XContentEventListener>& p1) override
+ { OComponentDefinition::removeContentEventListener(p1); }
+ virtual void SAL_CALL dispose() override
+ { OComponentDefinition::dispose(); }
+ virtual void SAL_CALL addEventListener(const css::uno::Reference<css::lang::XEventListener>& p1) override
+ { OComponentDefinition::addEventListener(p1); }
+ virtual void SAL_CALL removeEventListener(const css::uno::Reference<css::lang::XEventListener>& p1) override
+ { OComponentDefinition::removeEventListener(p1); }
+
+ // OPropertySetHelper
+ virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+
+private:
+ // helper
+ void registerProperties();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/connection.cxx b/dbaccess/source/core/dataaccess/connection.cxx
new file mode 100644
index 000000000..37cf9e669
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/connection.cxx
@@ -0,0 +1,808 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <iterator>
+
+#include "connection.hxx"
+#include "datasource.hxx"
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <statement.hxx>
+#include <preparedstatement.hxx>
+#include <callablestatement.hxx>
+#include <SingleSelectQueryComposer.hxx>
+#include <querycomposer.hxx>
+
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/tools/ConnectionTools.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdb::application;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::reflection;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::graphic;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::dbtools;
+
+using ::com::sun::star::sdb::tools::XTableName;
+using ::com::sun::star::sdb::tools::XObjectNames;
+using ::com::sun::star::sdb::tools::XDataSourceMetaData;
+
+namespace dbaccess
+{
+
+// XServiceInfo
+OUString OConnection::getImplementationName( )
+{
+ return "com.sun.star.comp.dbaccess.Connection";
+}
+
+sal_Bool OConnection::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OConnection::getSupportedServiceNames( )
+{
+ Sequence< OUString > aSupported = OConnectionWrapper::getSupportedServiceNames();
+
+ if ( comphelper::findValue( aSupported, SERVICE_SDB_CONNECTION ) == -1 )
+ {
+ sal_Int32 nLen = aSupported.getLength();
+ aSupported.realloc( nLen + 1 );
+ aSupported.getArray()[ nLen ] = SERVICE_SDB_CONNECTION;
+ }
+
+ return aSupported;
+}
+
+// XCloseable
+void OConnection::close()
+{
+ // being closed is the same as being disposed
+ dispose();
+}
+
+sal_Bool OConnection::isClosed()
+{
+ MutexGuard aGuard(m_aMutex);
+ return !m_xMasterConnection.is();
+}
+
+// XConnection
+Reference< XStatement > OConnection::createStatement()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ Reference< XStatement > xStatement;
+ Reference< XStatement > xMasterStatement = m_xMasterConnection->createStatement();
+ if ( xMasterStatement.is() )
+ {
+ xStatement = new OStatement(this, xMasterStatement);
+ m_aStatements.emplace_back(xStatement);
+ }
+ return xStatement;
+}
+
+Reference< XPreparedStatement > OConnection::prepareStatement(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ // TODO convert the SQL to SQL the driver understands
+ Reference< XPreparedStatement > xStatement;
+ Reference< XPreparedStatement > xMasterStatement = m_xMasterConnection->prepareStatement(sql);
+ if ( xMasterStatement.is() )
+ {
+ xStatement = new OPreparedStatement(this, xMasterStatement);
+ m_aStatements.emplace_back(xStatement);
+ }
+ return xStatement;
+}
+
+Reference< XPreparedStatement > OConnection::prepareCall(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ Reference< XPreparedStatement > xStatement;
+ Reference< XPreparedStatement > xMasterStatement = m_xMasterConnection->prepareCall(sql);
+ if ( xMasterStatement.is() )
+ {
+ xStatement = new OCallableStatement(this, xMasterStatement);
+ m_aStatements.emplace_back(xStatement);
+ }
+ return xStatement;
+}
+
+OUString OConnection::nativeSQL(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->nativeSQL(sql);
+}
+
+void OConnection::setAutoCommit(sal_Bool autoCommit)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setAutoCommit(autoCommit);
+}
+
+sal_Bool OConnection::getAutoCommit()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getAutoCommit();
+}
+
+void OConnection::commit()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->commit();
+}
+
+void OConnection::rollback()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->rollback();
+}
+
+Reference< XDatabaseMetaData > OConnection::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getMetaData();
+}
+
+void OConnection::setReadOnly(sal_Bool readOnly)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setReadOnly(readOnly);
+}
+
+sal_Bool OConnection::isReadOnly()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->isReadOnly();
+}
+
+void OConnection::setCatalog(const OUString& catalog)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setCatalog(catalog);
+}
+
+OUString OConnection::getCatalog()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getCatalog();
+}
+
+void OConnection::setTransactionIsolation(sal_Int32 level)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setTransactionIsolation(level);
+}
+
+sal_Int32 OConnection::getTransactionIsolation()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getTransactionIsolation();
+}
+
+Reference< XNameAccess > OConnection::getTypeMap()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getTypeMap();
+}
+
+void OConnection::setTypeMap(const Reference< XNameAccess > & typeMap)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setTypeMap(typeMap);
+}
+
+// OConnection
+
+OConnection::OConnection(ODatabaseSource& _rDB
+ , Reference< XConnection > const & _rxMaster
+ , const Reference< XComponentContext >& _rxORB)
+ :OSubComponent(m_aMutex, static_cast< OWeakObject* >(&_rDB))
+ // as the queries reroute their refcounting to us, this m_aMutex is okey. If the queries
+ // container would do its own refcounting, it would have to acquire m_pMutex
+ // same for tables
+ ,m_aTableFilter(_rDB.m_pImpl->m_aTableFilter)
+ ,m_aTableTypeFilter(_rDB.m_pImpl->m_aTableTypeFilter)
+ ,m_aContext( _rxORB )
+ ,m_xMasterConnection(_rxMaster)
+ ,m_aWarnings( Reference< XWarningsSupplier >( _rxMaster, UNO_QUERY ) )
+ ,m_nInAppend(0)
+ ,m_bSupportsViews(false)
+ ,m_bSupportsUsers(false)
+ ,m_bSupportsGroups(false)
+{
+ osl_atomic_increment(&m_refCount);
+
+ try
+ {
+ Reference< XProxyFactory > xProxyFactory = ProxyFactory::create( m_aContext );
+ Reference<XAggregation> xAgg = xProxyFactory->createProxy(_rxMaster);
+ setDelegation(xAgg,m_refCount);
+ OSL_ENSURE(m_xConnection.is(), "OConnection::OConnection : invalid master connection !");
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xTableUIProvider.set(m_xMasterConnection, css::uno::UNO_QUERY);
+
+ try
+ {
+ m_xQueries = OQueryContainer::create(Reference< XNameContainer >(_rDB.getQueryDefinitions(), UNO_QUERY), this, _rxORB, &m_aWarnings).get();
+
+ bool bCase = true;
+ Reference<XDatabaseMetaData> xMeta;
+ try
+ {
+ xMeta = getMetaData();
+ bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ }
+ catch(const SQLException&)
+ {
+ }
+ Reference< XNameContainer > xTableDefinitions(_rDB.getTables(),UNO_QUERY);
+ m_pTables.reset( new OTableContainer( *this, m_aMutex, this, bCase, xTableDefinitions, this, m_nInAppend ) );
+
+ // check if we support types
+ if ( xMeta.is() )
+ {
+ Reference<XResultSet> xRes = xMeta->getTableTypes();
+ if(xRes.is())
+ {
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ while(xRes->next())
+ {
+ OUString sValue = xRow->getString(1);
+ if( !xRow->wasNull() && sValue == "VIEW")
+ {
+ m_bSupportsViews = true;
+ break;
+ }
+ }
+ }
+ // some dbs don't support this type so we should ask if a XViewsSupplier is supported
+ if(!m_bSupportsViews)
+ {
+ Reference< XViewsSupplier > xMaster(getMasterTables(),UNO_QUERY);
+
+ if (xMaster.is() && xMaster->getViews().is())
+ m_bSupportsViews = true;
+ }
+ if(m_bSupportsViews)
+ {
+ m_pViews.reset( new OViewContainer(*this, m_aMutex, this, bCase, this, m_nInAppend) );
+ m_pViews->addContainerListener(m_pTables.get());
+ m_pTables->addContainerListener(m_pViews.get());
+ }
+ m_bSupportsUsers = Reference< XUsersSupplier> (getMasterTables(),UNO_QUERY).is();
+ m_bSupportsGroups = Reference< XGroupsSupplier> (getMasterTables(),UNO_QUERY).is();
+
+ impl_checkTableQueryNames_nothrow();
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OConnection::~OConnection()
+{
+}
+
+// XWarningsSupplier
+Any SAL_CALL OConnection::getWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_aWarnings.getWarnings();
+}
+
+void SAL_CALL OConnection::clearWarnings( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_aWarnings.clearWarnings();
+}
+
+namespace
+{
+ struct CompareTypeByName
+ {
+ bool operator() ( const Type& _rLHS, const Type& _rRHS ) const
+ {
+ return _rLHS.getTypeName() < _rRHS.getTypeName();
+ }
+ };
+ typedef std::set< Type, CompareTypeByName > TypeBag;
+
+ void lcl_copyTypes( TypeBag& _out_rTypes, const Sequence< Type >& _rTypes )
+ {
+ std::copy( _rTypes.begin(), _rTypes.end(),
+ std::insert_iterator< TypeBag >( _out_rTypes, _out_rTypes.begin() ) );
+ }
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OConnection::getTypes()
+{
+ TypeBag aNormalizedTypes;
+
+ lcl_copyTypes( aNormalizedTypes, OSubComponent::getTypes() );
+ lcl_copyTypes( aNormalizedTypes, OConnection_Base::getTypes() );
+ lcl_copyTypes( aNormalizedTypes, ::connectivity::OConnectionWrapper::getTypes() );
+
+ if ( !m_bSupportsViews )
+ aNormalizedTypes.erase( cppu::UnoType<XViewsSupplier>::get() );
+ if ( !m_bSupportsUsers )
+ aNormalizedTypes.erase( cppu::UnoType<XUsersSupplier>::get() );
+ if ( !m_bSupportsGroups )
+ aNormalizedTypes.erase( cppu::UnoType<XGroupsSupplier>::get() );
+
+ return comphelper::containerToSequence(aNormalizedTypes);
+}
+
+Sequence< sal_Int8 > OConnection::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OConnection::queryInterface( const Type & rType )
+{
+ if ( !m_bSupportsViews && rType.equals( cppu::UnoType<XViewsSupplier>::get() ) )
+ return Any();
+ else if ( !m_bSupportsUsers && rType.equals( cppu::UnoType<XUsersSupplier>::get() ) )
+ return Any();
+ else if ( !m_bSupportsGroups && rType.equals( cppu::UnoType<XGroupsSupplier>::get() ) )
+ return Any();
+ Any aReturn = OSubComponent::queryInterface( rType );
+ if (!aReturn.hasValue())
+ {
+ aReturn = OConnection_Base::queryInterface( rType );
+ if (!aReturn.hasValue())
+ aReturn = OConnectionWrapper::queryInterface( rType );
+ }
+ return aReturn;
+}
+
+void OConnection::acquire() noexcept
+{
+ // include this one when you want to see who calls it (call graph)
+ OSubComponent::acquire();
+}
+
+void OConnection::release() noexcept
+{
+ // include this one when you want to see who calls it (call graph)
+ OSubComponent::release();
+}
+
+// OSubComponent
+void OConnection::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ OSubComponent::disposing();
+ OConnectionWrapper::disposing();
+
+ for (auto const& statement : m_aStatements)
+ {
+ Reference<XComponent> xComp(statement.get(),UNO_QUERY);
+ ::comphelper::disposeComponent(xComp);
+ }
+ m_aStatements.clear();
+ m_xMasterTables = nullptr;
+
+ if(m_pTables)
+ m_pTables->dispose();
+ if(m_pViews)
+ m_pViews->dispose();
+
+ ::comphelper::disposeComponent(m_xQueries);
+
+ for (auto const& composer : m_aComposers)
+ {
+ Reference<XComponent> xComp(composer.get(),UNO_QUERY);
+ ::comphelper::disposeComponent(xComp);
+ }
+
+ m_aComposers.clear();
+
+ try
+ {
+ if (m_xMasterConnection.is())
+ m_xMasterConnection->close();
+ }
+ catch(const Exception&)
+ {
+ }
+ m_xMasterConnection = nullptr;
+}
+
+// XChild
+Reference< XInterface > OConnection::getParent()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xParent;
+}
+
+void OConnection::setParent(const Reference< XInterface > & /*Parent*/)
+{
+ throw NoSupportException();
+}
+
+// XSQLQueryComposerFactory
+Reference< XSQLQueryComposer > OConnection::createQueryComposer()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ // Reference< XNumberFormatsSupplier > xSupplier = pParent->getNumberFormatsSupplier();
+ Reference< XSQLQueryComposer > xComposer( new OQueryComposer( this ) );
+ m_aComposers.emplace_back(xComposer);
+ return xComposer;
+}
+
+void OConnection::impl_fillTableFilter()
+{
+ Reference<XPropertySet> xProp(getParent(),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= m_aTableFilter;
+ xProp->getPropertyValue(PROPERTY_TABLETYPEFILTER) >>= m_aTableTypeFilter;
+ }
+}
+
+void OConnection::refresh(const Reference< XNameAccess >& _rToBeRefreshed)
+{
+ if ( _rToBeRefreshed == Reference< XNameAccess >(m_pTables.get()) )
+ {
+ if (m_pTables && !m_pTables->isInitialized())
+ {
+ impl_fillTableFilter();
+ // check if our "master connection" can supply tables
+ getMasterTables();
+
+ if (m_xMasterTables.is() && m_xMasterTables->getTables().is())
+ { // yes -> wrap them
+ m_pTables->construct(m_xMasterTables->getTables(),m_aTableFilter, m_aTableTypeFilter);
+ }
+ else
+ { // no -> use an own container
+ m_pTables->construct(m_aTableFilter, m_aTableTypeFilter);
+ }
+ }
+ }
+ else if ( _rToBeRefreshed == Reference< XNameAccess >(m_pViews.get()) )
+ {
+ if (m_pViews && !m_pViews->isInitialized())
+ {
+ impl_fillTableFilter();
+ // check if our "master connection" can supply tables
+ Reference< XViewsSupplier > xMaster(getMasterTables(),UNO_QUERY);
+
+ if (xMaster.is() && xMaster->getViews().is())
+ m_pViews->construct(xMaster->getViews(),m_aTableFilter, m_aTableTypeFilter);
+ else
+ m_pViews->construct(m_aTableFilter, m_aTableTypeFilter);
+ }
+ }
+}
+
+// XTablesSupplier
+Reference< XNameAccess > OConnection::getTables()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ refresh(m_pTables.get());
+
+ return m_pTables.get();
+}
+
+Reference< XNameAccess > SAL_CALL OConnection::getViews( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ refresh(m_pViews.get());
+
+ return m_pViews.get();
+}
+
+// XQueriesSupplier
+Reference< XNameAccess > OConnection::getQueries()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ return m_xQueries;
+}
+
+// css::sdb::XCommandPreparation
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareCommand( const OUString& command, sal_Int32 commandType )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ OUString aStatement;
+ switch (commandType)
+ {
+ case CommandType::TABLE:
+ {
+ aStatement = "SELECT * FROM ";
+
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents( getMetaData(), command, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
+ aStatement += ::dbtools::composeTableNameForSelect( this, sCatalog, sSchema, sTable );
+ }
+ break;
+ case CommandType::QUERY:
+ if ( m_xQueries->hasByName(command) )
+ {
+ Reference< XPropertySet > xQuery(m_xQueries->getByName(command),UNO_QUERY);
+ xQuery->getPropertyValue(PROPERTY_COMMAND) >>= aStatement;
+ }
+ break;
+ default:
+ aStatement = command;
+ }
+ // TODO EscapeProcessing
+ return prepareStatement(aStatement);
+}
+
+Reference< XInterface > SAL_CALL OConnection::createInstance( const OUString& _sServiceSpecifier )
+{
+ Reference< XServiceInfo > xRet;
+ if ( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER == _sServiceSpecifier || _sServiceSpecifier == "com.sun.star.sdb.SingleSelectQueryAnalyzer" )
+ {
+ xRet = new OSingleSelectQueryComposer( getTables(),this, m_aContext );
+ m_aComposers.emplace_back(xRet);
+ }
+ else
+ {
+ if ( !_sServiceSpecifier.isEmpty() )
+ {
+ TSupportServices::const_iterator aFind = m_aSupportServices.find(_sServiceSpecifier);
+ if ( aFind == m_aSupportServices.end() )
+ {
+ Reference<XConnection> xMy(this);
+ Sequence<Any> aArgs{ Any(NamedValue("ActiveConnection",Any(xMy))) };
+ aFind = m_aSupportServices.emplace(
+ _sServiceSpecifier,
+ m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(_sServiceSpecifier, aArgs, m_aContext)
+ ).first;
+ }
+ return aFind->second;
+ }
+ }
+ return Reference<XInterface>(xRet, UNO_QUERY);
+}
+
+Reference< XInterface > SAL_CALL OConnection::createInstanceWithArguments( const OUString& _sServiceSpecifier, const Sequence< Any >& /*Arguments*/ )
+{
+ return createInstance(_sServiceSpecifier);
+}
+
+Sequence< OUString > SAL_CALL OConnection::getAvailableServiceNames( )
+{
+ Sequence< OUString > aRet { SERVICE_NAME_SINGLESELECTQUERYCOMPOSER };
+ return aRet;
+}
+
+Reference< XTablesSupplier > const & OConnection::getMasterTables()
+{
+// check if out "master connection" can supply tables
+ if(!m_xMasterTables.is())
+ {
+ try
+ {
+ Reference<XDatabaseMetaData> xMeta = getMetaData();
+ if ( xMeta.is() )
+ m_xMasterTables = ::dbtools::getDataDefinitionByURLAndConnection( xMeta->getURL(), m_xMasterConnection, m_aContext );
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ return m_xMasterTables;
+}
+
+// XUsersSupplier
+Reference< XNameAccess > SAL_CALL OConnection::getUsers( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ Reference<XUsersSupplier> xUsr(getMasterTables(),UNO_QUERY);
+ return xUsr.is() ? xUsr->getUsers() : Reference< XNameAccess >();
+}
+
+// XGroupsSupplier
+Reference< XNameAccess > SAL_CALL OConnection::getGroups( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ Reference<XGroupsSupplier> xGrp(getMasterTables(),UNO_QUERY);
+ return xGrp.is() ? xGrp->getGroups() : Reference< XNameAccess >();
+}
+
+void OConnection::impl_loadConnectionTools_throw()
+{
+ m_xConnectionTools = css::sdb::tools::ConnectionTools::createWithConnection( m_aContext, this );
+}
+
+Reference< XTableName > SAL_CALL OConnection::createTableName( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->createTableName();
+}
+
+Reference< XObjectNames > SAL_CALL OConnection::getObjectNames( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getObjectNames();
+}
+
+Reference< XDataSourceMetaData > SAL_CALL OConnection::getDataSourceMetaData( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getDataSourceMetaData();
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OConnection::getFieldsByCommandDescriptor( ::sal_Int32 commandType, const OUString& command, css::uno::Reference< css::lang::XComponent >& keepFieldsAlive )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getFieldsByCommandDescriptor(commandType,command,keepFieldsAlive);
+}
+
+Reference< XSingleSelectQueryComposer > SAL_CALL OConnection::getComposer( ::sal_Int32 commandType, const OUString& command )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getComposer(commandType,command);
+}
+
+void OConnection::impl_checkTableQueryNames_nothrow()
+{
+ DatabaseMetaData aMeta( static_cast< XConnection* >( this ) );
+ if ( !aMeta.supportsSubqueriesInFrom() )
+ // nothing to do
+ return;
+
+ try
+ {
+ Reference< XNameAccess > xTables( getTables() );
+ const Sequence< OUString > aTableNames( xTables->getElementNames() );
+ std::set< OUString > aSortedTableNames( aTableNames.begin(), aTableNames.end() );
+
+ Reference< XNameAccess > xQueries( getQueries() );
+ const Sequence< OUString > aQueryNames( xQueries->getElementNames() );
+
+ for ( auto const & queryName : aQueryNames )
+ {
+ if ( aSortedTableNames.find( queryName ) != aSortedTableNames.end() )
+ {
+ OUString sConflictWarning( DBA_RES( RID_STR_CONFLICTING_NAMES ) );
+ m_aWarnings.appendWarning( sConflictWarning, "01SB0", *this );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference< XGraphic > SAL_CALL OConnection::getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode )
+{
+ Reference< XGraphic > xReturn;
+
+ // ask our aggregate
+ if ( m_xTableUIProvider.is() )
+ xReturn = m_xTableUIProvider->getTableIcon( TableName, ColorMode );
+
+ // ask ourself
+ // well, we don't have own functionality here ...
+ // In the future, we might decide to delegate the complete handling to this interface.
+ // In this case, we would need to load the icon here.
+
+ return xReturn;
+}
+
+Reference< XInterface > SAL_CALL OConnection::getTableEditor( const Reference< XDatabaseDocumentUI >& DocumentUI, const OUString& TableName )
+{
+ Reference< XInterface > xReturn;
+
+ // ask our aggregate
+ if ( m_xTableUIProvider.is() )
+ xReturn = m_xTableUIProvider->getTableEditor( DocumentUI, TableName );
+
+ // ask ourself
+ // well, we don't have own functionality here ...
+ // In the future, we might decide to delegate the complete handling to this interface.
+ // In this case, we would need to instantiate a css.sdb.TableDesign here.
+
+ return xReturn;
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/connection.hxx b/dbaccess/source/core/dataaccess/connection.hxx
new file mode 100644
index 000000000..4ecfa7d70
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/connection.hxx
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+#include <map>
+
+#include <apitools.hxx>
+#include <querycontainer.hxx>
+#include <tablecontainer.hxx>
+#include <viewcontainer.hxx>
+#include <RefreshListener.hxx>
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
+#include <com/sun/star/sdb/XCommandPreparation.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XGroupsSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/tools/XConnectionTools.hpp>
+#include <com/sun/star/sdb/application/XTableUIProvider.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+
+#include <cppuhelper/implbase13.hxx>
+#include <connectivity/ConnectionWrapper.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/warningscontainer.hxx>
+
+namespace dbaccess
+{
+
+typedef cppu::ImplHelper13 < css::container::XChild
+ , css::sdbcx::XTablesSupplier
+ , css::sdbcx::XViewsSupplier
+ , css::sdbc::XConnection
+ , css::sdbc::XWarningsSupplier
+ , css::sdb::XQueriesSupplier
+ , css::sdb::XSQLQueryComposerFactory
+ , css::sdb::XCommandPreparation
+ , css::lang::XMultiServiceFactory
+ , css::sdbcx::XUsersSupplier
+ , css::sdbcx::XGroupsSupplier
+ , css::sdb::tools::XConnectionTools
+ , css::sdb::application::XTableUIProvider
+ > OConnection_Base;
+
+class ODatabaseSource;
+// OConnection
+class OConnection final :public ::cppu::BaseMutex
+ ,public OSubComponent
+ ,public ::connectivity::OConnectionWrapper
+ ,public OConnection_Base
+ ,public IRefreshListener
+{
+ css::uno::Reference< css::sdbcx::XTablesSupplier >
+ m_xMasterTables; // just to avoid the recreation of the catalog
+ connectivity::OWeakRefArray m_aStatements;
+ css::uno::Reference< css::container::XNameAccess >
+ m_xQueries;
+ connectivity::OWeakRefArray m_aComposers;
+
+ // the filter as set on the parent data link at construction of the connection
+ css::uno::Sequence< OUString > m_aTableFilter;
+ css::uno::Sequence< OUString > m_aTableTypeFilter;
+ css::uno::Reference< css::uno::XComponentContext > m_aContext;
+ css::uno::Reference< css::sdbc::XConnection > m_xMasterConnection;
+ css::uno::Reference< css::sdb::tools::XConnectionTools > m_xConnectionTools;
+ css::uno::Reference< css::sdb::application::XTableUIProvider > m_xTableUIProvider;
+
+ // defines the helper services for example to query the command of a view
+ // @ see com.sun.star.sdb.tools.XViewAccess
+ typedef std::map< OUString, css::uno::Reference< css::uno::XInterface> > TSupportServices;
+ TSupportServices m_aSupportServices;
+
+ std::unique_ptr<OTableContainer> m_pTables;
+ std::unique_ptr<OViewContainer> m_pViews;
+ ::dbtools::WarningsContainer m_aWarnings;
+ std::atomic<std::size_t> m_nInAppend;
+ bool m_bSupportsViews; // true when the getTableTypes return "VIEW" as type
+ bool m_bSupportsUsers;
+ bool m_bSupportsGroups;
+
+ virtual ~OConnection() override;
+public:
+ OConnection(ODatabaseSource& _rDB
+ ,css::uno::Reference< css::sdbc::XConnection > const & _rxMaster
+ ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+// css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+// css::sdbcx::XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+// css::sdbcx::XViewsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getViews( ) override;
+
+// css::sdb::XQueriesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getQueries( ) override;
+
+// css::sdb::XSQLQueryComposerFactory
+ virtual css::uno::Reference< css::sdb::XSQLQueryComposer > SAL_CALL createQueryComposer( ) override;
+
+// css::sdb::XCommandPreparation
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCommand( const OUString& command, sal_Int32 commandType ) override;
+
+// css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+// css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XMultiServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( const OUString& aServiceSpecifier ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const OUString& ServiceSpecifier, const css::uno::Sequence< css::uno::Any >& Arguments ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames( ) override;
+
+ // XUsersSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getUsers( ) override;
+ // XGroupsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getGroups( ) override;
+
+ // XConnectionTools
+ virtual css::uno::Reference< css::sdb::tools::XTableName > SAL_CALL createTableName( ) override;
+ virtual css::uno::Reference< css::sdb::tools::XObjectNames > SAL_CALL getObjectNames( ) override;
+ virtual css::uno::Reference< css::sdb::tools::XDataSourceMetaData > SAL_CALL getDataSourceMetaData( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getFieldsByCommandDescriptor( ::sal_Int32 commandType, const OUString& command, css::uno::Reference< css::lang::XComponent >& keepFieldsAlive ) override;
+ virtual css::uno::Reference< css::sdb::XSingleSelectQueryComposer > SAL_CALL getComposer( ::sal_Int32 commandType, const OUString& command ) override;
+
+ // XTableUIProvider
+ virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getTableEditor( const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) override;
+
+ // IRefreshListener
+ virtual void refresh(const css::uno::Reference< css::container::XNameAccess >& _rToBeRefreshed) override;
+
+private:
+ /// @throws css::lang::DisposedException
+ void checkDisposed()
+ {
+ if ( rBHelper.bDisposed || !m_xConnection.is() )
+ throw css::lang::DisposedException();
+ }
+
+ css::uno::Reference< css::sdbcx::XTablesSupplier > const & getMasterTables();
+
+ /** checks whether or not there are naming conflicts between tables and queries
+ */
+ void impl_checkTableQueryNames_nothrow();
+
+ /** loads the XConnectionTools implementation which we forward the respective functionality to
+
+ @throws css::uno::RuntimeException
+ if the implementation cannot be loaded
+
+ @postcond
+ m_xConnectionTools is nol <NULL/>
+ */
+ void impl_loadConnectionTools_throw();
+
+ /** reads the table filter and table type filter from the datasource
+ */
+ void impl_fillTableFilter();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx
new file mode 100644
index 000000000..ef5239a67
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdb/XDataAccessDescriptorFactory.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+namespace
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdbc::XResultSet;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::PropertyValue;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+
+ // DataAccessDescriptor
+ typedef ::comphelper::OMutexAndBroadcastHelper DataAccessDescriptor_MutexBase;
+
+ typedef ::cppu::WeakImplHelper< XServiceInfo
+ > DataAccessDescriptor_TypeBase;
+
+ typedef ::comphelper::OPropertyContainer DataAccessDescriptor_PropertyBase;
+
+ class DataAccessDescriptor :public DataAccessDescriptor_MutexBase
+ ,public DataAccessDescriptor_TypeBase
+ ,public DataAccessDescriptor_PropertyBase
+ ,public ::comphelper::OPropertyArrayUsageHelper< DataAccessDescriptor >
+ {
+ public:
+ DataAccessDescriptor();
+
+ // UNO
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ protected:
+ virtual ~DataAccessDescriptor() override;
+
+ protected:
+ // XPropertySet
+ virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ private:
+ // </properties>
+ OUString m_sDataSourceName;
+ OUString m_sDatabaseLocation;
+ OUString m_sConnectionResource;
+ Sequence< PropertyValue > m_aConnectionInfo;
+ Reference< XConnection > m_xActiveConnection;
+ OUString m_sCommand;
+ sal_Int32 m_nCommandType;
+ OUString m_sFilter;
+ OUString m_sOrder;
+ OUString m_sHavingClause;
+ OUString m_sGroupBy;
+ bool m_bEscapeProcessing;
+ Reference< XResultSet > m_xResultSet;
+ Sequence< Any > m_aSelection;
+ bool m_bBookmarkSelection;
+ OUString m_sColumnName;
+ Reference< XPropertySet > m_xColumn;
+ // </properties>
+ };
+
+ DataAccessDescriptor::DataAccessDescriptor()
+ :DataAccessDescriptor_PropertyBase( m_aBHelper )
+ ,m_nCommandType( CommandType::COMMAND )
+ ,m_bEscapeProcessing( true )
+ ,m_bBookmarkSelection( true )
+ {
+ registerProperty(PROPERTY_DATASOURCENAME, PROPERTY_ID_DATASOURCENAME, PropertyAttribute::BOUND, &m_sDataSourceName , cppu::UnoType<decltype(m_sDataSourceName )>::get());
+ registerProperty(PROPERTY_DATABASE_LOCATION, PROPERTY_ID_DATABASE_LOCATION, PropertyAttribute::BOUND, &m_sDatabaseLocation , cppu::UnoType<decltype(m_sDatabaseLocation )>::get());
+ registerProperty(PROPERTY_CONNECTION_RESOURCE, PROPERTY_ID_CONNECTION_RESOURCE, PropertyAttribute::BOUND, &m_sConnectionResource , cppu::UnoType<decltype(m_sConnectionResource )>::get());
+ registerProperty(PROPERTY_CONNECTION_INFO, PROPERTY_ID_CONNECTION_INFO, PropertyAttribute::BOUND, &m_aConnectionInfo , cppu::UnoType<decltype(m_aConnectionInfo )>::get());
+ registerProperty(PROPERTY_ACTIVE_CONNECTION, PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::BOUND, &m_xActiveConnection , cppu::UnoType<decltype(m_xActiveConnection )>::get());
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, &m_sCommand , cppu::UnoType<decltype(m_sCommand )>::get());
+ registerProperty(PROPERTY_COMMAND_TYPE, PROPERTY_ID_COMMAND_TYPE, PropertyAttribute::BOUND, &m_nCommandType , cppu::UnoType<decltype(m_nCommandType )>::get());
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND, &m_sFilter , cppu::UnoType<decltype(m_sFilter )>::get());
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, &m_sOrder , cppu::UnoType<decltype(m_sOrder )>::get());
+ registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND, &m_sHavingClause , cppu::UnoType<decltype(m_sHavingClause )>::get());
+ registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND, &m_sGroupBy , cppu::UnoType<decltype(m_sGroupBy )>::get());
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, &m_bEscapeProcessing , cppu::UnoType<decltype(m_bEscapeProcessing )>::get());
+ registerProperty(PROPERTY_RESULT_SET, PROPERTY_ID_RESULT_SET, PropertyAttribute::BOUND, &m_xResultSet , cppu::UnoType<decltype(m_xResultSet )>::get());
+ registerProperty(PROPERTY_SELECTION, PROPERTY_ID_SELECTION, PropertyAttribute::BOUND, &m_aSelection , cppu::UnoType<decltype(m_aSelection )>::get());
+ registerProperty(PROPERTY_BOOKMARK_SELECTION, PROPERTY_ID_BOOKMARK_SELECTION, PropertyAttribute::BOUND, &m_bBookmarkSelection , cppu::UnoType<decltype(m_bBookmarkSelection )>::get());
+ registerProperty(PROPERTY_COLUMN_NAME, PROPERTY_ID_COLUMN_NAME, PropertyAttribute::BOUND, &m_sColumnName , cppu::UnoType<decltype(m_sColumnName )>::get());
+ registerProperty(PROPERTY_COLUMN, PROPERTY_ID_COLUMN, PropertyAttribute::BOUND, &m_xColumn , cppu::UnoType<decltype(m_xColumn )>::get());
+ }
+
+ DataAccessDescriptor::~DataAccessDescriptor()
+ {
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2( DataAccessDescriptor, DataAccessDescriptor_TypeBase, DataAccessDescriptor_PropertyBase );
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( DataAccessDescriptor, DataAccessDescriptor_TypeBase, DataAccessDescriptor_PropertyBase );
+
+ OUString SAL_CALL DataAccessDescriptor::getImplementationName()
+ {
+ return "com.sun.star.comp.dba.DataAccessDescriptor";
+ }
+
+ sal_Bool SAL_CALL DataAccessDescriptor::supportsService( const OUString& rServiceName )
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL DataAccessDescriptor::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.sdb.DataAccessDescriptor" };
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL DataAccessDescriptor::getPropertySetInfo()
+ {
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+ ::cppu::IPropertyArrayHelper& DataAccessDescriptor::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* DataAccessDescriptor::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+ // DataAccessDescriptorFactory
+ class DataAccessDescriptorFactory: public ::cppu::WeakImplHelper<XServiceInfo, css::sdb::XDataAccessDescriptorFactory>
+ {
+ public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDataAccessDescriptorFactory
+ virtual Reference< XPropertySet > SAL_CALL createDataAccessDescriptor( ) override;
+
+ DataAccessDescriptorFactory();
+ };
+
+ DataAccessDescriptorFactory::DataAccessDescriptorFactory()
+ {
+ }
+
+ OUString SAL_CALL DataAccessDescriptorFactory::getImplementationName()
+ {
+ return "com.sun.star.comp.dba.DataAccessDescriptorFactory";
+ }
+
+ sal_Bool SAL_CALL DataAccessDescriptorFactory::supportsService( const OUString& rServiceName )
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL DataAccessDescriptorFactory::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.DataAccessDescriptorFactory" };
+ }
+
+ Reference< XPropertySet > SAL_CALL DataAccessDescriptorFactory::createDataAccessDescriptor( )
+ {
+ return new DataAccessDescriptor();
+ }
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_dba_DataAccessDescriptorFactory(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new DataAccessDescriptorFactory());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databasecontext.cxx b/dbaccess/source/core/dataaccess/databasecontext.cxx
new file mode 100644
index 000000000..5afdadb67
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databasecontext.cxx
@@ -0,0 +1,753 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <databasecontext.hxx>
+#include "databaseregistrations.hxx"
+#include "datasource.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/TerminationVetoException.hpp>
+#include <com/sun/star/frame/XLoadable.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/registry/InvalidRegistryException.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/task/InteractionClassification.hpp>
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+
+#include <basic/basmgr.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/uri.hxx>
+#include <sal/log.hxx>
+#include <svl/filenotation.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <rtl/ref.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <vector>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::registry;
+using namespace ::com::sun::star;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::utl;
+
+using ::com::sun::star::task::InteractionClassification_ERROR;
+using ::com::sun::star::ucb::IOErrorCode_NO_FILE;
+using ::com::sun::star::ucb::InteractiveIOException;
+using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING;
+using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING_PATH;
+
+namespace dbaccess
+{
+
+ typedef ::cppu::WeakImplHelper< XTerminateListener
+ > DatabaseDocumentLoader_Base;
+ class DatabaseDocumentLoader : public DatabaseDocumentLoader_Base
+ {
+ private:
+ Reference< XDesktop2 > m_xDesktop;
+ std::vector< const ODatabaseModelImpl* > m_aDatabaseDocuments;
+
+ public:
+ explicit DatabaseDocumentLoader( const Reference<XComponentContext> & rxContext);
+
+ void append(const ODatabaseModelImpl& _rModelImpl )
+ {
+ m_aDatabaseDocuments.emplace_back(&_rModelImpl);
+ }
+
+ void remove(const ODatabaseModelImpl& _rModelImpl)
+ {
+ m_aDatabaseDocuments.erase(std::find(m_aDatabaseDocuments.begin(), m_aDatabaseDocuments.end(), &_rModelImpl));
+ }
+
+
+ private:
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const lang::EventObject& Event ) override;
+ virtual void SAL_CALL notifyTermination( const lang::EventObject& Event ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ };
+
+ DatabaseDocumentLoader::DatabaseDocumentLoader( const Reference<XComponentContext> & rxContext )
+ {
+ try
+ {
+ m_xDesktop.set( Desktop::create(rxContext) );
+ m_xDesktop->addTerminateListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void SAL_CALL DatabaseDocumentLoader::queryTermination( const lang::EventObject& /*Event*/ )
+ {
+ std::vector< const ODatabaseModelImpl* > aCpy(m_aDatabaseDocuments);
+ for( const auto& pCopy : aCpy )
+ {
+ try
+ {
+ const Reference< XModel2 > xMod( pCopy->getModel_noCreate(),
+ UNO_QUERY_THROW );
+ if( !xMod->getControllers()->hasMoreElements() )
+ {
+ Reference< util::XCloseable > xClose( xMod,
+ UNO_QUERY_THROW );
+ xClose->close( false );
+ }
+ }
+ catch( const CloseVetoException& )
+ {
+ throw TerminationVetoException();
+ }
+ }
+ }
+
+ void SAL_CALL DatabaseDocumentLoader::notifyTermination( const lang::EventObject& /*Event*/ )
+ {
+ }
+
+ void SAL_CALL DatabaseDocumentLoader::disposing( const lang::EventObject& /*Source*/ )
+ {
+ }
+
+// ODatabaseContext
+
+ODatabaseContext::ODatabaseContext( const Reference< XComponentContext >& _rxContext )
+ :DatabaseAccessContext_Base(m_aMutex)
+ ,m_aContext( _rxContext )
+ ,m_aContainerListeners(m_aMutex)
+{
+ m_xDatabaseDocumentLoader = new DatabaseDocumentLoader( _rxContext );
+
+#if HAVE_FEATURE_SCRIPTING
+ ::basic::BasicManagerRepository::registerCreationListener( *this );
+#endif
+
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xDBRegistrationAggregate.set( createDataSourceRegistrations( m_aContext ), UNO_SET_THROW );
+ m_xDatabaseRegistrations.set( m_xDBRegistrationAggregate, UNO_QUERY_THROW );
+
+ m_xDBRegistrationAggregate->setDelegator( *this );
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+ODatabaseContext::~ODatabaseContext()
+{
+#if HAVE_FEATURE_SCRIPTING
+ ::basic::BasicManagerRepository::revokeCreationListener( *this );
+#endif
+
+ m_xDatabaseDocumentLoader.clear();
+ m_xDBRegistrationAggregate->setDelegator( nullptr );
+ m_xDBRegistrationAggregate.clear();
+ m_xDatabaseRegistrations.clear();
+}
+
+// XServiceInfo
+OUString ODatabaseContext::getImplementationName( )
+{
+ return "com.sun.star.comp.dba.ODatabaseContext";
+}
+
+sal_Bool ODatabaseContext::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > ODatabaseContext::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.DatabaseContext" };
+}
+
+Reference< XInterface > ODatabaseContext::impl_createNewDataSource()
+{
+ ::rtl::Reference pImpl( new ODatabaseModelImpl( m_aContext, *this ) );
+ Reference< XDataSource > xDataSource( pImpl->getOrCreateDataSource() );
+
+ return xDataSource;
+}
+
+Reference< XInterface > SAL_CALL ODatabaseContext::createInstance( )
+{
+ // for convenience of the API user, we ensure the document is fully initialized (effectively: XLoadable::initNew
+ // has been called at the DatabaseDocument).
+ return impl_createNewDataSource();
+}
+
+Reference< XInterface > SAL_CALL ODatabaseContext::createInstanceWithArguments( const Sequence< Any >& _rArguments )
+{
+ ::comphelper::NamedValueCollection aArgs( _rArguments );
+ OUString sURL = aArgs.getOrDefault( INFO_POOLURL, OUString() );
+
+ Reference< XInterface > xDataSource;
+ if ( !sURL.isEmpty() )
+ xDataSource = getObject( sURL );
+
+ if ( !xDataSource.is() )
+ xDataSource = impl_createNewDataSource();
+
+ return xDataSource;
+}
+
+// DatabaseAccessContext_Base
+void ODatabaseContext::disposing()
+{
+ // notify our listener
+ css::lang::EventObject aDisposeEvent(static_cast< XContainer* >(this));
+ m_aContainerListeners.disposeAndClear(aDisposeEvent);
+
+ // dispose the data sources
+ // disposing seems to remove elements, so work on copy for valid iterators
+ ObjectCache objCopy;
+ objCopy.swap(m_aDatabaseObjects);
+ for (auto const& elem : objCopy)
+ {
+ rtl::Reference< ODatabaseModelImpl > obj(elem.second);
+ // make sure obj is acquired and does not delete itself from within
+ // dispose()
+ obj->dispose();
+ }
+}
+
+// XNamingService
+Reference< XInterface > ODatabaseContext::getRegisteredObject(const OUString& _rName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ OUString sURL( getDatabaseLocation( _rName ) );
+
+ if ( sURL.isEmpty() )
+ // there is a registration for this name, but no URL
+ throw IllegalArgumentException();
+
+ // check if URL is already loaded
+ Reference< XInterface > xExistent = getObject( sURL );
+ if ( xExistent.is() )
+ return xExistent;
+
+ return loadObjectFromURL( _rName, sURL );
+}
+
+Reference< XInterface > ODatabaseContext::loadObjectFromURL(const OUString& _rName,const OUString& _sURL)
+{
+ INetURLObject aURL( _sURL );
+
+ if ( aURL.GetProtocol() == INetProtocol::NotValid )
+ throw NoSuchElementException( _rName, *this );
+
+ bool bEmbeddedDataSource = aURL.isSchemeEqualTo(INetProtocol::VndSunStarPkg);
+ try
+ {
+ if (!bEmbeddedDataSource)
+ {
+ ::ucbhelper::Content aContent( _sURL, nullptr, comphelper::getProcessComponentContext() );
+ if ( !aContent.isDocument() )
+ throw InteractiveIOException(
+ _sURL, *this, InteractionClassification_ERROR, IOErrorCode_NO_FILE
+ );
+ }
+ }
+ catch ( const InteractiveIOException& e )
+ {
+ if ( ( e.Code == IOErrorCode_NO_FILE )
+ || ( e.Code == IOErrorCode_NOT_EXISTING )
+ || ( e.Code == IOErrorCode_NOT_EXISTING_PATH )
+ )
+ {
+ // #i40463# #i39187#
+ OUString sErrorMessage( DBA_RES( RID_STR_FILE_DOES_NOT_EXIST ) );
+ ::svt::OFileNotation aTransformer( _sURL );
+
+ SQLException aError;
+ aError.Message = sErrorMessage.replaceAll( "$file$", aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) );
+
+ throw WrappedTargetException( _sURL, *this, Any( aError ) );
+ }
+ throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
+ }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
+ }
+
+ OSL_ENSURE( m_aDatabaseObjects.find( _sURL ) == m_aDatabaseObjects.end(),
+ "ODatabaseContext::loadObjectFromURL: not intended for already-cached objects!" );
+
+ ::rtl::Reference< ODatabaseModelImpl > pModelImpl;
+ {
+ pModelImpl.set( new ODatabaseModelImpl( _rName, m_aContext, *this ) );
+
+ Reference< XModel > xModel( pModelImpl->createNewModel_deliverOwnership(), UNO_SET_THROW );
+ Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
+
+ ::comphelper::NamedValueCollection aArgs;
+ aArgs.put( "URL", _sURL );
+ aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
+ aArgs.put( "InteractionHandler", task::InteractionHandler::createWithParent(m_aContext, nullptr) );
+ if (bEmbeddedDataSource)
+ {
+ // In this case the host contains the real path, and the path is the embedded stream name.
+ auto const uri = css::uri::UriReferenceFactory::create(m_aContext)->parse(_sURL);
+ if (uri.is() && uri->isAbsolute()
+ && uri->hasAuthority() && !uri->hasQuery() && !uri->hasFragment())
+ {
+ auto const auth = uri->getAuthority();
+ auto const decAuth = rtl::Uri::decode(
+ auth, rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8);
+ if (auth.isEmpty() == decAuth.isEmpty()) {
+ // Decoding of auth to UTF-8 succeeded:
+ OUString sBaseURI = decAuth + uri->getPath();
+ aArgs.put("BaseURI", sBaseURI);
+ } else {
+ SAL_WARN(
+ "dbaccess.core",
+ "<" << _sURL << "> cannot be parse as vnd.sun.star.pkg URL");
+ }
+ } else {
+ SAL_WARN(
+ "dbaccess.core", "<" << _sURL << "> cannot be parse as vnd.sun.star.pkg URL");
+ }
+ }
+
+ Sequence< PropertyValue > aResource( aArgs.getPropertyValues() );
+ xLoad->load( aResource );
+ xModel->attachResource( _sURL, aResource );
+
+ ::utl::CloseableComponent aEnsureClose( xModel );
+ }
+
+ setTransientProperties( _sURL, *pModelImpl );
+
+ return pModelImpl->getOrCreateDataSource();
+}
+
+void ODatabaseContext::appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
+{
+ m_xDatabaseDocumentLoader->append(_rDataSourceModel);
+}
+
+void ODatabaseContext::removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
+{
+ m_xDatabaseDocumentLoader->remove(_rDataSourceModel);
+}
+
+void ODatabaseContext::setTransientProperties(const OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel )
+{
+ if ( m_aDatasourceProperties.end() == m_aDatasourceProperties.find(_sURL) )
+ return;
+ try
+ {
+ OUString sAuthFailedPassword;
+ Reference< XPropertySet > xDSProps( _rDataSourceModel.getOrCreateDataSource(), UNO_QUERY_THROW );
+ const Sequence< PropertyValue >& rSessionPersistentProps = m_aDatasourceProperties[_sURL];
+ for ( auto const & prop : rSessionPersistentProps )
+ {
+ if ( prop.Name == "AuthFailedPassword" )
+ {
+ OSL_VERIFY( prop.Value >>= sAuthFailedPassword );
+ }
+ else
+ {
+ xDSProps->setPropertyValue( prop.Name, prop.Value );
+ }
+ }
+
+ _rDataSourceModel.m_sFailedPassword = sAuthFailedPassword;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODatabaseContext::registerObject(const OUString& _rName, const Reference< XInterface > & _rxObject)
+{
+ if ( _rName.isEmpty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ Reference< XDocumentDataSource > xDocDataSource( _rxObject, UNO_QUERY );
+ Reference< XModel > xModel( xDocDataSource.is() ? xDocDataSource->getDatabaseDocument() : Reference< XOfficeDatabaseDocument >(), UNO_QUERY );
+ if ( !xModel.is() )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+
+ OUString sURL = xModel->getURL();
+ if ( sURL.isEmpty() )
+ throw IllegalArgumentException( DBA_RES( RID_STR_DATASOURCE_NOT_STORED ), *this, 2 );
+
+ { // avoid deadlocks: lock m_aMutex after checking arguments
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ registerDatabaseLocation( _rName, sURL );
+
+ ODatabaseSource::setName( xDocDataSource, _rName, ODatabaseSource::DBContextAccess() );
+ }
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_rName), Any(_rxObject), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+}
+
+void ODatabaseContext::storeTransientProperties( ODatabaseModelImpl& _rModelImpl)
+{
+ Reference< XPropertySet > xSource( _rModelImpl.getOrCreateDataSource(), UNO_QUERY );
+ ::comphelper::NamedValueCollection aRememberProps;
+
+ try
+ {
+ // get the info about the properties, check which ones are transient and not readonly
+ Reference< XPropertySetInfo > xSetInfo;
+ if (xSource.is())
+ xSetInfo = xSource->getPropertySetInfo();
+ Sequence< Property > aProperties;
+ if (xSetInfo.is())
+ aProperties = xSetInfo->getProperties();
+
+ for ( const Property& rProperty : std::as_const(aProperties) )
+ {
+ if ( ( ( rProperty.Attributes & PropertyAttribute::TRANSIENT) != 0 )
+ && ( ( rProperty.Attributes & PropertyAttribute::READONLY) == 0 )
+ )
+ {
+ // found such a property
+ aRememberProps.put( rProperty.Name, xSource->getPropertyValue( rProperty.Name ) );
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // additionally, remember the "failed password", which is not available as property
+ // #i86178#
+ aRememberProps.put( "AuthFailedPassword", _rModelImpl.m_sFailedPassword );
+
+ OUString sDocumentURL( _rModelImpl.getURL() );
+ if ( m_aDatabaseObjects.find( sDocumentURL ) != m_aDatabaseObjects.end() )
+ {
+ m_aDatasourceProperties[ sDocumentURL ] = aRememberProps.getPropertyValues();
+ }
+ else if ( m_aDatabaseObjects.find( _rModelImpl.m_sName ) != m_aDatabaseObjects.end() )
+ {
+ OSL_FAIL( "ODatabaseContext::storeTransientProperties: a database document register by name? This shouldn't happen anymore!" );
+ // all the code should have been changed so that registration is by URL only
+ m_aDatasourceProperties[ _rModelImpl.m_sName ] = aRememberProps.getPropertyValues();
+ }
+ else
+ {
+ OSL_ENSURE( sDocumentURL.isEmpty() && _rModelImpl.m_sName.isEmpty() ,
+ "ODatabaseContext::storeTransientProperties: a non-empty data source which I do not know?!" );
+ }
+}
+
+void SAL_CALL ODatabaseContext::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL ODatabaseContext::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+void ODatabaseContext::revokeObject(const OUString& _rName)
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ OUString sURL = getDatabaseLocation( _rName );
+
+ revokeDatabaseLocation( _rName );
+ // will throw if something goes wrong
+
+ if ( m_aDatabaseObjects.find( _rName ) != m_aDatabaseObjects.end() )
+ {
+ m_aDatasourceProperties[ sURL ] = m_aDatasourceProperties[ _rName ];
+ }
+
+ // check if URL is already loaded
+ ObjectCache::const_iterator aExistent = m_aDatabaseObjects.find( sURL );
+ if ( aExistent != m_aDatabaseObjects.end() )
+ m_aDatabaseObjects.erase( aExistent );
+
+ // notify our container listeners
+ ContainerEvent aEvent( *this, Any( _rName ), Any(), Any() );
+ aGuard.clear();
+ m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
+}
+
+sal_Bool SAL_CALL ODatabaseContext::hasRegisteredDatabase( const OUString& Name )
+{
+ return m_xDatabaseRegistrations->hasRegisteredDatabase( Name );
+}
+
+Sequence< OUString > SAL_CALL ODatabaseContext::getRegistrationNames()
+{
+ return m_xDatabaseRegistrations->getRegistrationNames();
+}
+
+OUString SAL_CALL ODatabaseContext::getDatabaseLocation( const OUString& Name )
+{
+ return m_xDatabaseRegistrations->getDatabaseLocation( Name );
+}
+
+void SAL_CALL ODatabaseContext::registerDatabaseLocation( const OUString& Name, const OUString& Location )
+{
+ m_xDatabaseRegistrations->registerDatabaseLocation( Name, Location );
+}
+
+void SAL_CALL ODatabaseContext::revokeDatabaseLocation( const OUString& Name )
+{
+ m_xDatabaseRegistrations->revokeDatabaseLocation( Name );
+}
+
+void SAL_CALL ODatabaseContext::changeDatabaseLocation( const OUString& Name, const OUString& NewLocation )
+{
+ m_xDatabaseRegistrations->changeDatabaseLocation( Name, NewLocation );
+}
+
+sal_Bool SAL_CALL ODatabaseContext::isDatabaseRegistrationReadOnly( const OUString& Name )
+{
+ return m_xDatabaseRegistrations->isDatabaseRegistrationReadOnly( Name );
+}
+
+void SAL_CALL ODatabaseContext::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+{
+ m_xDatabaseRegistrations->addDatabaseRegistrationsListener( Listener );
+}
+
+void SAL_CALL ODatabaseContext::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+{
+ m_xDatabaseRegistrations->removeDatabaseRegistrationsListener( Listener );
+}
+
+// css::container::XElementAccess
+Type ODatabaseContext::getElementType( )
+{
+ return cppu::UnoType<XDataSource>::get();
+}
+
+sal_Bool ODatabaseContext::hasElements()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ return getElementNames().hasElements();
+}
+
+// css::container::XEnumerationAccess
+Reference< css::container::XEnumeration > ODatabaseContext::createEnumeration()
+{
+ MutexGuard aGuard(m_aMutex);
+ return new ::comphelper::OEnumerationByName(static_cast<XNameAccess*>(this));
+}
+
+// css::container::XNameAccess
+Any ODatabaseContext::getByName(const OUString& _rName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+ if ( _rName.isEmpty() )
+ throw NoSuchElementException(_rName, *this);
+
+ try
+ {
+ Reference< XInterface > xExistent = getObject( _rName );
+ if ( xExistent.is() )
+ return Any( xExistent );
+
+ // see whether this is a registered name
+ OUString sURL;
+ if ( hasRegisteredDatabase( _rName ) )
+ {
+ sURL = getDatabaseLocation( _rName );
+ // is the object cached under its URL?
+ xExistent = getObject( sURL );
+ }
+ else
+ // interpret the name as URL
+ sURL = _rName;
+
+ if ( !xExistent.is() )
+ // try to load this as URL
+ xExistent = loadObjectFromURL( _rName, sURL );
+ return Any( xExistent );
+ }
+ catch (const NoSuchElementException&)
+ { // let these exceptions through
+ throw;
+ }
+ catch (const WrappedTargetException&)
+ { // let these exceptions through
+ throw;
+ }
+ catch (const RuntimeException&)
+ { // let these exceptions through
+ throw;
+ }
+ catch (const Exception&)
+ { // exceptions other than the specified ones -> wrap
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetException(_rName, *this, aError );
+ }
+}
+
+Sequence< OUString > ODatabaseContext::getElementNames()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ return getRegistrationNames();
+}
+
+sal_Bool ODatabaseContext::hasByName(const OUString& _rName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ return hasRegisteredDatabase( _rName );
+}
+
+Reference< XInterface > ODatabaseContext::getObject( const OUString& _rURL )
+{
+ ObjectCache::const_iterator aFind = m_aDatabaseObjects.find( _rURL );
+ Reference< XInterface > xExistent;
+ if ( aFind != m_aDatabaseObjects.end() )
+ xExistent = aFind->second->getOrCreateDataSource();
+ return xExistent;
+}
+
+void ODatabaseContext::registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl )
+{
+ OUString sURL( _rModelImpl.getURL() );
+ SAL_INFO("dbaccess.core", "DatabaseContext: registering " << sURL);
+ if ( m_aDatabaseObjects.find( sURL ) == m_aDatabaseObjects.end() )
+ {
+ m_aDatabaseObjects[ sURL ] = &_rModelImpl;
+ setTransientProperties( sURL, _rModelImpl );
+ }
+ else
+ OSL_FAIL( "ODatabaseContext::registerDatabaseDocument: already have an object registered for this URL!" );
+}
+
+void ODatabaseContext::revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl )
+{
+ const OUString& sURL( _rModelImpl.getURL() );
+ SAL_INFO("dbaccess.core", "DatabaseContext: deregistering " << sURL);
+ m_aDatabaseObjects.erase( sURL );
+}
+
+void ODatabaseContext::databaseDocumentURLChange( const OUString& _rOldURL, const OUString& _rNewURL )
+{
+ SAL_INFO("dbaccess.core", "DatabaseContext: changing registrations from " << _rOldURL <<
+ " to " << _rNewURL);
+ ObjectCache::const_iterator oldPos = m_aDatabaseObjects.find( _rOldURL );
+ ENSURE_OR_THROW( oldPos != m_aDatabaseObjects.end(), "illegal old database document URL" );
+ ObjectCache::const_iterator newPos = m_aDatabaseObjects.find( _rNewURL );
+ ENSURE_OR_THROW( newPos == m_aDatabaseObjects.end(), "illegal new database document URL" );
+
+ m_aDatabaseObjects[ _rNewURL ] = oldPos->second;
+ m_aDatabaseObjects.erase( oldPos );
+}
+
+sal_Int64 SAL_CALL ODatabaseContext::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & ODatabaseContext::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+void ODatabaseContext::onBasicManagerCreated( const Reference< XModel >& _rxForDocument, BasicManager& _rBasicManager )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) _rxForDocument;
+ (void) _rBasicManager;
+#else
+ // if it's a database document ...
+ Reference< XOfficeDatabaseDocument > xDatabaseDocument( _rxForDocument, UNO_QUERY );
+ // ... or a sub document of a database document ...
+ if ( !xDatabaseDocument.is() )
+ {
+ Reference< XChild > xDocAsChild( _rxForDocument, UNO_QUERY );
+ if ( xDocAsChild.is() )
+ xDatabaseDocument.set( xDocAsChild->getParent(), UNO_QUERY );
+ }
+
+ // ... whose BasicManager has just been created, then add the global DatabaseDocument variable to its scope.
+ if ( xDatabaseDocument.is() )
+ _rBasicManager.SetGlobalUNOConstant( "ThisDatabaseDocument", Any( xDatabaseDocument ) );
+#endif
+}
+
+} // namespace dbaccess
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ODatabaseContext_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new dbaccess::ODatabaseContext(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databasedocument.cxx b/dbaccess/source/core/dataaccess/databasedocument.cxx
new file mode 100644
index 000000000..419d02d2d
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databasedocument.cxx
@@ -0,0 +1,2211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include "databasedocument.hxx"
+#include "documenteventexecutor.hxx"
+#include <databasecontext.hxx>
+#include "documentcontainer.hxx"
+#include <sdbcoretools.hxx>
+#include <strings.hxx>
+#include <recovery/dbdocrecovery.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/document/XGraphicStorageHandler.hpp>
+#include <com/sun/star/document/GraphicStorageHandler.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/ui/UIConfigurationManager.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+
+#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/DialogProvider.hpp>
+
+#include <comphelper/documentconstants.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/genericpropertyset.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/numberedcollection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <comphelper/types.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <framework/titlehelper.hxx>
+#include <unotools/saveopt.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+
+#include <vcl/GraphicObject.hxx>
+#include <tools/urlobj.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::script::provider;
+using namespace ::com::sun::star::ui;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// ViewMonitor
+
+bool ViewMonitor::onControllerConnected( const Reference< XController >& _rxController )
+{
+ bool bFirstControllerEver = !m_bEverHadController;
+ m_bEverHadController = true;
+
+ m_xLastConnectedController = _rxController;
+ m_bLastIsFirstEverController = bFirstControllerEver;
+
+ return bFirstControllerEver;
+}
+
+bool ViewMonitor::onSetCurrentController( const Reference< XController >& _rxController )
+{
+ // we interpret this as "loading the document (including UI) is finished",
+ // if and only if this is the controller which was last connected, and it was the
+ // first controller ever connected
+ bool bLoadFinished = ( _rxController == m_xLastConnectedController ) && m_bLastIsFirstEverController;
+
+ // notify the respective events
+ if ( bLoadFinished )
+ m_rEventNotifier.notifyDocumentEventAsync( m_bIsNewDocument ? "OnNew" : "OnLoad" );
+
+ return bLoadFinished;
+}
+
+
+ODatabaseDocument::ODatabaseDocument(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl )
+ :ModelDependentComponent( _pImpl )
+ ,ODatabaseDocument_OfficeDocument( getMutex() )
+ ,m_aModifyListeners( getMutex() )
+ ,m_aCloseListener( getMutex() )
+ ,m_aStorageListeners( getMutex() )
+ ,m_pEventContainer( new DocumentEvents( *this, getMutex(), _pImpl->getDocumentEvents() ) )
+ ,m_aEventNotifier( *this, getMutex() )
+ ,m_aViewMonitor( m_aEventNotifier )
+ ,m_eInitState( NotInitialized )
+ ,m_bClosing( false )
+ ,m_bAllowDocumentScripting( false )
+ ,m_bHasBeenRecovered( false )
+ ,m_bEmbedded(false)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ impl_reparent_nothrow( m_xForms );
+ impl_reparent_nothrow( m_xReports );
+ impl_reparent_nothrow( m_pImpl->m_xTableDefinitions );
+ impl_reparent_nothrow( m_pImpl->m_xCommandDefinitions );
+
+ m_pEventExecutor = new DocumentEventExecutor( m_pImpl->m_aContext, this );
+ }
+ osl_atomic_decrement( &m_refCount );
+
+ // if there previously was a document instance for the same Impl which was already initialized,
+ // then consider ourself initialized, too.
+ // #i94840#
+ if ( !m_pImpl->hadInitializedDocument() )
+ return;
+
+ // Note we set our init-state to "Initializing", not "Initialized". We're created from inside the ModelImpl,
+ // which is expected to call attachResource in case there was a previous incarnation of the document,
+ // so we can properly finish our initialization then.
+ impl_setInitializing();
+
+ if ( !m_pImpl->getURL().isEmpty() )
+ {
+ // if the previous incarnation of the DatabaseDocument already had a URL, then creating this incarnation
+ // here is effectively loading the document.
+ // #i105505#
+ m_aViewMonitor.onLoadedDocument();
+ }
+}
+
+ODatabaseDocument::~ODatabaseDocument()
+{
+ if ( !ODatabaseDocument_OfficeDocument::rBHelper.bInDispose && !ODatabaseDocument_OfficeDocument::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+}
+
+Any SAL_CALL ODatabaseDocument::queryInterface( const Type& _rType )
+{
+ // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report
+ // which already contains macros. In this case, the database document itself is not
+ // allowed to contain macros, too.
+ if ( !m_bAllowDocumentScripting
+ && ( _rType.equals( cppu::UnoType<XEmbeddedScripts>::get() )
+ || _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() )
+ )
+ )
+ return Any();
+
+ Any aReturn = ODatabaseDocument_OfficeDocument::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ODatabaseDocument_Title::queryInterface(_rType);
+ return aReturn;
+}
+
+void SAL_CALL ODatabaseDocument::acquire( ) noexcept
+{
+ ODatabaseDocument_OfficeDocument::acquire();
+}
+
+void SAL_CALL ODatabaseDocument::release( ) noexcept
+{
+ ODatabaseDocument_OfficeDocument::release();
+}
+
+Sequence< Type > SAL_CALL ODatabaseDocument::getTypes( )
+{
+ Sequence< Type > aTypes = ::comphelper::concatSequences(
+ ODatabaseDocument_OfficeDocument::getTypes(),
+ ODatabaseDocument_Title::getTypes()
+ );
+
+ // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report
+ // which already contains macros. In this case, the database document itself is not
+ // allowed to contain macros, too.
+ if ( !m_bAllowDocumentScripting )
+ {
+ auto [begin, end] = asNonConstRange(aTypes);
+ auto newEnd = std::remove_if( begin, end,
+ [](const Type& t)
+ { return t == cppu::UnoType<XEmbeddedScripts>::get() ||
+ t == cppu::UnoType<XScriptInvocationContext>::get();} );
+ aTypes.realloc( std::distance(begin, newEnd) );
+ }
+
+ return aTypes;
+}
+
+Sequence< sal_Int8 > SAL_CALL ODatabaseDocument::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// local functions
+namespace
+{
+ Reference< XStatusIndicator > lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments )
+ {
+ Reference< XStatusIndicator > xStatusIndicator;
+ return _rArguments.getOrDefault( "StatusIndicator", xStatusIndicator );
+ }
+
+ void lcl_triggerStatusIndicator_throw( const ::comphelper::NamedValueCollection& _rArguments, DocumentGuard& _rGuard, const bool _bStart )
+ {
+ Reference< XStatusIndicator > xStatusIndicator( lcl_extractStatusIndicator( _rArguments ) );
+ if ( !xStatusIndicator.is() )
+ return;
+
+ _rGuard.clear();
+ try
+ {
+ if ( _bStart )
+ xStatusIndicator->start( OUString(), sal_Int32(1000000) );
+ else
+ xStatusIndicator->end();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ _rGuard.reset();
+ // note that |reset| can throw a DisposedException
+ }
+
+ void lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments, Sequence< Any >& _rCallArgs )
+ {
+ Reference< XStatusIndicator > xStatusIndicator( lcl_extractStatusIndicator( _rArguments ) );
+ if ( !xStatusIndicator.is() )
+ return;
+
+ sal_Int32 nLength = _rCallArgs.getLength();
+ _rCallArgs.realloc( nLength + 1 );
+ _rCallArgs.getArray()[ nLength ] <<= xStatusIndicator;
+ }
+
+ void lcl_extractAndStartStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments, Reference< XStatusIndicator >& _rxStatusIndicator,
+ Sequence< Any >& _rCallArgs )
+ {
+ _rxStatusIndicator = lcl_extractStatusIndicator( _rArguments );
+ if ( !_rxStatusIndicator.is() )
+ return;
+
+ try
+ {
+ _rxStatusIndicator->start( OUString(), sal_Int32(1000000) );
+
+ sal_Int32 nLength = _rCallArgs.getLength();
+ _rCallArgs.realloc( nLength + 1 );
+ _rCallArgs.getArray()[ nLength ] <<= _rxStatusIndicator;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ Sequence< PropertyValue > lcl_appendFileNameToDescriptor( const ::comphelper::NamedValueCollection& _rDescriptor, const OUString& _rURL )
+ {
+ ::comphelper::NamedValueCollection aMutableDescriptor( _rDescriptor );
+ if ( !_rURL.isEmpty() )
+ {
+ aMutableDescriptor.put( "FileName", _rURL );
+ aMutableDescriptor.put( "URL", _rURL );
+ }
+ return aMutableDescriptor.getPropertyValues();
+ }
+}
+
+constexpr OUStringLiteral sPictures = u"Pictures";
+
+// base documents seem to have a different behaviour to other documents, the
+// root storage contents at least seem to be re-used over different saves, thus if there is a
+// top level Picture directory it is never cleared.
+// If we delete the 'Pictures' directory then the dialog library storage which does store
+// any embed images will not work properly. ( this is due to the fact it will
+// try to load the dialog which will try and access the embed images, if those images are not cached in
+// memory it will try to read them from the Picture directory which is now gone, so... we have to use this
+// inglorious hack below which basically will
+//
+// a) create a temp storage
+//
+// b) introspect any dialogs for any embed graphics and grab the associate URL(s)
+//
+// c) populate the temp storage with the associated embed images ( will be stored in a 'Pictures' folder )
+//
+// d) delete the 'Picture' element from the root storage
+//
+// e) copy the Pictures element of the temp storage to the root storage
+//
+// this assumes that we don't use the Pictures folder in the root of the base
+// document for anything, I believe this is a valid assumption ( as much as
+// I could check anyway )
+
+/// @throws RuntimeException
+static void lcl_uglyHackToStoreDialogeEmbedImages( const Reference< XStorageBasedLibraryContainer >& xDlgCont, const Reference< XStorage >& xStorage, const Reference< XModel >& rxModel, const Reference<XComponentContext >& rxContext )
+{
+ const Sequence< OUString > sLibraries = xDlgCont->getElementNames();
+ Reference< XStorage > xTmpPic = xStorage->openStorageElement( "tempPictures", ElementModes::READWRITE );
+
+ std::vector<uno::Reference<graphic::XGraphic>> vxGraphicList;
+ for ( OUString const & sLibrary : sLibraries )
+ {
+ xDlgCont->loadLibrary( sLibrary );
+ Reference< XNameContainer > xLib;
+ xDlgCont->getByName( sLibrary ) >>= xLib;
+ if ( xLib.is() )
+ {
+ Sequence< OUString > sDialogs = xLib->getElementNames();
+ sal_Int32 nDialogs( sDialogs.getLength() );
+ for ( sal_Int32 j=0; j < nDialogs; ++j )
+ {
+ Reference < awt::XDialogProvider > xDlgPrv = awt::DialogProvider::createWithModel(rxContext, rxModel);
+ OUString sDialogUrl =
+ "vnd.sun.star.script:" + sLibrary + "." + sDialogs[j] + "?location=document";
+
+ Reference< css::awt::XControl > xDialog( xDlgPrv->createDialog( sDialogUrl ), UNO_QUERY );
+ Reference< XInterface > xModel( xDialog->getModel() );
+ vcl::graphic::SearchForGraphics(xModel, vxGraphicList);
+ }
+ }
+ }
+ // if we have any image urls, make sure we copy the associated images into tempPictures
+ if (!vxGraphicList.empty())
+ {
+ // Export the images to the storage
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ xGraphicStorageHandler.set(GraphicStorageHandler::createWithStorage(rxContext, xTmpPic));
+ if (xGraphicStorageHandler.is())
+ {
+ for (uno::Reference<graphic::XGraphic> const & rxGraphic : vxGraphicList)
+ {
+ xGraphicStorageHandler->saveGraphic(rxGraphic);
+ }
+ }
+ // delete old 'Pictures' storage and copy the contents of tempPictures into xStorage
+ xStorage->removeElement( sPictures );
+ xTmpPic->copyElementTo( sPictures, xStorage, sPictures );
+ }
+ else
+ {
+ // clean up an existing Pictures dir
+ if ( xStorage->isStorageElement( sPictures ) )
+ xStorage->removeElement( sPictures );
+ }
+}
+
+void ODatabaseDocument::impl_setInitialized()
+{
+ m_eInitState = Initialized;
+
+ // start event notifications
+ m_aEventNotifier.onDocumentInitialized();
+}
+
+void ODatabaseDocument::impl_reset_nothrow()
+{
+ try
+ {
+ m_pImpl->clearConnections();
+ m_pImpl->disposeStorages();
+ m_pImpl->resetRootStorage();
+
+ clearObjectContainer( m_xForms );
+ clearObjectContainer( m_xReports );
+ clearObjectContainer( m_pImpl->m_xTableDefinitions );
+ clearObjectContainer( m_pImpl->m_xCommandDefinitions );
+
+ m_eInitState = NotInitialized;
+
+ m_pImpl->reset();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_pImpl->m_bDocumentReadOnly = false;
+}
+
+namespace
+{
+ /** property map for import/export info set */
+ comphelper::PropertyMapEntry const aExportInfoMap[] =
+ {
+ { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("UsePrettyPrinting"), 0, ::cppu::UnoType<sal_Bool>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("TargetStorage"), 0, cppu::UnoType<embed::XStorage>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("StreamRelPath"), 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ };
+}
+
+void ODatabaseDocument::impl_import_nolck_throw( const Reference< XComponentContext >& _rContext, const Reference< XInterface >& _rxTargetComponent,
+ const ::comphelper::NamedValueCollection& _rResource )
+{
+ Sequence< Any > aFilterCreationArgs;
+ Reference< XStatusIndicator > xStatusIndicator;
+ lcl_extractAndStartStatusIndicator( _rResource, xStatusIndicator, aFilterCreationArgs );
+
+ uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ) );
+ OUString sBaseURI = _rResource.getOrDefault("BaseURI", OUString());
+ if (sBaseURI.isEmpty())
+ sBaseURI = _rResource.getOrDefault("URL",OUString());
+ assert(!sBaseURI.isEmpty()); // needed for relative URLs
+ xInfoSet->setPropertyValue("BaseURI", uno::Any(sBaseURI));
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("content.xml")));
+
+ const sal_Int32 nCount = aFilterCreationArgs.getLength();
+ aFilterCreationArgs.realloc(nCount + 1);
+ aFilterCreationArgs.getArray()[nCount] <<= xInfoSet;
+
+ Reference< XImporter > xImporter(
+ _rContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs, _rContext),
+ UNO_QUERY_THROW );
+
+ Reference< XComponent > xComponent( _rxTargetComponent, UNO_QUERY_THROW );
+ xImporter->setTargetDocument( xComponent );
+
+ Reference< XFilter > xFilter( xImporter, UNO_QUERY_THROW );
+ Sequence< PropertyValue > aFilterArgs( ODatabaseModelImpl::stripLoadArguments( _rResource ).getPropertyValues() );
+ xFilter->filter( aFilterArgs );
+
+ if ( xStatusIndicator.is() )
+ xStatusIndicator->end();
+}
+
+void SAL_CALL ODatabaseDocument::initNew( )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::InitMethod );
+
+ impl_reset_nothrow();
+
+ impl_setInitializing();
+
+ // create a temporary storage
+ Reference< XStorage > xTempStor( ::comphelper::OStorageHelper::GetTemporaryStorage( m_pImpl->m_aContext ) );
+
+ // store therein
+ impl_storeToStorage_throw( xTempStor, Sequence< PropertyValue >(), aGuard );
+
+ // let the impl know we're now based on this storage
+ m_pImpl->switchToStorage( xTempStor );
+
+ // for the newly created document, allow document-wide scripting
+ m_bAllowDocumentScripting = true;
+
+ impl_setInitialized();
+
+ m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" );
+
+ impl_setModified_nothrow( false, aGuard );
+ // <- SYNCHRONIZED
+
+ m_aEventNotifier.notifyDocumentEvent( "OnCreate" );
+
+ impl_notifyStorageChange_nolck_nothrow( xTempStor );
+}
+
+void SAL_CALL ODatabaseDocument::load( const Sequence< PropertyValue >& Arguments )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::InitMethod );
+
+ impl_reset_nothrow();
+
+ ::comphelper::NamedValueCollection aResource( Arguments );
+ if ( aResource.has( "FileName" ) && !aResource.has( "URL" ) )
+ // FileName is the compatibility name for URL, so we might have clients passing
+ // a FileName only. However, some of our code works with the URL only, so ensure
+ // we have one.
+ aResource.put( "URL", aResource.get( "FileName" ) );
+ if ( aResource.has( "URL" ) && !aResource.has( "FileName" ) )
+ // similar ... just in case there is legacy code which expects a FileName only
+ aResource.put( "FileName", aResource.get( "URL" ) );
+
+ // now that somebody (perhaps) told us a macro execution mode, remember it as
+ // ImposedMacroExecMode
+ m_pImpl->setImposedMacroExecMode(
+ aResource.getOrDefault( "MacroExecutionMode", m_pImpl->getImposedMacroExecMode() ) );
+
+ impl_setInitializing();
+ try
+ {
+ aGuard.clear();
+ impl_import_nolck_throw( m_pImpl->m_aContext, *this, aResource );
+ aGuard.reset();
+ }
+ catch( const Exception& )
+ {
+ impl_reset_nothrow();
+ throw;
+ }
+ // tell our view monitor that the document has been loaded - this way it will fire the proper
+ // event (OnLoad instead of OnCreate) later on
+ m_aViewMonitor.onLoadedDocument();
+
+ // note that we do *not* call impl_setInitialized() here: The initialization is only complete
+ // when the XModel::attachResource has been called, not sooner.
+ // however, in case of embedding, XModel::attachResource is already called.
+ if (m_bEmbedded)
+ impl_setInitialized();
+
+ impl_setModified_nothrow( false, aGuard );
+ // <- SYNCHRONIZED
+}
+
+namespace
+{
+ bool lcl_hasAnyModifiedSubComponent_throw( const Reference< XController >& i_rController )
+ {
+ Reference< css::sdb::application::XDatabaseDocumentUI > xDatabaseUI( i_rController, UNO_QUERY_THROW );
+
+ const Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() );
+
+ bool isAnyModified = false;
+ for ( auto const & xComponent : aComponents )
+ {
+ Reference< XModifiable > xModify( xComponent, UNO_QUERY );
+ if ( xModify.is() )
+ {
+ isAnyModified = xModify->isModified();
+ continue;
+ }
+
+ // TODO: clarify: anything else to care for? Both the sub components with and without model
+ // should support the XModifiable interface, so I think nothing more is needed here.
+ OSL_FAIL( "lcl_hasAnyModifiedSubComponent_throw: anything left to do here?" );
+ }
+
+ return isAnyModified;
+ }
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::wasModifiedSinceLastSave()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ // The implementation here is somewhat sloppy, in that it returns whether *any* part of the whole
+ // database document, including opened sub components, is modified. This is more than what is requested:
+ // We need to return <TRUE/> if the doc itself, or any of the opened sub components, has been modified
+ // since the last call to any of the save* methods, or since the document has been loaded/created.
+ // However, the API definition explicitly allows to be that sloppy ...
+
+ if ( isModified() )
+ return true;
+
+ // auto recovery is an "UI feature", it is to restore the UI the user knows. Thus,
+ // we ask our connected controllers, not simply our existing form/report definitions.
+ // (There is some information which even cannot be obtained without asking the controller.
+ // For instance, newly created, but not yet saved, forms/reports are accessible via the
+ // controller only, but not via the model.)
+
+ try
+ {
+ for (auto const& controller : m_aControllers)
+ {
+ if ( lcl_hasAnyModifiedSubComponent_throw(controller) )
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return false;
+}
+
+void SAL_CALL ODatabaseDocument::storeToRecoveryFile( const OUString& i_TargetLocation, const Sequence< PropertyValue >& i_MediaDescriptor )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ ModifyLock aLock( *this );
+
+ try
+ {
+ // create a storage for the target location
+ Reference< XStorage > xTargetStorage( impl_createStorageFor_throw( i_TargetLocation ) );
+
+ // first store the document as a whole into this storage
+ impl_storeToStorage_throw( xTargetStorage, i_MediaDescriptor, aGuard );
+
+ // save the sub components which need saving
+ DatabaseDocumentRecovery aDocRecovery( m_pImpl->m_aContext);
+ aDocRecovery.saveModifiedSubComponents( xTargetStorage, m_aControllers );
+
+ // commit the root storage
+ tools::stor::commitStorageIfWriteable( xTargetStorage );
+ }
+ catch( const IOException& )
+ {
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const WrappedTargetException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetException( OUString(), *this, aError );
+ }
+}
+
+void SAL_CALL ODatabaseDocument::recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor )
+{
+ try
+ {
+ DocumentGuard aGuard( *this, DocumentGuard::InitMethod );
+
+ if ( i_SourceLocation.isEmpty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+
+ // load the document itself, by simply delegating to our "load" method
+
+ // our load implementation expects the SalvagedFile and URL to be in the media descriptor
+ ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor );
+ aMediaDescriptor.put( "SalvagedFile", i_SalvagedFile );
+ aMediaDescriptor.put( "URL", i_SourceLocation );
+
+ aGuard.clear(); // (load has an own guarding scheme)
+ load( aMediaDescriptor.getPropertyValues() );
+ aGuard.reset();
+
+ // Without a controller, we are unable to recover the sub components, as they're always tied to a controller.
+ // So, everything else is done when the first controller is connected.
+ m_bHasBeenRecovered = true;
+
+ // tell the impl that we've been loaded from the given location
+ m_pImpl->setDocFileLocation( i_SourceLocation );
+
+ // by definition (of XDocumentRecovery), we're responsible for delivering a fully-initialized document,
+ // which includes an attachResource call.
+ const OUString sLogicalDocumentURL( i_SalvagedFile.isEmpty() ? i_SourceLocation : i_SalvagedFile );
+ impl_attachResource( sLogicalDocumentURL, aMediaDescriptor.getPropertyValues(), aGuard );
+ // <- SYNCHRONIZED
+ }
+ catch( const IOException& )
+ {
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const WrappedTargetException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetException( OUString(), *this, aError );
+ }
+}
+
+// XModel
+sal_Bool SAL_CALL ODatabaseDocument::attachResource( const OUString& _rURL, const Sequence< PropertyValue >& _rArguments )
+{
+ if (_rURL.isEmpty() && _rArguments.getLength() == 1 && _rArguments[0].Name == "SetEmbedded")
+ {
+ m_bEmbedded = true;
+ return true;
+ }
+
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ bool bRet = false;
+ try
+ {
+ bRet = impl_attachResource( _rURL, _rArguments, aGuard );
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetRuntimeException( OUString(), *this, aError );
+ }
+ return bRet;
+}
+
+bool ODatabaseDocument::impl_attachResource( const OUString& i_rLogicalDocumentURL,
+ const Sequence< PropertyValue >& i_rMediaDescriptor, DocumentGuard& _rDocGuard )
+{
+ if (i_rLogicalDocumentURL == getURL())
+ {
+ ::comphelper::NamedValueCollection aArgs(i_rMediaDescriptor);
+
+ // this misuse of attachresource is a hack of the Basic importer code
+ // repurposing existing interfaces for uses it probably wasn't intended
+ // for
+
+ // we do not support macro signatures, so we can ignore that request
+ aArgs.remove("BreakMacroSignature");
+
+ bool bMacroEventRead = false;
+ if ((aArgs.get( "MacroEventRead" ) >>= bMacroEventRead) && bMacroEventRead)
+ m_pImpl->m_bMacroCallsSeenWhileLoading = true;
+ aArgs.remove( "MacroEventRead" );
+
+ if (aArgs.empty())
+ return false;
+ }
+
+ // if no URL has been provided, the caller was lazy enough to not call our getURL - which is not allowed anymore,
+ // now since getURL and getLocation both return the same, so calling one of those should be simple.
+ OUString sDocumentURL( i_rLogicalDocumentURL );
+ OSL_ENSURE( !sDocumentURL.isEmpty(), "ODatabaseDocument::impl_attachResource: invalid URL!" );
+ if ( sDocumentURL.isEmpty() )
+ sDocumentURL = getURL();
+
+ m_pImpl->setResource( sDocumentURL, i_rMediaDescriptor );
+
+ if ( impl_isInitializing() )
+ { // this means we've just been loaded, and this is the attachResource call which follows
+ // the load call.
+ impl_setInitialized();
+
+ // determine whether the document as a whole, or sub documents, have macros. Especially the latter
+ // controls the availability of our XEmbeddedScripts and XScriptInvocationContext interfaces, and we
+ // should know this before anybody actually uses the object.
+ m_bAllowDocumentScripting = ( m_pImpl->determineEmbeddedMacros() != ODatabaseModelImpl::eSubDocumentMacros );
+
+ _rDocGuard.clear();
+ // <- SYNCHRONIZED
+ m_aEventNotifier.notifyDocumentEvent( "OnLoadFinished" );
+ }
+
+ return true;
+}
+
+OUString SAL_CALL ODatabaseDocument::getURL( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getURL();
+}
+
+Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getArgs( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getMediaDescriptor().getPropertyValues();
+}
+
+Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getArgs2( const ::css::uno::Sequence< ::rtl::OUString >& requestedArgs )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ std::vector<PropertyValue> aRet;
+ for (const auto & rArgName : requestedArgs)
+ aRet.push_back(PropertyValue(rArgName, 0, m_pImpl->getMediaDescriptor().get(rArgName), PropertyState_DIRECT_VALUE));
+ return comphelper::containerToSequence(aRet);
+}
+
+void SAL_CALL ODatabaseDocument::setArgs(const Sequence<beans::PropertyValue>& /* aArgs */)
+{
+ throw NoSupportException();
+}
+
+void SAL_CALL ODatabaseDocument::connectController( const Reference< XController >& _xController )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+#if OSL_DEBUG_LEVEL > 0
+ for (auto const& controller : m_aControllers)
+ {
+ OSL_ENSURE( controller != _xController, "ODatabaseDocument::connectController: this controller is already connected!" );
+ }
+#endif
+
+ m_aControllers.push_back( _xController );
+
+ m_aEventNotifier.notifyDocumentEventAsync( "OnViewCreated", Reference< XController2 >( _xController, UNO_QUERY ) );
+
+ bool bFirstControllerEver = m_aViewMonitor.onControllerConnected( _xController );
+ if ( !bFirstControllerEver )
+ return;
+
+ // check/adjust our macro mode.
+ m_pImpl->checkMacrosOnLoading();
+}
+
+void SAL_CALL ODatabaseDocument::disconnectController( const Reference< XController >& _xController )
+{
+ bool bNotifyViewClosed = false;
+ bool bLastControllerGone = false;
+ bool bIsClosing = false;
+
+ // SYNCHRONIZED ->
+ {
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Controllers::iterator pos = std::find( m_aControllers.begin(), m_aControllers.end(), _xController );
+ OSL_ENSURE( pos != m_aControllers.end(), "ODatabaseDocument::disconnectController: don't know this controller!" );
+ if ( pos != m_aControllers.end() )
+ {
+ m_aControllers.erase( pos );
+ bNotifyViewClosed = true;
+ }
+
+ if ( m_xCurrentController == _xController )
+ m_xCurrentController = nullptr;
+
+ bLastControllerGone = m_aControllers.empty();
+ bIsClosing = m_bClosing;
+ }
+ // <- SYNCHRONIZED
+
+ if ( bNotifyViewClosed )
+ m_aEventNotifier.notifyDocumentEvent( "OnViewClosed", Reference< XController2 >( _xController, UNO_QUERY ) );
+
+ if ( !bLastControllerGone || bIsClosing )
+ return;
+
+ // if this was the last view, close the document as a whole
+ // #i51157#
+ try
+ {
+ close( true );
+ }
+ catch( const CloseVetoException& )
+ {
+ // okay, somebody vetoed and took ownership
+ }
+}
+
+void SAL_CALL ODatabaseDocument::lockControllers( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ ++m_pImpl->m_nControllerLockCount;
+}
+
+void SAL_CALL ODatabaseDocument::unlockControllers( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ --m_pImpl->m_nControllerLockCount;
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::hasControllersLocked( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ return m_pImpl->m_nControllerLockCount != 0;
+}
+
+Reference< XController > SAL_CALL ODatabaseDocument::getCurrentController()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ return m_xCurrentController.is() ? m_xCurrentController : ( m_aControllers.empty() ? Reference< XController >() : *m_aControllers.begin() );
+}
+
+void SAL_CALL ODatabaseDocument::setCurrentController( const Reference< XController >& _xController )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ m_xCurrentController = _xController;
+
+ if ( !m_aViewMonitor.onSetCurrentController( _xController ) )
+ return;
+
+ // check if there are sub components to recover from our document storage
+ bool bAttemptRecovery = m_bHasBeenRecovered;
+ if ( !bAttemptRecovery && m_pImpl->getMediaDescriptor().has( "ForceRecovery" ) )
+ // do not use getOrDefault, it will throw for invalid types, which is not desired here
+ m_pImpl->getMediaDescriptor().get( "ForceRecovery" ) >>= bAttemptRecovery;
+
+ if ( !bAttemptRecovery )
+ return;
+
+ try
+ {
+ DatabaseDocumentRecovery aDocRecovery( m_pImpl->m_aContext );
+ aDocRecovery.recoverSubDocuments( m_pImpl->getRootStorage(), _xController );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference< XInterface > SAL_CALL ODatabaseDocument::getCurrentSelection( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XInterface > xRet;
+ Reference< XSelectionSupplier > xDocView( getCurrentController(), UNO_QUERY );
+ if ( xDocView.is() )
+ xRet.set(xDocView->getSelection(),UNO_QUERY);
+
+ return xRet;
+}
+
+// XStorable
+sal_Bool SAL_CALL ODatabaseDocument::hasLocation( )
+{
+ return !getLocation().isEmpty();
+}
+
+OUString SAL_CALL ODatabaseDocument::getLocation( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getURL();
+ // both XStorable::getLocation and XModel::getURL have to return the URL of the document, *not*
+ // the location of the file which the document was possibly recovered from (which would be getDocFileLocation)
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::isReadonly( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->m_bDocumentReadOnly;
+}
+
+void SAL_CALL ODatabaseDocument::store( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ OUString sDocumentURL( m_pImpl->getURL() );
+ if ( !sDocumentURL.isEmpty() )
+ {
+ if ( m_pImpl->getDocFileLocation() == m_pImpl->getURL() )
+ if ( m_pImpl->m_bDocumentReadOnly )
+ throw IOException();
+
+ impl_storeAs_throw( m_pImpl->getURL(), m_pImpl->getMediaDescriptor(), SAVE, aGuard );
+ return;
+ }
+
+ // if we have no URL, but did survive the DocumentGuard above, then we've been inited via XLoadable::initNew,
+ // i.e. we're based on a temporary storage
+ OSL_ENSURE( m_pImpl->getDocFileLocation().isEmpty(), "ODatabaseDocument::store: unexpected URL inconsistency!" );
+
+ try
+ {
+ impl_storeToStorage_throw( m_pImpl->getRootStorage(), m_pImpl->getMediaDescriptor().getPropertyValues(), aGuard );
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() )
+ || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() )
+ )
+ {
+ // allowed to leave
+ throw;
+ }
+ impl_throwIOExceptionCausedBySave_throw( aError, {} );
+ }
+}
+
+void ODatabaseDocument::impl_throwIOExceptionCausedBySave_throw( const Any& i_rError, std::u16string_view i_rTargetURL ) const
+{
+ OUString sErrorMessage = extractExceptionMessage( m_pImpl->m_aContext, i_rError );
+ sErrorMessage = ResourceManager::loadString(
+ RID_STR_ERROR_WHILE_SAVING,
+ "$location$", i_rTargetURL,
+ "$message$", sErrorMessage
+ );
+ throw IOException( sErrorMessage, *const_cast< ODatabaseDocument* >( this ) );
+}
+
+void ODatabaseDocument::impl_storeAs_throw( const OUString& _rURL, const ::comphelper::NamedValueCollection& _rArguments,
+ const StoreType _eType, DocumentGuard& _rGuard )
+{
+ OSL_PRECOND( ( _eType == SAVE ) || ( _eType == SAVE_AS ),
+ "ODatabaseDocument::impl_storeAs_throw: you introduced a new type which cannot be handled here!" );
+
+ // if we're in the process of initializing the document (which effectively means it is an implicit
+ // initialization triggered in storeAsURL), the we do not notify events, since to an observer, the SaveAs
+ // should not be noticeable
+ bool bIsInitializationProcess = impl_isInitializing();
+
+ if ( !bIsInitializationProcess )
+ {
+ _rGuard.clear();
+ m_aEventNotifier.notifyDocumentEvent( _eType == SAVE ? "OnSave" : "OnSaveAs", nullptr, Any( _rURL ) );
+ _rGuard.reset();
+ }
+
+ Reference< XStorage > xNewRootStorage;
+ // will be non-NULL if our storage changed
+
+ try
+ {
+ ModifyLock aLock( *this );
+ // ignore all changes of our "modified" state during storing
+
+ bool bLocationChanged = ( _rURL != m_pImpl->getDocFileLocation() );
+ if ( bLocationChanged )
+ {
+ // create storage for target URL
+ uno::Reference<embed::XStorage> xTargetStorage(
+ impl_GetStorageOrCreateFor_throw(_rArguments, _rURL));
+
+ if ( m_pImpl->isEmbeddedDatabase() )
+ m_pImpl->clearConnections();
+
+ // commit everything
+ m_pImpl->commitEmbeddedStorage();
+ m_pImpl->commitStorages();
+
+ // copy own storage to target storage
+ Reference< XStorage > xCurrentStorage( m_pImpl->getRootStorage() );
+ if ( xCurrentStorage.is() )
+ xCurrentStorage->copyToStorage( xTargetStorage );
+
+ m_pImpl->disposeStorages();
+
+ // each and every document definition obtained via m_xForms and m_xReports depends
+ // on the sub storages which we just disposed. So, dispose the forms/reports collections, too.
+ // This ensures that they're re-created when needed.
+ clearObjectContainer( m_xForms );
+ clearObjectContainer( m_xReports );
+
+ xNewRootStorage = m_pImpl->switchToStorage( xTargetStorage );
+
+ m_pImpl->m_bDocumentReadOnly = false;
+ }
+
+ // store to current storage
+ Reference< XStorage > xCurrentStorage( m_pImpl->getOrCreateRootStorage(), UNO_SET_THROW );
+ Sequence< PropertyValue > aMediaDescriptor( lcl_appendFileNameToDescriptor( _rArguments, _rURL ) );
+ impl_storeToStorage_throw( xCurrentStorage, aMediaDescriptor, _rGuard );
+
+ // success - tell our impl
+ m_pImpl->setDocFileLocation( _rURL );
+ m_pImpl->setResource( _rURL, aMediaDescriptor );
+
+ // if we are in an initialization process, then this is finished, now that we stored the document
+ if ( bIsInitializationProcess )
+ impl_setInitialized();
+ }
+ catch( const IOException& )
+ {
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, Any( _rURL ) );
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, Any( _rURL ) );
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+
+ // notify the failure
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, Any( _rURL ) );
+
+ impl_throwIOExceptionCausedBySave_throw( aError, _rURL );
+ }
+
+ // notify the document event
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveDone" : "OnSaveAsDone", nullptr, Any( _rURL ) );
+
+ // reset our "modified" flag, and clear the guard
+ impl_setModified_nothrow( false, _rGuard );
+ // <- SYNCHRONIZED
+
+ // notify storage listeners
+ if ( xNewRootStorage.is() )
+ impl_notifyStorageChange_nolck_nothrow( xNewRootStorage );
+}
+
+Reference< XStorage > ODatabaseDocument::impl_createStorageFor_throw( const OUString& _rURL ) const
+{
+ Reference< ucb::XSimpleFileAccess3 > xTempAccess(ucb::SimpleFileAccess::create(m_pImpl->m_aContext));
+ Reference< io::XStream > xStream = xTempAccess->openFileReadWrite( _rURL );
+ Reference< io::XTruncate > xTruncate(xStream,UNO_QUERY);
+ if ( xTruncate.is() )
+ {
+ xTruncate->truncate();
+ }
+ Sequence<Any> aParam{ Any(xStream), Any(ElementModes::READWRITE | ElementModes::TRUNCATE) };
+
+ Reference< XSingleServiceFactory > xStorageFactory( m_pImpl->createStorageFactory(), UNO_SET_THROW );
+ return Reference< XStorage >( xStorageFactory->createInstanceWithArguments( aParam ), UNO_QUERY_THROW );
+}
+
+css::uno::Reference<css::embed::XStorage> ODatabaseDocument::impl_GetStorageOrCreateFor_throw(
+ const ::comphelper::NamedValueCollection& _rArguments, const OUString& _rURL) const
+{
+ // Try to get the storage from arguments, then create storage for target URL
+ uno::Reference<embed::XStorage> xTargetStorage;
+ _rArguments.get("TargetStorage") >>= xTargetStorage;
+ if (!xTargetStorage.is())
+ xTargetStorage = impl_createStorageFor_throw(_rURL);
+
+ // In case we got a StreamRelPath, then xTargetStorage should reference that sub-storage.
+ OUString sStreamRelPath = _rArguments.getOrDefault("StreamRelPath", OUString());
+ if (!sStreamRelPath.isEmpty())
+ xTargetStorage
+ = xTargetStorage->openStorageElement(sStreamRelPath, embed::ElementModes::READWRITE);
+
+ return xTargetStorage;
+}
+
+void SAL_CALL ODatabaseDocument::storeAsURL( const OUString& _rURL, const Sequence< PropertyValue >& _rArguments )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+
+ // Normally, a document initialization is done via XLoadable::load or XLoadable::initNew. For convenience
+ // reasons, and to not break existing API clients, it's allowed to call storeAsURL without having initialized
+ // the document, in which case the initialization will be done implicitly.
+ bool bImplicitInitialization = !impl_isInitialized();
+ // implicit initialization while another initialization is just running is not possible
+ if ( bImplicitInitialization && impl_isInitializing() )
+ throw RuntimeException();
+
+ if ( bImplicitInitialization )
+ impl_setInitializing();
+
+ try
+ {
+ impl_storeAs_throw( _rURL, _rArguments, SAVE_AS, aGuard );
+ // <- SYNCHRONIZED
+
+ // impl_storeAs_throw cleared the lock on our mutex, but the below lines need this lock
+ // SYNCHRONIZED ->
+ aGuard.reset();
+
+ // our title might have changed, potentially at least
+ // Sadly, we cannot check this: Calling getTitle here and now would not deliver
+ // an up-to-date result, as the call is delegated to our TitleHelper instance, which itself
+ // updates its title only if it gets the OnSaveAsDone event (which was sent asynchronously
+ // by impl_storeAs_throw). So, we simply notify always, and also asynchronously
+ m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" );
+ }
+ catch( const Exception& )
+ {
+ impl_reset_nothrow();
+ throw;
+ }
+
+ if ( bImplicitInitialization )
+ m_bAllowDocumentScripting = true;
+
+ aGuard.clear();
+ // <- SYNCHRONIZED
+
+ if ( bImplicitInitialization )
+ m_aEventNotifier.notifyDocumentEvent( "OnCreate" );
+}
+
+void ODatabaseDocument::impl_storeToStorage_throw( const Reference< XStorage >& _rxTargetStorage, const Sequence< PropertyValue >& _rMediaDescriptor,
+ DocumentGuard& _rDocGuard ) const
+{
+ if ( !_rxTargetStorage.is() )
+ throw IllegalArgumentException( OUString(), *const_cast< ODatabaseDocument* >( this ), 1 );
+
+ if ( !m_pImpl.is() )
+ throw DisposedException( OUString(), *const_cast< ODatabaseDocument* >( this ) );
+
+ try
+ {
+ // commit everything
+ m_pImpl->commitEmbeddedStorage();
+ m_pImpl->commitStorages();
+
+ // copy own storage to target storage
+ if ( impl_isInitialized() )
+ {
+ Reference< XStorage > xCurrentStorage = m_pImpl->getOrCreateRootStorage();
+ // Root storage may be empty in case of embedding.
+ if ( xCurrentStorage.is() && xCurrentStorage != _rxTargetStorage )
+ xCurrentStorage->copyToStorage( _rxTargetStorage );
+ }
+
+ // write into target storage
+ ::comphelper::NamedValueCollection aWriteArgs( _rMediaDescriptor );
+ lcl_triggerStatusIndicator_throw( aWriteArgs, _rDocGuard, true );
+ impl_writeStorage_throw( _rxTargetStorage, aWriteArgs );
+ lcl_triggerStatusIndicator_throw( aWriteArgs, _rDocGuard, false );
+
+ // commit target storage
+ m_pImpl->commitStorageIfWriteable_ignoreErrors(_rxTargetStorage);
+ }
+ catch( const IOException& ) { throw; }
+ catch( const RuntimeException& ) { throw; }
+ catch ( const Exception& e )
+ {
+ throw IOException( e.Message, *const_cast< ODatabaseDocument* >( this ) );
+ }
+}
+
+void SAL_CALL ODatabaseDocument::storeToURL( const OUString& _rURL, const Sequence< PropertyValue >& _rArguments )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ ModifyLock aLock( *this );
+
+ {
+ aGuard.clear();
+ m_aEventNotifier.notifyDocumentEvent( "OnSaveTo", nullptr, Any( _rURL ) );
+ aGuard.reset();
+ }
+
+ try
+ {
+ const ::comphelper::NamedValueCollection aArguments(_rArguments);
+ // create storage for target URL
+ Reference<XStorage> xTargetStorage(impl_GetStorageOrCreateFor_throw(aArguments, _rURL));
+
+ // extend media descriptor with URL
+ Sequence<PropertyValue> aMediaDescriptor(lcl_appendFileNameToDescriptor(aArguments, _rURL));
+
+ // store to this storage
+ impl_storeToStorage_throw( xTargetStorage, aMediaDescriptor, aGuard );
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ m_aEventNotifier.notifyDocumentEventAsync( "OnSaveToFailed", nullptr, aError );
+
+ if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() )
+ || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() )
+ )
+ {
+ // allowed to leave
+ throw;
+ }
+
+ impl_throwIOExceptionCausedBySave_throw( aError, _rURL );
+ }
+
+ m_aEventNotifier.notifyDocumentEventAsync( "OnSaveToDone", nullptr, Any( _rURL ) );
+}
+
+// XModifyBroadcaster
+void SAL_CALL ODatabaseDocument::addModifyListener( const Reference< XModifyListener >& _xListener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aModifyListeners.addInterface(_xListener);
+}
+
+void SAL_CALL ODatabaseDocument::removeModifyListener( const Reference< XModifyListener >& _xListener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aModifyListeners.removeInterface(_xListener);
+}
+
+// XModifiable
+sal_Bool SAL_CALL ODatabaseDocument::isModified( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ return m_pImpl->m_bModified;
+}
+
+void SAL_CALL ODatabaseDocument::setModified( sal_Bool _bModified )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ if ( impl_isInitialized() )
+ impl_setModified_nothrow( _bModified, aGuard );
+ // it's allowed to call setModified without the document being initialized already. In this case,
+ // we simply ignore the call - when the initialization is finished, the respective code will set
+ // a proper "modified" flag
+}
+
+void ODatabaseDocument::impl_setModified_nothrow( bool _bModified, DocumentGuard& _rGuard )
+{
+ // SYNCHRONIZED ->
+ bool bModifiedChanged = ( m_pImpl->m_bModified != _bModified ) && ( !m_pImpl->isModifyLocked() );
+
+ if ( bModifiedChanged )
+ {
+ m_pImpl->m_bModified = _bModified;
+ m_aEventNotifier.notifyDocumentEventAsync( "OnModifyChanged" );
+ }
+ _rGuard.clear();
+ // <- SYNCHRONIZED
+
+ if ( bModifiedChanged )
+ {
+ lang::EventObject aEvent( *this );
+ m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
+ }
+}
+
+// css::document::XEventBroadcaster
+void SAL_CALL ODatabaseDocument::addEventListener(const uno::Reference< document::XEventListener >& Listener )
+{
+ m_aEventNotifier.addLegacyEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::removeEventListener( const uno::Reference< document::XEventListener >& Listener )
+{
+ m_aEventNotifier.removeLegacyEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::addDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+{
+ m_aEventNotifier.addDocumentEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+{
+ m_aEventNotifier.removeDocumentEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::notifyDocumentEvent( const OUString& EventName, const Reference< XController2 >& ViewController, const Any& Supplement )
+{
+ if ( EventName.isEmpty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ if ( !DocumentEvents::needsSynchronousNotification( EventName ) )
+ {
+ m_aEventNotifier.notifyDocumentEventAsync( EventName, ViewController, Supplement );
+ return;
+ }
+ aGuard.clear();
+ // <- SYNCHRONIZED
+
+ m_aEventNotifier.notifyDocumentEvent( EventName, ViewController, Supplement );
+}
+
+Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getPrinter( )
+{
+ OSL_FAIL( "ODatabaseDocument::getPrinter: not supported!" );
+ return Sequence< PropertyValue >();
+}
+
+void SAL_CALL ODatabaseDocument::setPrinter( const Sequence< PropertyValue >& /*aPrinter*/ )
+{
+ OSL_FAIL( "ODatabaseDocument::setPrinter: not supported!" );
+}
+
+void SAL_CALL ODatabaseDocument::print( const Sequence< PropertyValue >& /*xOptions*/ )
+{
+ OSL_FAIL( "ODatabaseDocument::print: not supported!" );
+}
+
+void ODatabaseDocument::impl_reparent_nothrow( const WeakReference< XNameAccess >& _rxContainer )
+{
+ Reference< XChild > xChild( _rxContainer.get(), UNO_QUERY );
+ if ( xChild.is() )
+ xChild->setParent( *this );
+}
+
+void ODatabaseDocument::clearObjectContainer( WeakReference< XNameAccess >& _rxContainer)
+{
+ Reference< XNameAccess > xContainer = _rxContainer;
+ ::comphelper::disposeComponent( xContainer );
+
+ Reference< XChild > xChild( _rxContainer.get(),UNO_QUERY );
+ if ( xChild.is() )
+ xChild->setParent( nullptr );
+ _rxContainer.clear();
+}
+
+Reference< XNameAccess > ODatabaseDocument::impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType )
+{
+ if ( ( _eType != ODatabaseModelImpl::E_FORM ) && ( _eType != ODatabaseModelImpl::E_REPORT ) )
+ throw IllegalArgumentException();
+
+ bool bFormsContainer = _eType == ODatabaseModelImpl::E_FORM;
+
+ WeakReference< XNameAccess >& rContainerRef( bFormsContainer ? m_xForms : m_xReports );
+ Reference< XNameAccess > xContainer = rContainerRef;
+ if ( !xContainer.is() )
+ {
+ Any aValue;
+ css::uno::Reference< css::uno::XInterface > xMy(*this);
+ if ( dbtools::getDataSourceSetting(xMy,bFormsContainer ? "Forms" : "Reports",aValue) )
+ {
+ OUString sSupportService;
+ aValue >>= sSupportService;
+ if ( !sSupportService.isEmpty() )
+ {
+ Sequence<Any> aArgs{ Any(NamedValue("DatabaseDocument",Any(xMy))) };
+ xContainer.set(
+ m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext),
+ UNO_QUERY);
+ rContainerRef = xContainer;
+ }
+ }
+ if ( !xContainer.is() )
+ {
+ TContentPtr& rContainerData( m_pImpl->getObjectContainer( _eType ) );
+ rContainerRef = xContainer = new ODocumentContainer( m_pImpl->m_aContext, *this, rContainerData, bFormsContainer );
+ }
+ impl_reparent_nothrow( xContainer );
+ }
+ return xContainer;
+}
+
+void ODatabaseDocument::impl_closeControllerFrames_nolck_throw( bool _bDeliverOwnership )
+{
+ Controllers aCopy = m_aControllers;
+
+ for (auto const& elem : aCopy)
+ {
+ if ( !elem.is() )
+ continue;
+
+ try
+ {
+ Reference< XCloseable> xFrame( elem->getFrame(), UNO_QUERY );
+ if ( xFrame.is() )
+ xFrame->close( _bDeliverOwnership );
+ }
+ catch( const CloseVetoException& ) { throw; }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void ODatabaseDocument::impl_disposeControllerFrames_nothrow()
+{
+ Controllers aCopy;
+ aCopy.swap( m_aControllers ); // ensure m_aControllers is empty afterwards
+ for( const auto& rController : aCopy )
+ {
+ try
+ {
+ if( rController.is() )
+ {
+ Reference< XFrame > xFrame( rController->getFrame() );
+ ::comphelper::disposeComponent( xFrame );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void SAL_CALL ODatabaseDocument::close(sal_Bool bDeliverOwnership)
+{
+ // nearly everything below can/must be done without our mutex locked, the below is just for
+ // the checks for being disposed and the like
+ // SYNCHRONIZED ->
+ {
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ assert (!m_bClosing);
+ m_bClosing = true;
+ }
+ // <- SYNCHRONIZED
+
+ try
+ {
+ // allow listeners to veto
+ lang::EventObject aEvent( *this );
+ m_aCloseListener.forEach(
+ [&aEvent, &bDeliverOwnership] (uno::Reference<XCloseListener> const& xListener) {
+ return xListener->queryClosing(aEvent, bDeliverOwnership);
+ });
+
+ // notify that we're going to unload
+ m_aEventNotifier.notifyDocumentEvent( "OnPrepareUnload" );
+
+ impl_closeControllerFrames_nolck_throw( bDeliverOwnership );
+
+ m_aCloseListener.notifyEach( &XCloseListener::notifyClosing, const_cast<const lang::EventObject&>(aEvent) );
+
+ dispose();
+ }
+ catch ( const Exception& )
+ {
+ SolarMutexGuard g;
+ m_bClosing = false;
+ throw;
+ }
+
+ // SYNCHRONIZED ->
+ SolarMutexGuard g;
+ m_bClosing = false;
+ // <- SYNCHRONIZED
+}
+
+void SAL_CALL ODatabaseDocument::addCloseListener( const Reference< css::util::XCloseListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aCloseListener.addInterface(Listener);
+}
+
+void SAL_CALL ODatabaseDocument::removeCloseListener( const Reference< css::util::XCloseListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aCloseListener.removeInterface(Listener);
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseDocument::getFormDocuments( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_FORM );
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseDocument::getReportDocuments( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_REPORT );
+}
+
+void ODatabaseDocument::WriteThroughComponent( const Reference< XComponent >& xComponent, const char* pStreamName,
+ const char* pServiceName, const Sequence< Any >& _rArguments, const Sequence< PropertyValue >& rMediaDesc,
+ const Reference<XStorage>& _xStorageToSaveTo ) const
+{
+ OSL_ENSURE( pStreamName, "Need stream name!" );
+ OSL_ENSURE( pServiceName, "Need service name!" );
+
+ // open stream
+ OUString sStreamName = OUString::createFromAscii( pStreamName );
+ Reference< XStream > xStream = _xStorageToSaveTo->openStreamElement( sStreamName, ElementModes::READWRITE | ElementModes::TRUNCATE );
+ if ( !xStream.is() )
+ return;
+
+ Reference< XOutputStream > xOutputStream( xStream->getOutputStream() );
+ OSL_ENSURE( xOutputStream.is(), "Can't create output stream in package!" );
+ if ( !xOutputStream.is() )
+ return;
+
+ Reference< XSeekable > xSeek( xOutputStream, UNO_QUERY );
+ if ( xSeek.is() )
+ xSeek->seek(0);
+
+ Reference< XPropertySet > xStreamProp( xOutputStream, UNO_QUERY_THROW );
+ xStreamProp->setPropertyValue( INFO_MEDIATYPE, Any( OUString( "text/xml" ) ) );
+ xStreamProp->setPropertyValue( "Compressed", Any( true ) );
+
+ // write the stuff
+ WriteThroughComponent( xOutputStream, xComponent, pServiceName, _rArguments, rMediaDesc );
+}
+
+void ODatabaseDocument::WriteThroughComponent( const Reference< XOutputStream >& xOutputStream,
+ const Reference< XComponent >& xComponent, const char* pServiceName, const Sequence< Any >& _rArguments,
+ const Sequence< PropertyValue >& rMediaDesc ) const
+{
+ OSL_ENSURE( xOutputStream.is(), "I really need an output stream!" );
+ OSL_ENSURE( xComponent.is(), "Need component!" );
+ OSL_ENSURE( nullptr != pServiceName, "Need component name!" );
+
+ // get component
+ Reference< XWriter > xSaxWriter = xml::sax::Writer::create( m_pImpl->m_aContext );
+
+ // connect XML writer to output stream
+ xSaxWriter->setOutputStream( xOutputStream );
+
+ // prepare arguments (prepend doc handler to given arguments)
+ Sequence<Any> aArgs( 1 + _rArguments.getLength() );
+ auto pArgs = aArgs.getArray();
+ pArgs[0] <<= xSaxWriter;
+ for ( sal_Int32 i = 0; i < _rArguments.getLength(); ++i )
+ pArgs[ i+1 ] = _rArguments[i];
+
+ // get filter component
+ Reference< XExporter > xExporter( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(OUString::createFromAscii(pServiceName), aArgs, m_pImpl->m_aContext), UNO_QUERY_THROW );
+
+ // connect model and filter
+ xExporter->setSourceDocument( xComponent );
+
+ // filter
+ Reference< XFilter > xFilter( xExporter, UNO_QUERY_THROW );
+ xFilter->filter( rMediaDesc );
+}
+
+void ODatabaseDocument::impl_writeStorage_throw( const Reference< XStorage >& _rxTargetStorage, const ::comphelper::NamedValueCollection& _rMediaDescriptor ) const
+{
+ // extract status indicator
+ Sequence< Any > aDelegatorArguments;
+ lcl_extractStatusIndicator( _rMediaDescriptor, aDelegatorArguments );
+
+ uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ) );
+
+ xInfoSet->setPropertyValue("UsePrettyPrinting", uno::Any(officecfg::Office::Common::Save::Document::PrettyPrinting::get()));
+ if ( officecfg::Office::Common::Save::URL::FileSystem::get() )
+ {
+ OUString sBaseURI = _rMediaDescriptor.getOrDefault("BaseURI", OUString());
+ if (sBaseURI.isEmpty())
+ sBaseURI = _rMediaDescriptor.getOrDefault("URL",OUString());
+ xInfoSet->setPropertyValue("BaseURI", uno::Any(sBaseURI));
+ }
+
+ // Set TargetStorage, so it doesn't have to be re-constructed based on possibly empty URL.
+ xInfoSet->setPropertyValue("TargetStorage", uno::Any(m_pImpl->getRootStorage()));
+
+ // Set StreamRelPath, in case this document is an embedded one.
+ OUString sStreamRelPath;
+ OUString sURL = _rMediaDescriptor.getOrDefault("URL", OUString());
+ if (sURL.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:"))
+ {
+ // In this case the host contains the real path, and the path is the embedded stream name.
+ INetURLObject aURL(sURL);
+ sStreamRelPath = aURL.GetURLPath(INetURLObject::DecodeMechanism::WithCharset);
+ if (sStreamRelPath.startsWith("/"))
+ sStreamRelPath = sStreamRelPath.copy(1);
+ }
+ if (!sStreamRelPath.isEmpty())
+ xInfoSet->setPropertyValue("StreamRelPath", uno::Any(sStreamRelPath));
+
+ sal_Int32 nArgsLen = aDelegatorArguments.getLength();
+ aDelegatorArguments.realloc(nArgsLen+1);
+ aDelegatorArguments.getArray()[nArgsLen++] <<= xInfoSet;
+
+ Reference< XPropertySet > xProp( _rxTargetStorage, UNO_QUERY_THROW );
+ xProp->setPropertyValue( INFO_MEDIATYPE, Any( OUString(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII) ) );
+
+ OUString aVersion;
+ SvtSaveOptions::ODFSaneDefaultVersion const nDefVersion =
+ GetODFSaneDefaultVersion();
+ // older versions can not have this property set,
+ // it exists only starting from ODF1.2
+ if (nDefVersion >= SvtSaveOptions::ODFSVER_013)
+ {
+ aVersion = ODFVER_013_TEXT;
+ }
+ else if (nDefVersion >= SvtSaveOptions::ODFSVER_012)
+ {
+ aVersion = ODFVER_012_TEXT;
+ }
+
+ if (!aVersion.isEmpty())
+ {
+ try
+ {
+ xProp->setPropertyValue("Version" , uno::Any(aVersion));
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "exception setting Version");
+ }
+ }
+
+ Reference< XComponent > xComponent( *const_cast< ODatabaseDocument* >( this ), UNO_QUERY_THROW );
+
+ Sequence< PropertyValue > aMediaDescriptor;
+ _rMediaDescriptor >>= aMediaDescriptor;
+
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("settings.xml")));
+ WriteThroughComponent( xComponent, "settings.xml", "com.sun.star.comp.sdb.XMLSettingsExporter",
+ aDelegatorArguments, aMediaDescriptor, _rxTargetStorage );
+
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("content.xml")));
+ WriteThroughComponent( xComponent, "content.xml", "com.sun.star.comp.sdb.DBExportFilter",
+ aDelegatorArguments, aMediaDescriptor, _rxTargetStorage );
+
+ if ( _rxTargetStorage->hasByName ( sPictures ) )
+ {
+ try
+ {
+ // Delete any previously existing Pictures folder and regenerate
+ // any needed content if needed
+ Reference< XStorageBasedLibraryContainer > xDlgs = m_pImpl->getLibraryContainer( false );
+ if ( xDlgs.is() )
+ {
+ Reference< XModel > xModel(const_cast< ODatabaseDocument*>(this));
+ lcl_uglyHackToStoreDialogeEmbedImages( m_pImpl->getLibraryContainer(false), _rxTargetStorage, xModel, m_pImpl->m_aContext );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ m_pImpl->storeLibraryContainersTo( _rxTargetStorage );
+}
+
+Reference< XUIConfigurationManager > SAL_CALL ODatabaseDocument::getUIConfigurationManager( )
+{
+ return Reference< XUIConfigurationManager >( getUIConfigurationManager2(), UNO_QUERY_THROW );
+}
+
+Reference< XUIConfigurationManager2 > const & ODatabaseDocument::getUIConfigurationManager2( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ if ( !m_xUIConfigurationManager.is() )
+ {
+ m_xUIConfigurationManager = UIConfigurationManager::create( m_pImpl->m_aContext );
+
+ OUString aUIConfigFolderName( "Configurations2" );
+
+ // First try to open with READWRITE and then READ
+ Reference< XStorage > xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, ElementModes::READWRITE );
+ if ( xConfigStorage.is() )
+ {
+ OUString aMediaType;
+ Reference< XPropertySet > xPropSet( xConfigStorage, UNO_QUERY );
+ Any a = xPropSet->getPropertyValue( INFO_MEDIATYPE );
+ if ( !( a >>= aMediaType ) || aMediaType.isEmpty() )
+ {
+ a <<= OUString("application/vnd.sun.xml.ui.configuration");
+ xPropSet->setPropertyValue( INFO_MEDIATYPE, a );
+ }
+ }
+ else
+ xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, ElementModes::READ );
+
+ // initialize ui configuration manager with document substorage
+ m_xUIConfigurationManager->setStorage( xConfigStorage );
+ }
+
+ return m_xUIConfigurationManager;
+}
+
+Reference< XStorage > SAL_CALL ODatabaseDocument::getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XDocumentSubStorageSupplier > xStorageAccess( m_pImpl->getDocumentSubStorageSupplier() );
+ return xStorageAccess->getDocumentSubStorage( aStorageName, nMode );
+}
+
+Sequence< OUString > SAL_CALL ODatabaseDocument::getDocumentSubStoragesNames( )
+{
+ Reference< XDocumentSubStorageSupplier > xStorageAccess( m_pImpl->getDocumentSubStorageSupplier() );
+ return xStorageAccess->getDocumentSubStoragesNames();
+}
+
+void ODatabaseDocument::impl_notifyStorageChange_nolck_nothrow( const Reference< XStorage >& xNewRootStorage )
+{
+ Reference< XInterface > xMe( *this );
+
+ m_aStorageListeners.forEach(
+ [&xMe, &xNewRootStorage] (uno::Reference<XStorageChangeListener> const& xListener) {
+ return xListener->notifyStorageChange(xMe, xNewRootStorage);
+ });
+}
+
+void ODatabaseDocument::disposing()
+{
+ if ( !m_pImpl.is() )
+ {
+ // this means that we're already disposed
+ OSL_ENSURE( ODatabaseDocument_OfficeDocument::rBHelper.bDisposed, "ODatabaseDocument::disposing: no impl anymore, but not yet disposed!" );
+ return;
+ }
+
+ if ( impl_isInitialized() )
+ m_aEventNotifier.notifyDocumentEvent( "OnUnload" );
+
+ Reference< XModel > xHoldAlive( this );
+
+ m_aEventNotifier.disposing();
+
+ lang::EventObject aDisposeEvent(static_cast<XWeak*>(this));
+ m_aModifyListeners.disposeAndClear( aDisposeEvent );
+ m_aCloseListener.disposeAndClear( aDisposeEvent );
+ m_aStorageListeners.disposeAndClear( aDisposeEvent );
+
+ // this is the list of objects which we currently hold as member. Upon resetting
+ // those members, we can (potentially) release the last reference to them, in which
+ // case they will be deleted - if they're C++ implementations, that is :).
+ // Some of those implementations are offending enough to require the SolarMutex, which
+ // means we should not release the last reference while our own mutex is locked ...
+ std::vector< Reference< XInterface > > aKeepAlive;
+
+ // SYNCHRONIZED ->
+ {
+ SolarMutexGuard aGuard;
+
+ OSL_ENSURE(m_aControllers.empty(),
+ "ODatabaseDocument::disposing: there still are controllers!");
+ // normally, nobody should explicitly dispose, but only XCloseable::close
+ // the document. And upon closing, our controllers are closed, too
+
+ {
+ uno::Reference<uno::XInterface> xUIInterface(m_xUIConfigurationManager);
+ aKeepAlive.push_back(xUIInterface);
+ }
+ m_xUIConfigurationManager = nullptr;
+
+ clearObjectContainer(m_xForms);
+ clearObjectContainer(m_xReports);
+
+ // reset the macro mode: in case the our impl struct stays alive (e.g. because our DataSource
+ // object still exists), and somebody subsequently re-opens the document, we want to have
+ // the security warning, again.
+ m_pImpl->resetMacroExecutionMode();
+
+ // similar arguing for our ViewMonitor
+ m_aViewMonitor.reset();
+
+ // tell our Impl to forget us
+ m_pImpl->modelIsDisposing(impl_isInitialized(), ODatabaseModelImpl::ResetModelAccess());
+
+ // now, at the latest, the controller array should be empty. Controllers are
+ // expected to listen for our disposal, and disconnect then
+ OSL_ENSURE(m_aControllers.empty(),
+ "ODatabaseDocument::disposing: there still are controllers!");
+ impl_disposeControllerFrames_nothrow();
+
+ {
+ uno::Reference<uno::XInterface> xModuleInterface(m_xModuleManager);
+ aKeepAlive.push_back(xModuleInterface);
+ }
+ m_xModuleManager.clear();
+
+ {
+ uno::Reference<uno::XInterface> xTitleInterface(m_xTitleHelper);
+ aKeepAlive.push_back(xTitleInterface);
+ }
+ m_xTitleHelper.clear();
+
+ m_pImpl.clear();
+ }
+ // <- SYNCHRONIZED
+
+ aKeepAlive.clear();
+}
+
+// XComponent
+void SAL_CALL ODatabaseDocument::dispose( )
+{
+ ::cppu::WeakComponentImplHelperBase::dispose();
+}
+
+void SAL_CALL ODatabaseDocument::addEventListener( const Reference< lang::XEventListener >& _xListener )
+{
+ ::cppu::WeakComponentImplHelperBase::addEventListener( _xListener );
+}
+
+void SAL_CALL ODatabaseDocument::removeEventListener( const Reference< lang::XEventListener >& _xListener )
+{
+ ::cppu::WeakComponentImplHelperBase::removeEventListener( _xListener );
+}
+
+// XServiceInfo
+OUString ODatabaseDocument::getImplementationName()
+{
+ return "com.sun.star.comp.dba.ODatabaseDocument";
+}
+
+Sequence< OUString > ODatabaseDocument::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.OfficeDatabaseDocument", "com.sun.star.document.OfficeDocument" };
+}
+
+sal_Bool ODatabaseDocument::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Reference< XDataSource > SAL_CALL ODatabaseDocument::getDataSource()
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getOrCreateDataSource();
+}
+
+namespace
+{
+/// Property map for embedded import info set.
+comphelper::PropertyMapEntry const aEmbeddedImportInfoMap[] =
+{
+ {OUString("StreamRelPath"), 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ {OUString("StreamName"), 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ {OUString("SourceStorage"), 0, cppu::UnoType<embed::XStorage>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+};
+}
+
+void SAL_CALL ODatabaseDocument::loadFromStorage(const Reference<XStorage>& xStorage, const Sequence<PropertyValue>& rMediaDescriptor)
+{
+ DocumentGuard aGuard(*this, DocumentGuard::InitMethod);
+
+ uno::Reference<beans::XPropertySet> xInfoSet(comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aEmbeddedImportInfoMap)));
+ xInfoSet->setPropertyValue("StreamRelPath", uno::Any(comphelper::NamedValueCollection::getOrDefault(rMediaDescriptor, u"HierarchicalDocumentName", OUString())));
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("content.xml")));
+ xInfoSet->setPropertyValue("SourceStorage", uno::Any(xStorage));
+
+ uno::Sequence<uno::Any> aFilterCreationArgs{ Any(xInfoSet) };
+
+ uno::Reference<document::XImporter> xImporter(m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs, m_pImpl->m_aContext), uno::UNO_QUERY_THROW);
+
+ uno::Reference<lang::XComponent> xComponent(*this, uno::UNO_QUERY_THROW);
+ xImporter->setTargetDocument(xComponent);
+
+ uno::Reference<document::XFilter> xFilter(xImporter, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aFilterArgs;
+ xFilter->filter(aFilterArgs);
+
+ // In case of embedding, XModel::attachResource is already called.
+ if (m_bEmbedded)
+ impl_setInitialized();
+
+ impl_setModified_nothrow(false, aGuard);
+}
+
+void SAL_CALL ODatabaseDocument::storeToStorage( const Reference< XStorage >& _rxStorage, const Sequence< PropertyValue >& _rMediaDescriptor )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_storeToStorage_throw( _rxStorage, _rMediaDescriptor, aGuard );
+}
+
+void SAL_CALL ODatabaseDocument::switchToStorage( const Reference< XStorage >& _rxNewRootStorage )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XStorage > xNewRootStorage( m_pImpl->switchToStorage( _rxNewRootStorage ) );
+
+ aGuard.clear();
+ impl_notifyStorageChange_nolck_nothrow( xNewRootStorage );
+}
+
+Reference< XStorage > SAL_CALL ODatabaseDocument::getDocumentStorage( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::MethodUsedDuringInit);
+ return m_pImpl->getOrCreateRootStorage();
+}
+
+void SAL_CALL ODatabaseDocument::addStorageChangeListener( const Reference< XStorageChangeListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aStorageListeners.addInterface( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::removeStorageChangeListener( const Reference< XStorageChangeListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aStorageListeners.addInterface( Listener );
+}
+
+Reference< XStorageBasedLibraryContainer > SAL_CALL ODatabaseDocument::getBasicLibraries()
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return m_pImpl->getLibraryContainer( true );
+}
+
+Reference< XStorageBasedLibraryContainer > SAL_CALL ODatabaseDocument::getDialogLibraries()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ return m_pImpl->getLibraryContainer( false );
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::getAllowMacroExecution()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ return m_pImpl->adjustMacroMode_AutoReject();
+}
+
+Reference< XEmbeddedScripts > SAL_CALL ODatabaseDocument::getScriptContainer()
+{
+ return this;
+}
+
+Reference< provider::XScriptProvider > SAL_CALL ODatabaseDocument::getScriptProvider( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XScriptProvider > xScriptProvider( m_xScriptProvider );
+ if ( !xScriptProvider.is() )
+ {
+ Reference < XScriptProviderFactory > xFactory =
+ theMasterScriptProviderFactory::get( m_pImpl->m_aContext );
+
+ Any aScriptProviderContext;
+ if ( m_bAllowDocumentScripting )
+ aScriptProviderContext <<= Reference< XModel >( this );
+
+ xScriptProvider.set( xFactory->createScriptProvider( aScriptProviderContext ), UNO_SET_THROW );
+ m_xScriptProvider = xScriptProvider;
+ }
+
+ return xScriptProvider;
+}
+
+Reference< XNameReplace > SAL_CALL ODatabaseDocument::getEvents( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return m_pEventContainer.get();
+}
+
+Reference< XInterface > ODatabaseDocument::getThis() const
+{
+ return *const_cast< ODatabaseDocument* >( this );
+}
+
+namespace {
+
+struct CreateAny
+{
+ Any operator() (const Reference<XController>& lhs) const
+ {
+ return Any(lhs);
+ }
+};
+
+}
+
+// XModel2
+Reference< XEnumeration > SAL_CALL ODatabaseDocument::getControllers( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ uno::Sequence< Any> aController( m_aControllers.size() );
+ std::transform( m_aControllers.begin(), m_aControllers.end(), aController.getArray(), CreateAny() );
+ return new ::comphelper::OAnyEnumeration(aController);
+}
+
+Sequence< OUString > SAL_CALL ODatabaseDocument::getAvailableViewControllerNames( )
+{
+ Sequence< OUString > aNames { SERVICE_SDB_APPLICATIONCONTROLLER };
+ return aNames;
+}
+
+Reference< XController2 > SAL_CALL ODatabaseDocument::createDefaultViewController( const Reference< XFrame >& Frame )
+{
+ return createViewController( "Default", Sequence< PropertyValue >(), Frame);
+}
+
+Reference< XController2 > SAL_CALL ODatabaseDocument::createViewController( const OUString& ViewName, const Sequence< PropertyValue >& Arguments, const Reference< XFrame >& Frame )
+{
+ if ( ViewName != "Default" && ViewName != "Preview" )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ if ( !Frame.is() )
+ throw IllegalArgumentException( OUString(), *this, 3 );
+
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ aGuard.clear();
+
+ Reference< XController2 > xController(
+ m_pImpl->m_aContext->getServiceManager()->createInstanceWithContext("org.openoffice.comp.dbu.OApplicationController", m_pImpl->m_aContext),
+ UNO_QUERY_THROW );
+
+ ::comphelper::NamedValueCollection aInitArgs( Arguments );
+ aInitArgs.put( "Frame", Frame );
+ if ( ViewName == "Preview" )
+ aInitArgs.put( "Preview", true );
+ Reference< XInitialization > xInitController( xController, UNO_QUERY_THROW );
+ xInitController->initialize( aInitArgs.getWrappedPropertyValues() );
+
+ return xController;
+}
+
+Reference< XTitle > const & ODatabaseDocument::impl_getTitleHelper_throw()
+{
+ if ( ! m_xTitleHelper.is ())
+ {
+ Reference< XUntitledNumbers > xDesktop(Desktop::create(m_pImpl->m_aContext), uno::UNO_QUERY_THROW);
+ Reference< frame::XModel > xThis (getThis(), uno::UNO_QUERY_THROW);
+
+ m_xTitleHelper = new ::framework::TitleHelper(m_pImpl->m_aContext, xThis, xDesktop);
+ }
+
+ return m_xTitleHelper;
+}
+
+uno::Reference< frame::XUntitledNumbers > ODatabaseDocument::impl_getUntitledHelper_throw(const uno::Reference< uno::XInterface >& _xComponent)
+{
+ if ( !m_xModuleManager.is() )
+ m_xModuleManager.set( ModuleManager::create(m_pImpl->m_aContext) );
+
+ OUString sModuleId;
+ if (_xComponent.is())
+ sModuleId = m_xModuleManager->identify(_xComponent);
+
+ uno::Reference< frame::XUntitledNumbers > xNumberedControllers;
+
+ TNumberedController::const_iterator aFind = m_aNumberedControllers.find(sModuleId);
+ if ( aFind == m_aNumberedControllers.end() )
+ {
+ rtl::Reference<::comphelper::NumberedCollection> pHelper = new ::comphelper::NumberedCollection();
+ xNumberedControllers = pHelper;
+ pHelper->setOwner(uno::Reference< frame::XModel >(this));
+
+ m_aNumberedControllers.emplace( sModuleId,xNumberedControllers );
+ }
+ else
+ xNumberedControllers = aFind->second;
+
+ return xNumberedControllers;
+}
+
+// css.frame.XTitle
+OUString SAL_CALL ODatabaseDocument::getTitle()
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return impl_getTitleHelper_throw()->getTitle();
+}
+
+// css.frame.XTitle
+void SAL_CALL ODatabaseDocument::setTitle( const OUString& sTitle )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_getTitleHelper_throw()->setTitle( sTitle );
+ m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" );
+ // <- SYNCHRONIZED
+}
+
+// css.frame.XTitleChangeBroadcaster
+void SAL_CALL ODatabaseDocument::addTitleChangeListener( const uno::Reference< frame::XTitleChangeListener >& xListener )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ uno::Reference< frame::XTitleChangeBroadcaster > xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW );
+ xBroadcaster->addTitleChangeListener( xListener );
+}
+
+// css.frame.XTitleChangeBroadcaster
+void SAL_CALL ODatabaseDocument::removeTitleChangeListener( const uno::Reference< frame::XTitleChangeListener >& xListener )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ uno::Reference< frame::XTitleChangeBroadcaster > xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW );
+ xBroadcaster->removeTitleChangeListener( xListener );
+}
+
+// css.frame.XUntitledNumbers
+::sal_Int32 SAL_CALL ODatabaseDocument::leaseNumber( const uno::Reference< uno::XInterface >& xComponent )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ return impl_getUntitledHelper_throw(xComponent)->leaseNumber (xComponent);
+}
+
+// css.frame.XUntitledNumbers
+void SAL_CALL ODatabaseDocument::releaseNumber( ::sal_Int32 nNumber )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_getUntitledHelper_throw()->releaseNumber (nNumber);
+}
+
+// css.frame.XUntitledNumbers
+void SAL_CALL ODatabaseDocument::releaseNumberForComponent( const uno::Reference< uno::XInterface >& xComponent )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_getUntitledHelper_throw(xComponent)->releaseNumberForComponent (xComponent);
+}
+
+// css.frame.XUntitledNumbers
+OUString SAL_CALL ODatabaseDocument::getUntitledPrefix()
+{
+ return OUString();
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ODatabaseDocument(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ Reference<XUnoTunnel> xDBContextTunnel(DatabaseContext::create(context), UNO_QUERY_THROW);
+ dbaccess::ODatabaseContext* pContext
+ = comphelper::getFromUnoTunnel<dbaccess::ODatabaseContext>(xDBContextTunnel);
+ assert(pContext);
+
+ rtl::Reference pImpl(
+ new dbaccess::ODatabaseModelImpl(context, *pContext));
+ css::uno::Reference<XInterface> inst(pImpl->createNewModel_deliverOwnership());
+ inst->acquire();
+ return inst.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databasedocument.hxx b/dbaccess/source/core/dataaccess/databasedocument.hxx
new file mode 100644
index 000000000..bd458d1b9
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databasedocument.hxx
@@ -0,0 +1,753 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <memory>
+
+#include <ModelImpl.hxx>
+#include "documenteventnotifier.hxx"
+
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <com/sun/star/frame/DoubleInitializationException.hpp>
+#include <com/sun/star/frame/XModel3.hpp>
+#include <com/sun/star/frame/XTitle.hpp>
+#include <com/sun/star/frame/XTitleChangeBroadcaster.hpp>
+#include <com/sun/star/frame/XUntitledNumbers.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <com/sun/star/view/XPrintable.hpp>
+#include <com/sun/star/frame/XModuleManager2.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/NotInitializedException.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
+#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
+#include <com/sun/star/frame/XLoadable.hpp>
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/document/XDocumentRecovery.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager2.hpp>
+#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <rtl/ref.hxx>
+
+namespace comphelper {
+ class NamedValueCollection;
+}
+
+namespace dbaccess
+{
+
+class DocumentEvents;
+class DocumentEventExecutor;
+class DocumentGuard;
+
+typedef std::vector< css::uno::Reference< css::frame::XController > > Controllers;
+
+// ViewMonitor
+/** helper class monitoring the views of a document, and firing appropriate events
+ when views are attached / detached
+*/
+class ViewMonitor
+{
+public:
+ explicit ViewMonitor( DocumentEventNotifier& _rEventNotifier )
+ :m_rEventNotifier( _rEventNotifier )
+ ,m_bIsNewDocument( true )
+ ,m_bEverHadController( false )
+ ,m_bLastIsFirstEverController( false )
+ ,m_xLastConnectedController()
+ {
+ }
+
+ ViewMonitor(const ViewMonitor&) = delete;
+ const ViewMonitor& operator=(const ViewMonitor&) = delete;
+
+ void reset()
+ {
+ m_bEverHadController = false;
+ m_bLastIsFirstEverController = false;
+ m_xLastConnectedController.clear();
+ }
+
+ /** to be called when a view (aka controller) has been connected to the document
+ @return
+ <TRUE/> if and only if this was the first-ever controller connected to the document
+ */
+ bool onControllerConnected(
+ const css::uno::Reference< css::frame::XController >& _rxController
+ );
+
+ /** to be called when a controller is set as current controller
+ @return <TRUE/>
+ if and only if the controller connection indicates that loading the document is finished. This
+ is the case if the given controller has previously been connected, and it was the first controller
+ ever for which this happened.
+ */
+ bool onSetCurrentController(
+ const css::uno::Reference< css::frame::XController >& _rxController
+ );
+
+ void onLoadedDocument() { m_bIsNewDocument = false; }
+
+private:
+ DocumentEventNotifier& m_rEventNotifier;
+ bool m_bIsNewDocument;
+ bool m_bEverHadController;
+ bool m_bLastIsFirstEverController;
+ css::uno::Reference< css::frame::XController >
+ m_xLastConnectedController;
+};
+
+// ODatabaseDocument
+typedef cppu::PartialWeakComponentImplHelper< css::frame::XModel3
+ , css::util::XModifiable
+ , css::frame::XStorable
+ , css::document::XEventBroadcaster
+ , css::document::XDocumentEventBroadcaster
+ , css::view::XPrintable
+ , css::util::XCloseable
+ , css::lang::XServiceInfo
+ , css::sdb::XOfficeDatabaseDocument
+ , css::ui::XUIConfigurationManagerSupplier
+ , css::document::XStorageBasedDocument
+ , css::document::XEmbeddedScripts
+ , css::document::XScriptInvocationContext
+ , css::script::provider::XScriptProviderSupplier
+ , css::document::XEventsSupplier
+ , css::frame::XLoadable
+ , css::document::XDocumentRecovery
+ > ODatabaseDocument_OfficeDocument;
+
+typedef ::cppu::ImplHelper3< css::frame::XTitle
+ , css::frame::XTitleChangeBroadcaster
+ , css::frame::XUntitledNumbers
+ > ODatabaseDocument_Title;
+
+class ODatabaseDocument :public ModelDependentComponent // ModelDependentComponent must be first!
+ ,public ODatabaseDocument_OfficeDocument
+ ,public ODatabaseDocument_Title
+{
+ enum InitState
+ {
+ NotInitialized,
+ Initializing,
+ Initialized
+ };
+
+ typedef std::map< OUString, css::uno::Reference< css::frame::XUntitledNumbers > > TNumberedController;
+ css::uno::Reference< css::ui::XUIConfigurationManager2> m_xUIConfigurationManager;
+
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener> m_aModifyListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::util::XCloseListener> m_aCloseListener;
+ ::comphelper::OInterfaceContainerHelper3<css::document::XStorageChangeListener> m_aStorageListeners;
+
+ std::unique_ptr<DocumentEvents> m_pEventContainer;
+ ::rtl::Reference< DocumentEventExecutor > m_pEventExecutor;
+ DocumentEventNotifier m_aEventNotifier;
+
+ css::uno::Reference< css::frame::XController > m_xCurrentController;
+ Controllers m_aControllers;
+ ViewMonitor m_aViewMonitor;
+
+ css::uno::WeakReference< css::container::XNameAccess > m_xForms;
+ css::uno::WeakReference< css::container::XNameAccess > m_xReports;
+ css::uno::WeakReference< css::script::provider::XScriptProvider > m_xScriptProvider;
+
+ /** @short such module manager is used to classify new opened documents. */
+ css::uno::Reference< css::frame::XModuleManager2 > m_xModuleManager;
+ css::uno::Reference< css::frame::XTitle > m_xTitleHelper;
+ TNumberedController m_aNumberedControllers;
+
+ /** true if and only if the DatabaseDocument's "initNew" or "load" have been called (or, well,
+ the document has be initialized implicitly - see storeAsURL
+ */
+ InitState m_eInitState;
+ bool m_bClosing;
+ bool m_bAllowDocumentScripting;
+ bool m_bHasBeenRecovered;
+ /// If XModel::attachResource() was called to inform us that the document is embedded into another one.
+ bool m_bEmbedded;
+
+ enum StoreType { SAVE, SAVE_AS };
+ /** stores the document to the given URL, rebases it to the respective new storage, if necessary, resets
+ the modified flag, and notifies any listeners as required
+
+ @param _rURL
+ the URL to store the document to
+ @param _rArguments
+ arguments for storing the document (MediaDescriptor)
+ @param _eType
+ the type of the store process (Save or SaveAs). The method will automatically
+ notify the proper events for this type.
+ @param _rGuard
+ the instance lock to be released before doing synchronous notifications
+ @throws css::io::IOException
+ @throws css::uno::RuntimeException
+ */
+ void impl_storeAs_throw(
+ const OUString& _rURL,
+ const ::comphelper::NamedValueCollection& _rArguments,
+ const StoreType _eType,
+ DocumentGuard& _rGuard
+ );
+
+ /** notifies our storage change listeners that our underlying storage changed
+
+ @param _rxNewRootStorage
+ the new root storage to be notified. If <NULL/>, it is assumed that no storage change actually
+ happened, and the listeners are not notified.
+ */
+ void impl_notifyStorageChange_nolck_nothrow(
+ const css::uno::Reference< css::embed::XStorage >& _rxNewRootStorage
+ );
+
+ /// write a single XML stream into the package
+ void WriteThroughComponent(
+ const css::uno::Reference< css::lang::XComponent > & xComponent, /// the component we export
+ const char* pStreamName, /// the stream name
+ const char* pServiceName, /// service name of the component
+ const css::uno::Sequence< css::uno::Any> & rArguments, /// the argument (XInitialization)
+ const css::uno::Sequence< css::beans::PropertyValue> & rMediaDesc,/// output descriptor
+ const css::uno::Reference< css::embed::XStorage >& _xStorageToSaveTo
+ ) const;
+
+ /// write a single output stream
+ /// (to be called either directly or by WriteThroughComponent(...))
+ void WriteThroughComponent(
+ const css::uno::Reference< css::io::XOutputStream >& xOutputStream,
+ const css::uno::Reference< css::lang::XComponent >& xComponent,
+ const char* pServiceName,
+ const css::uno::Sequence< css::uno::Any >& rArguments,
+ const css::uno::Sequence< css::beans::PropertyValue> & rMediaDesc
+ ) const;
+
+ /** writes the content and settings
+ @param sURL
+ The URL
+ @param lArguments
+ The media descriptor
+ @param _xStorageToSaveTo
+ The storage which should be used for saving
+ */
+ void impl_writeStorage_throw(
+ const css::uno::Reference< css::embed::XStorage >& _rxTargetStorage,
+ const ::comphelper::NamedValueCollection& _rMediaDescriptor
+ ) const;
+
+ // ModelDependentComponent overridables
+ virtual css::uno::Reference< css::uno::XInterface > getThis() const override;
+
+ css::uno::Reference< css::frame::XTitle > const & impl_getTitleHelper_throw();
+ css::uno::Reference< css::frame::XUntitledNumbers > impl_getUntitledHelper_throw(
+ const css::uno::Reference< css::uno::XInterface >& _xComponent = css::uno::Reference< css::uno::XInterface >());
+
+private:
+ explicit ODatabaseDocument(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl);
+ // Do NOT create those documents directly, always use ODatabaseModelImpl::getModel. Reason is that
+ // ODatabaseDocument requires clear ownership, and in turn lifetime synchronisation with the ModelImpl.
+ // If you create a ODatabaseDocument directly, you might easily create a leak.
+ // #i50905#
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+ virtual ~ODatabaseDocument() override;
+
+public:
+ struct FactoryAccess { friend class ODatabaseModelImpl; private: FactoryAccess() { } };
+ static rtl::Reference<ODatabaseDocument> createDatabaseDocument( const ::rtl::Reference<ODatabaseModelImpl>& _pImpl, FactoryAccess /*accessControl*/ )
+ {
+ return new ODatabaseDocument( _pImpl );
+ }
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XModel
+ virtual sal_Bool SAL_CALL attachResource( const OUString& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override ;
+ virtual OUString SAL_CALL getURL( ) override ;
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getArgs( ) override ;
+ virtual void SAL_CALL connectController( const css::uno::Reference< css::frame::XController >& Controller ) override ;
+ virtual void SAL_CALL disconnectController( const css::uno::Reference< css::frame::XController >& Controller ) override ;
+ virtual void SAL_CALL lockControllers( ) override ;
+ virtual void SAL_CALL unlockControllers( ) override ;
+ virtual sal_Bool SAL_CALL hasControllersLocked( ) override ;
+ virtual css::uno::Reference< css::frame::XController > SAL_CALL getCurrentController( ) override ;
+ virtual void SAL_CALL setCurrentController( const css::uno::Reference< css::frame::XController >& Controller ) override ;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getCurrentSelection( ) override ;
+
+ // XModel2
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL getControllers( ) override ;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableViewControllerNames( ) override ;
+ virtual css::uno::Reference< css::frame::XController2 > SAL_CALL createDefaultViewController( const css::uno::Reference< css::frame::XFrame >& Frame ) override ;
+ virtual css::uno::Reference< css::frame::XController2 > SAL_CALL createViewController( const OUString& ViewName, const css::uno::Sequence< css::beans::PropertyValue >& Arguments, const css::uno::Reference< css::frame::XFrame >& Frame ) override ;
+ virtual void SAL_CALL setArgs(const css::uno::Sequence<css::beans::PropertyValue>& aArgs) override;
+
+ // XModel3
+ virtual ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL getArgs2( const ::css::uno::Sequence< ::rtl::OUString >& requestedArgs ) override;
+
+ // XStorable
+ virtual sal_Bool SAL_CALL hasLocation( ) override ;
+ virtual OUString SAL_CALL getLocation( ) override ;
+ virtual sal_Bool SAL_CALL isReadonly( ) override ;
+ virtual void SAL_CALL store( ) override ;
+ virtual void SAL_CALL storeAsURL( const OUString& sURL, const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override ;
+ virtual void SAL_CALL storeToURL( const OUString& sURL, const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override ;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // css::util::XModifiable
+ virtual sal_Bool SAL_CALL isModified( ) override ;
+ virtual void SAL_CALL setModified( sal_Bool bModified ) override ;
+
+ // XEventBroadcaster
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::document::XEventListener >& aListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::document::XEventListener >& aListener ) override;
+
+ // XDocumentEventBroadcaster
+ virtual void SAL_CALL addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
+ virtual void SAL_CALL removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
+ virtual void SAL_CALL notifyDocumentEvent( const OUString& EventName, const css::uno::Reference< css::frame::XController2 >& ViewController, const css::uno::Any& Supplement ) override;
+
+ // XPrintable
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getPrinter( ) override ;
+ virtual void SAL_CALL setPrinter( const css::uno::Sequence< css::beans::PropertyValue >& aPrinter ) override ;
+ virtual void SAL_CALL print( const css::uno::Sequence< css::beans::PropertyValue >& xOptions ) override ;
+
+ // XFormDocumentsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getFormDocuments( ) override;
+
+ // XReportDocumentsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getReportDocuments( ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( sal_Bool DeliverOwnership ) override;
+ virtual void SAL_CALL addCloseListener( const css::uno::Reference< css::util::XCloseListener >& Listener ) override;
+ virtual void SAL_CALL removeCloseListener( const css::uno::Reference< css::util::XCloseListener >& Listener ) override;
+
+ // XUIConfigurationManagerSupplier
+ virtual css::uno::Reference< css::ui::XUIConfigurationManager > SAL_CALL getUIConfigurationManager( ) override;
+
+ // XDocumentSubStorageSupplier
+ virtual css::uno::Reference< css::embed::XStorage > SAL_CALL getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getDocumentSubStoragesNames( ) override;
+
+ // XOfficeDatabaseDocument
+ virtual css::uno::Reference< css::sdbc::XDataSource > SAL_CALL getDataSource() override;
+
+ // XStorageBasedDocument
+ virtual void SAL_CALL loadFromStorage( const css::uno::Reference< css::embed::XStorage >& xStorage, const css::uno::Sequence< css::beans::PropertyValue >& aMediaDescriptor ) override;
+ virtual void SAL_CALL storeToStorage( const css::uno::Reference< css::embed::XStorage >& xStorage, const css::uno::Sequence< css::beans::PropertyValue >& aMediaDescriptor ) override;
+ virtual void SAL_CALL switchToStorage( const css::uno::Reference< css::embed::XStorage >& xStorage ) override;
+ virtual css::uno::Reference< css::embed::XStorage > SAL_CALL getDocumentStorage( ) override;
+ virtual void SAL_CALL addStorageChangeListener( const css::uno::Reference< css::document::XStorageChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeStorageChangeListener( const css::uno::Reference< css::document::XStorageChangeListener >& xListener ) override;
+
+ // XEmbeddedScripts
+ virtual css::uno::Reference< css::script::XStorageBasedLibraryContainer > SAL_CALL getBasicLibraries() override;
+ virtual css::uno::Reference< css::script::XStorageBasedLibraryContainer > SAL_CALL getDialogLibraries() override;
+ virtual sal_Bool SAL_CALL getAllowMacroExecution() override;
+
+ // XScriptInvocationContext
+ virtual css::uno::Reference< css::document::XEmbeddedScripts > SAL_CALL getScriptContainer() override;
+
+ // XScriptProviderSupplier
+ virtual css::uno::Reference< css::script::provider::XScriptProvider > SAL_CALL getScriptProvider( ) override;
+
+ // XEventsSupplier
+ virtual css::uno::Reference< css::container::XNameReplace > SAL_CALL getEvents( ) override;
+
+ // XLoadable
+ virtual void SAL_CALL initNew( ) override;
+ virtual void SAL_CALL load( const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+
+ // css.document.XDocumentRecovery
+ virtual sal_Bool SAL_CALL wasModifiedSinceLastSave() override;
+ virtual void SAL_CALL storeToRecoveryFile( const OUString& i_TargetLocation, const css::uno::Sequence< css::beans::PropertyValue >& i_MediaDescriptor ) override;
+ virtual void SAL_CALL recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const css::uno::Sequence< css::beans::PropertyValue >& i_MediaDescriptor ) override;
+
+ // XTitle
+ virtual OUString SAL_CALL getTitle( ) override;
+ virtual void SAL_CALL setTitle( const OUString& sTitle ) override;
+
+ // XTitleChangeBroadcaster
+ virtual void SAL_CALL addTitleChangeListener( const css::uno::Reference< css::frame::XTitleChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeTitleChangeListener( const css::uno::Reference< css::frame::XTitleChangeListener >& xListener ) override;
+
+ // XUntitledNumbers
+ virtual ::sal_Int32 SAL_CALL leaseNumber( const css::uno::Reference< css::uno::XInterface >& xComponent ) override;
+ virtual void SAL_CALL releaseNumber( ::sal_Int32 nNumber ) override;
+ virtual void SAL_CALL releaseNumberForComponent( const css::uno::Reference< css::uno::XInterface >& xComponent ) override;
+ virtual OUString SAL_CALL getUntitledPrefix( ) override;
+
+ /** clears the given object container
+
+ Clearing is done via disposal - the method calls XComponent::dispose at the given object,
+ which must be one of our impl's or our object containers (m_xForms, m_xReports,
+ m_xTableDefinitions, m_xCommandDefinitions)
+
+ @param _rxContainer
+ the container to clear
+ */
+ static void clearObjectContainer(
+ css::uno::WeakReference< css::container::XNameAccess >& _rxContainer);
+
+ /** checks whether the component is already initialized, throws a NotInitializedException if not
+ */
+ void checkInitialized() const
+ {
+ if ( !impl_isInitialized() )
+ throw css::lang::NotInitializedException( OUString(), getThis() );
+ }
+
+ /** checks the document is currently in the initialization phase, or already initialized.
+ Throws NotInitializedException if not so.
+ */
+ void checkNotUninitialized() const
+ {
+ if ( impl_isInitialized() || impl_isInitializing() )
+ // fine
+ return;
+
+ throw css::lang::NotInitializedException( OUString(), getThis() );
+ }
+
+ /** checks whether the document is currently being initialized, or already initialized,
+ throws a DoubleInitializationException if so
+ */
+ void checkNotInitialized() const
+ {
+ if ( impl_isInitializing() || impl_isInitialized() )
+ throw css::frame::DoubleInitializationException( OUString(), getThis() );
+ }
+
+private:
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::ui::XUIConfigurationManager2 > const & getUIConfigurationManager2();
+
+ /** returns whether the model is currently being initialized
+ */
+ bool impl_isInitializing() const { return m_eInitState == Initializing; }
+
+ /** returns whether the model is already initialized, i.e. the XModel's "initNew" or "load" methods have been called
+ */
+ bool impl_isInitialized() const { return m_eInitState == Initialized; }
+
+ /// tells the model it is being initialized now
+ void impl_setInitializing() { m_eInitState = Initializing; }
+
+ /// tells the model its initialization is done
+ void impl_setInitialized();
+
+ /** closes the frames of all connected controllers
+
+ @param _bDeliverOwnership
+ determines if the ownership should be transferred to the component which
+ possibly vetos the closing
+
+ @throws css::util::CloseVetoException
+ if the closing was vetoed by any instance
+ */
+ void impl_closeControllerFrames_nolck_throw( bool _bDeliverOwnership );
+
+ /** disposes the frames of all controllers which are still left in m_aControllers.
+ */
+ void impl_disposeControllerFrames_nothrow();
+
+ /** does a reparenting at the given object container to ourself
+
+ Calls XChild::setParent at the given object, which must be one of our impl's or our
+ object containers (m_xForms, m_xReports, m_xTableDefinitions, m_xCommandDefinitions)
+ */
+ void impl_reparent_nothrow( const css::uno::WeakReference< css::container::XNameAccess >& _rxContainer );
+
+ /** retrieves the forms or reports contained, creates and initializes it, if necessary
+
+ @throws DisposedException
+ if the instance is already disposed
+ @throws IllegalArgumentException
+ if <arg>_eType</arg> is not ODatabaseModelImpl::E_FORM and not ODatabaseModelImpl::E_REPORT
+ */
+ css::uno::Reference< css::container::XNameAccess >
+ impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType );
+
+ /** resets everything
+
+ @precond
+ m_pImpl is not <NULL/>
+ */
+ void
+ impl_reset_nothrow();
+
+ /** imports the document from the given resource.
+ */
+ static void
+ impl_import_nolck_throw(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::uno::XInterface >& _rxTargetComponent,
+ const ::comphelper::NamedValueCollection& _rResource
+ );
+
+ /** creates a storage for the given URL, truncating it if a file with this name already exists
+
+ @throws Exception
+ if creating the storage failed
+
+ @return
+ the newly created storage for the file at the given URL
+ */
+ css::uno::Reference< css::embed::XStorage >
+ impl_createStorageFor_throw(
+ const OUString& _rURL
+ ) const;
+
+ /** Extracts storage from arguments, or creates for the given URL, truncating it if a file with
+ this name already exists
+
+ @throws Exception
+ if creating the storage failed
+
+ @return
+ the storage that is either extracted from arguments, or newly created for the file at
+ the given URL
+ */
+ css::uno::Reference<css::embed::XStorage> impl_GetStorageOrCreateFor_throw(
+ const ::comphelper::NamedValueCollection& _rArguments, const OUString& _rURL) const;
+
+ /** sets our "modified" flag
+
+ will notify all our respective listeners, if the "modified" state actually changed
+
+ @param _bModified
+ the (new) flag indicating whether the document is currently modified or not
+ @param _rGuard
+ the guard for our instance. At method entry, the guard must hold the lock. At the moment
+ of method leave, the lock will be released.
+ @precond
+ our mutex is locked
+ @postcond
+ our mutex is not locked
+ */
+ void impl_setModified_nothrow( bool _bModified, DocumentGuard& _rGuard );
+
+ /** stores the document to the given storage
+
+ Note that the document is actually not rebased to this storage, it just stores a copy of itself
+ to the given target storage.
+
+ @param _rxTargetStorage
+ denotes the storage to store the document into
+ @param _rMediaDescriptor
+ contains additional parameters for storing the document
+ @param _rDocGuard
+ a guard which holds the (only) lock to the document, and which will be temporarily
+ released where necessary (e.g. for notifications, or calling into other components)
+
+ @throws css::uno::IllegalArgumentException
+ if the given storage is <NULL/>.
+
+ @throws css::uno::RuntimeException
+ when any of the used operations throws it
+
+ @throws css::io::IOException
+ when any of the used operations throws it, or any other exception occurs which is no
+ RuntimeException and no IOException
+ */
+ void impl_storeToStorage_throw(
+ const css::uno::Reference< css::embed::XStorage >& _rxTargetStorage,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rMediaDescriptor,
+ DocumentGuard& _rDocGuard
+ ) const;
+
+ /** impl-version of attachResource
+
+ @param i_rLogicalDocumentURL
+ denotes the logical URL of the document, to be reported by getURL/getLocation
+ @param i_rMediaDescriptor
+ denotes additional document parameters
+ @param _rDocGuard
+ is the guard which currently protects the document instance
+ */
+ bool impl_attachResource(
+ const OUString& i_rLogicalDocumentURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rMediaDescriptor,
+ DocumentGuard& _rDocGuard
+ );
+
+ /** throws an IOException with the message as defined in the RID_STR_ERROR_WHILE_SAVING resource, wrapping
+ the given caught non-IOException error
+ */
+ void impl_throwIOExceptionCausedBySave_throw(
+ const css::uno::Any& i_rError,
+ std::u16string_view i_rTargetURL
+ ) const;
+};
+
+/** an extended version of the ModelMethodGuard, which also cares for the initialization state
+ of the document
+*/
+class DocumentGuard : private ModelMethodGuard
+{
+public:
+ enum InitMethod_
+ {
+ // a method which is to initialize the document
+ InitMethod,
+ };
+
+ enum DefaultMethod_
+ {
+ // a default method
+ DefaultMethod
+ };
+
+ enum MethodUsedDuringInit_
+ {
+ // a method which is used (externally) during the initialization phase
+ MethodUsedDuringInit
+ };
+
+ enum MethodWithoutInit_
+ {
+ // a method which does not need initialization - use with care!
+ MethodWithoutInit
+ };
+
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+
+ @throws css::lang::NotInitializedException
+ if the given component is not yet initialized
+ */
+ DocumentGuard(const ODatabaseDocument& _document, DefaultMethod_)
+ : ModelMethodGuard(_document)
+ , m_document(_document )
+ {
+ m_document.checkInitialized();
+ }
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+
+ @throws css::frame::DoubleInitializationException
+ if the given component is already initialized, or currently being initialized.
+ */
+ DocumentGuard(const ODatabaseDocument& _document, InitMethod_)
+ : ModelMethodGuard(_document)
+ , m_document(_document)
+ {
+ m_document.checkNotInitialized();
+ }
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+
+ @throws css::lang::NotInitializedException
+ if the component is still uninitialized, and not in the initialization
+ phase currently.
+ */
+ DocumentGuard(const ODatabaseDocument& _document, MethodUsedDuringInit_)
+ : ModelMethodGuard(_document)
+ , m_document(_document)
+ {
+ m_document.checkNotUninitialized();
+ }
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+ */
+ DocumentGuard(const ODatabaseDocument& _document, MethodWithoutInit_)
+ : ModelMethodGuard( _document )
+ , m_document( _document )
+ {
+ }
+
+ void clear()
+ {
+ ModelMethodGuard::clear();
+ }
+ void reset()
+ {
+ ModelMethodGuard::reset();
+ m_document.checkDisposed();
+ }
+
+private:
+
+ const ODatabaseDocument& m_document;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.cxx b/dbaccess/source/core/dataaccess/databaseregistrations.cxx
new file mode 100644
index 000000000..40fa526d1
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databaseregistrations.cxx
@@ -0,0 +1,369 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <osl/diagnose.h>
+#include <unotools/pathoptions.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/confignode.hxx>
+
+#include "databaseregistrations.hxx"
+
+namespace dbaccess
+{
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::lang::IllegalAccessException;
+ using ::com::sun::star::container::ElementExistException;
+ using ::com::sun::star::sdb::XDatabaseRegistrations;
+ using ::com::sun::star::sdb::XDatabaseRegistrationsListener;
+ using ::com::sun::star::sdb::DatabaseRegistrationEvent;
+ using ::com::sun::star::uno::XAggregation;
+
+ static OUString getConfigurationRootPath()
+ {
+ return "org.openoffice.Office.DataAccess/RegisteredNames";
+ }
+
+ static OUString getLocationNodeName()
+ {
+ return "Location";
+ }
+
+ static OUString getNameNodeName()
+ {
+ return "Name";
+ }
+
+ // DatabaseRegistrations - declaration
+ typedef ::cppu::WeakAggImplHelper1 < XDatabaseRegistrations
+ > DatabaseRegistrations_Base;
+
+ namespace {
+
+ class DatabaseRegistrations :public ::cppu::BaseMutex
+ ,public DatabaseRegistrations_Base
+ {
+ public:
+ explicit DatabaseRegistrations( const Reference<XComponentContext>& _rxContext );
+
+ protected:
+ virtual ~DatabaseRegistrations() override;
+
+ public:
+ virtual sal_Bool SAL_CALL hasRegisteredDatabase( const OUString& Name ) override;
+ virtual Sequence< OUString > SAL_CALL getRegistrationNames() override;
+ virtual OUString SAL_CALL getDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL registerDatabaseLocation( const OUString& Name, const OUString& Location ) override;
+ virtual void SAL_CALL revokeDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL changeDatabaseLocation( const OUString& Name, const OUString& NewLocation ) override;
+ virtual sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const OUString& Name ) override;
+ virtual void SAL_CALL addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) override;
+ virtual void SAL_CALL removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) override;
+
+ private:
+ void
+ impl_checkValidName_common(std::u16string_view _rName);
+ ::utl::OConfigurationNode
+ impl_checkValidName_throw_must_exist(const OUString& _rName);
+ ::utl::OConfigurationNode
+ impl_checkValidName_throw_must_not_exist(const OUString& _rName);
+
+ void impl_checkValidLocation_throw( std::u16string_view _rLocation );
+
+ /** retrieves the configuration node whose "Name" sub node has the given value
+
+ Since we separated the name of the registration node from the "Name" value of the registration, we cannot
+ simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name.
+ Instead, we must search all nodes.
+
+ If a node with the given display name does not exist, then a NoSuchElementException is thrown.
+
+ If no exception is thrown, then a valid node is returned: If the node existed it is returned.
+ */
+ ::utl::OConfigurationNode
+ impl_getNodeForName_throw_must_exist(const OUString& _rName);
+
+ /** retrieves the configuration node whose "Name" sub node has the given value
+
+ Since we separated the name of the registration node from the "Name" value of the registration, we cannot
+ simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name.
+ Instead, we must search all nodes.
+
+ If a node with the given name already exists, then an ElementExistException is thrown.
+
+ If no exception is thrown, then a valid node is returned: If the node did not yet exist a new node is created,
+ in this case the root node is not yet committed.
+ */
+ ::utl::OConfigurationNode
+ impl_getNodeForName_throw_must_not_exist(const OUString& _rName);
+
+
+ ::utl::OConfigurationNode
+ impl_getNodeForName_nothrow(std::u16string_view _rName);
+
+ private:
+ Reference<XComponentContext> m_aContext;
+ ::utl::OConfigurationTreeRoot m_aConfigurationRoot;
+ ::comphelper::OInterfaceContainerHelper3<XDatabaseRegistrationsListener> m_aRegistrationListeners;
+ };
+
+ }
+
+ // DatabaseRegistrations - implementation
+ DatabaseRegistrations::DatabaseRegistrations( const Reference<XComponentContext> & _rxContext )
+ :m_aContext( _rxContext )
+ ,m_aRegistrationListeners( m_aMutex )
+ {
+ m_aConfigurationRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ m_aContext, getConfigurationRootPath() );
+ }
+
+ DatabaseRegistrations::~DatabaseRegistrations()
+ {
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_nothrow( std::u16string_view _rName )
+ {
+ const Sequence< OUString > aNames( m_aConfigurationRoot.getNodeNames() );
+ for ( auto const & nodeName : aNames )
+ {
+ ::utl::OConfigurationNode aNodeForName = m_aConfigurationRoot.openNode( nodeName );
+
+ OUString sTestName;
+ OSL_VERIFY( aNodeForName.getNodeValue( getNameNodeName() ) >>= sTestName );
+ if ( sTestName == _rName )
+ return aNodeForName;
+ }
+ return ::utl::OConfigurationNode();
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw_must_exist(const OUString& _rName)
+ {
+ ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) );
+
+ if (!aNodeForName.isValid())
+ {
+ throw NoSuchElementException( _rName, *this );
+ }
+
+ return aNodeForName;
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw_must_not_exist(const OUString& _rName)
+ {
+ ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) );
+
+ if (aNodeForName.isValid())
+ throw ElementExistException( _rName, *this );
+
+ // make unique
+ OUString sNewNodeName = "org.openoffice." + _rName;
+ while ( m_aConfigurationRoot.hasByName( sNewNodeName ) )
+ {
+ sNewNodeName = "org.openoffice." + _rName + " 2";
+ }
+
+ ::utl::OConfigurationNode aNewNode( m_aConfigurationRoot.createNode( sNewNodeName ) );
+ aNewNode.setNodeValue( getNameNodeName(), Any( _rName ) );
+ return aNewNode;
+ }
+
+ void DatabaseRegistrations::impl_checkValidName_common(std::u16string_view _rName)
+ {
+ if ( !m_aConfigurationRoot.isValid() )
+ throw RuntimeException( OUString(), *this );
+
+ if ( _rName.empty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw_must_exist(const OUString& _rName)
+ {
+ impl_checkValidName_common(_rName);
+ return impl_getNodeForName_throw_must_exist(_rName);
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw_must_not_exist(const OUString& _rName)
+ {
+ impl_checkValidName_common(_rName);
+ return impl_getNodeForName_throw_must_not_exist(_rName);
+ }
+
+ void DatabaseRegistrations::impl_checkValidLocation_throw( std::u16string_view _rLocation )
+ {
+ if ( _rLocation.empty() )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+
+ INetURLObject aURL( _rLocation );
+ if ( aURL.GetProtocol() == INetProtocol::NotValid )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+ }
+
+ sal_Bool SAL_CALL DatabaseRegistrations::hasRegisteredDatabase( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::utl::OConfigurationNode aNodeForName = impl_getNodeForName_nothrow( Name );
+ return aNodeForName.isValid();
+ }
+
+ Sequence< OUString > SAL_CALL DatabaseRegistrations::getRegistrationNames()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_aConfigurationRoot.isValid() )
+ throw RuntimeException( OUString(), *this );
+
+ const Sequence< OUString > aProgrammaticNames( m_aConfigurationRoot.getNodeNames() );
+ Sequence< OUString > aDisplayNames( aProgrammaticNames.getLength() );
+ OUString* pDisplayName = aDisplayNames.getArray();
+
+ for ( auto const & name : aProgrammaticNames )
+ {
+ ::utl::OConfigurationNode aRegistrationNode = m_aConfigurationRoot.openNode( name );
+ OSL_VERIFY( aRegistrationNode.getNodeValue( getNameNodeName() ) >>= *pDisplayName );
+ ++pDisplayName;
+ }
+
+ return aDisplayNames;
+ }
+
+ OUString SAL_CALL DatabaseRegistrations::getDatabaseLocation( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw_must_exist(Name);
+
+ OUString sLocation;
+ OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation );
+ sLocation = SvtPathOptions().SubstituteVariable( sLocation );
+
+ return sLocation;
+ }
+
+ void SAL_CALL DatabaseRegistrations::registerDatabaseLocation( const OUString& Name, const OUString& Location )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ // check
+ impl_checkValidLocation_throw( Location );
+ ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_not_exist(Name);
+
+ // register
+ aDataSourceRegistration.setNodeValue( getLocationNodeName(), Any( Location ) );
+ m_aConfigurationRoot.commit();
+
+ // notify
+ DatabaseRegistrationEvent aEvent( *this, Name, OUString(), Location );
+ aGuard.clear();
+ m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::registeredDatabaseLocation, aEvent );
+ }
+
+ void SAL_CALL DatabaseRegistrations::revokeDatabaseLocation( const OUString& Name )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ // check
+ ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw_must_exist(Name);
+
+ // obtain properties for notification
+ OUString sLocation;
+ OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation );
+
+ // revoke
+ if ( aNodeForName.isReadonly()
+ || !m_aConfigurationRoot.removeNode( aNodeForName.getLocalName() )
+ )
+ throw IllegalAccessException( OUString(), *this );
+
+ m_aConfigurationRoot.commit();
+
+ // notify
+ DatabaseRegistrationEvent aEvent( *this, Name, sLocation, OUString() );
+ aGuard.clear();
+ m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::revokedDatabaseLocation, aEvent );
+ }
+
+ void SAL_CALL DatabaseRegistrations::changeDatabaseLocation( const OUString& Name, const OUString& NewLocation )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ // check
+ impl_checkValidLocation_throw( NewLocation );
+ ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_exist(Name);
+
+ if ( aDataSourceRegistration.isReadonly() )
+ throw IllegalAccessException( OUString(), *this );
+
+ // obtain properties for notification
+ OUString sOldLocation;
+ OSL_VERIFY( aDataSourceRegistration.getNodeValue( getLocationNodeName() ) >>= sOldLocation );
+
+ // change
+ aDataSourceRegistration.setNodeValue( getLocationNodeName(), Any( NewLocation ) );
+ m_aConfigurationRoot.commit();
+
+ // notify
+ DatabaseRegistrationEvent aEvent( *this, Name, sOldLocation, NewLocation );
+ aGuard.clear();
+ m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::changedDatabaseLocation, aEvent );
+ }
+
+ sal_Bool SAL_CALL DatabaseRegistrations::isDatabaseRegistrationReadOnly( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_exist(Name);
+ return aDataSourceRegistration.isReadonly();
+ }
+
+ void SAL_CALL DatabaseRegistrations::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+ {
+ if ( Listener.is() )
+ m_aRegistrationListeners.addInterface( Listener );
+ }
+
+ void SAL_CALL DatabaseRegistrations::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+ {
+ if ( Listener.is() )
+ m_aRegistrationListeners.removeInterface( Listener );
+ }
+
+ // DatabaseRegistrations - factory
+ Reference< XAggregation > createDataSourceRegistrations( const Reference<XComponentContext> & _rxContext )
+ {
+ return new DatabaseRegistrations( _rxContext );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.hxx b/dbaccess/source/core/dataaccess/databaseregistrations.hxx
new file mode 100644
index 000000000..709bc9f98
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databaseregistrations.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XAggregation.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaccess
+{
+css::uno::Reference<css::uno::XAggregation>
+createDataSourceRegistrations(const css::uno::Reference<css::uno::XComponentContext>& _rxContext);
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/datasource.cxx b/dbaccess/source/core/dataaccess/datasource.cxx
new file mode 100644
index 000000000..d88b661c9
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/datasource.cxx
@@ -0,0 +1,1437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "datasource.hxx"
+#include "commandcontainer.hxx"
+#include <stringconstants.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include "connection.hxx"
+#include "SharedConnection.hxx"
+#include "databasedocument.hxx"
+#include <OAuthenticationContinuation.hxx>
+
+#include <hsqlimport.hxx>
+#include <migrwarndlg.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/ConnectionPool.hpp>
+#include <com/sun/star/sdbc/XDriverAccess.hpp>
+#include <com/sun/star/sdbc/XDriverManager.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/ucb/AuthenticationRequest.hpp>
+#include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <osl/process.h>
+#include <sal/log.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <rtl/digest.h>
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+
+#include <config_firebird.h>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::reflection;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::dbtools;
+using namespace ::comphelper;
+
+namespace dbaccess
+{
+
+namespace {
+
+/** helper class which implements a XFlushListener, and forwards all
+ notification events to another XFlushListener
+
+ The speciality is that the foreign XFlushListener instance, to which
+ the notifications are forwarded, is held weak.
+
+ Thus, the class can be used with XFlushable instance which hold
+ their listeners with a hard reference, if you simply do not *want*
+ to be held hard-ref-wise.
+*/
+class FlushNotificationAdapter : public ::cppu::WeakImplHelper< XFlushListener >
+{
+private:
+ WeakReference< XFlushable > m_aBroadcaster;
+ WeakReference< XFlushListener > m_aListener;
+
+public:
+ static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
+ {
+ new FlushNotificationAdapter( _rxBroadcaster, _rxListener );
+ }
+
+protected:
+ FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
+ virtual ~FlushNotificationAdapter() override;
+
+ void impl_dispose();
+
+protected:
+ // XFlushListener
+ virtual void SAL_CALL flushed( const css::lang::EventObject& rEvent ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+};
+
+}
+
+FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
+ :m_aBroadcaster( _rxBroadcaster )
+ ,m_aListener( _rxListener )
+{
+ OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ if ( _rxBroadcaster.is() )
+ _rxBroadcaster->addFlushListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
+}
+
+FlushNotificationAdapter::~FlushNotificationAdapter()
+{
+}
+
+void FlushNotificationAdapter::impl_dispose()
+{
+ Reference< XFlushListener > xKeepAlive( this );
+
+ Reference< XFlushable > xFlushable( m_aBroadcaster );
+ if ( xFlushable.is() )
+ xFlushable->removeFlushListener( this );
+
+ m_aListener.clear();
+ m_aBroadcaster.clear();
+}
+
+void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent )
+{
+ Reference< XFlushListener > xListener( m_aListener );
+ if ( xListener.is() )
+ xListener->flushed( rEvent );
+ else
+ impl_dispose();
+}
+
+void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source )
+{
+ Reference< XFlushListener > xListener( m_aListener );
+ if ( xListener.is() )
+ xListener->disposing( Source );
+
+ impl_dispose();
+}
+
+OAuthenticationContinuation::OAuthenticationContinuation()
+ :m_bRememberPassword(true), // TODO: a meaningful default
+ m_bCanSetUserName(true)
+{
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm( )
+{
+ return false;
+}
+
+void SAL_CALL OAuthenticationContinuation::setRealm( const OUString& /*Realm*/ )
+{
+ SAL_WARN("dbaccess","OAuthenticationContinuation::setRealm: not supported!");
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName( )
+{
+ // we always allow this, even if the database document is read-only. In this case,
+ // it's simply that the user cannot store the new user name.
+ return m_bCanSetUserName;
+}
+
+void SAL_CALL OAuthenticationContinuation::setUserName( const OUString& _rUser )
+{
+ m_sUser = _rUser;
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword( )
+{
+ return true;
+}
+
+void SAL_CALL OAuthenticationContinuation::setPassword( const OUString& _rPassword )
+{
+ m_sPassword = _rPassword;
+}
+
+Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault )
+{
+ _reDefault = RememberAuthentication_SESSION;
+ return { _reDefault };
+}
+
+void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember )
+{
+ m_bRememberPassword = (RememberAuthentication_NO != _eRemember);
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( )
+{
+ return false;
+}
+
+void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& )
+{
+ SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
+}
+
+Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault )
+{
+ _reDefault = RememberAuthentication_NO;
+ return { RememberAuthentication_NO };
+}
+
+void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ )
+{
+ SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
+}
+
+namespace {
+
+/** The class OSharedConnectionManager implements a structure to share connections.
+ It owns the master connections which will be disposed when the last connection proxy is gone.
+*/
+// need to hold the digest
+struct TDigestHolder
+{
+ sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
+ TDigestHolder()
+ {
+ m_pBuffer[0] = 0;
+ }
+
+};
+
+}
+
+class OSharedConnectionManager : public ::cppu::WeakImplHelper< XEventListener >
+{
+
+ // contains the currently used master connections
+ struct TConnectionHolder
+ {
+ Reference< XConnection > xMasterConnection;
+ oslInterlockedCount nALiveCount;
+ };
+
+ // the less-compare functor, used for the stl::map
+ struct TDigestLess
+ {
+ bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
+ {
+ sal_uInt32 i;
+ for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
+ ;
+ return i < RTL_DIGEST_LENGTH_SHA1;
+ }
+ };
+
+ typedef std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections
+ typedef std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections
+
+ ::osl::Mutex m_aMutex;
+ TConnectionMap m_aConnections; // remember the master connection in conjunction with the digest
+ TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map
+ Reference< XProxyFactory > m_xProxyFactory;
+
+protected:
+ virtual ~OSharedConnectionManager() override;
+
+public:
+ explicit OSharedConnectionManager(const Reference< XComponentContext >& _rxContext);
+
+ void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ Reference<XConnection> getConnection( const OUString& url,
+ const OUString& user,
+ const OUString& password,
+ const Sequence< PropertyValue >& _aInfo,
+ ODatabaseSource* _pDataSource);
+ void addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter);
+};
+
+OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
+{
+ m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
+}
+
+OSharedConnectionManager::~OSharedConnectionManager()
+{
+}
+
+void SAL_CALL OSharedConnectionManager::disposing( const css::lang::EventObject& Source )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
+ TSharedConnectionMap::const_iterator aFind = m_aSharedConnection.find(xConnection);
+ if ( m_aSharedConnection.end() != aFind )
+ {
+ osl_atomic_decrement(&aFind->second->second.nALiveCount);
+ if ( !aFind->second->second.nALiveCount )
+ {
+ ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
+ m_aConnections.erase(aFind->second);
+ }
+ m_aSharedConnection.erase(aFind);
+ }
+}
+
+Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
+ const OUString& user,
+ const OUString& password,
+ const Sequence< PropertyValue >& _aInfo,
+ ODatabaseSource* _pDataSource)
+{
+ MutexGuard aGuard(m_aMutex);
+ TConnectionMap::key_type nId;
+ Sequence< PropertyValue > aInfoCopy(_aInfo);
+ sal_Int32 nPos = aInfoCopy.getLength();
+ aInfoCopy.realloc( nPos + 2 );
+ auto pInfoCopy = aInfoCopy.getArray();
+ pInfoCopy[nPos].Name = "TableFilter";
+ pInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
+ pInfoCopy[nPos].Name = "TableTypeFilter";
+ pInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
+
+ OUString sUser = user;
+ OUString sPassword = password;
+ if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
+ { // ease the usage of this method. data source which are intended to have a user automatically
+ // fill in the user/password combination if the caller of this method does not specify otherwise
+ sUser = _pDataSource->m_pImpl->m_sUser;
+ if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
+ sPassword = _pDataSource->m_pImpl->m_aPassword;
+ }
+
+ ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
+ TConnectionMap::iterator aIter = m_aConnections.find(nId);
+
+ if ( m_aConnections.end() == aIter )
+ {
+ TConnectionHolder aHolder;
+ aHolder.nALiveCount = 0; // will be incremented by addListener
+ aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
+ aIter = m_aConnections.emplace(nId,aHolder).first;
+ }
+
+ Reference<XConnection> xRet;
+ if ( aIter->second.xMasterConnection.is() )
+ {
+ Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection);
+ xRet = new OSharedConnection(xConProxy);
+ m_aSharedConnection.emplace(xRet,aIter);
+ addEventListener(xRet,aIter);
+ }
+
+ return xRet;
+}
+
+void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter)
+{
+ Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
+ xComp->addEventListener(this);
+ OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
+ osl_atomic_increment(&_rIter->second.nALiveCount);
+}
+
+namespace
+{
+ Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
+ const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
+ {
+ if ( _xDriver.is() )
+ {
+ Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
+
+ const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
+ const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
+
+ std::vector< PropertyValue > aRet;
+
+ for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
+ {
+ bool bAllowSetting = false;
+ const AsciiPropertyValue* pSetting = _pKnownSettings;
+ for ( ; pSetting->AsciiName; ++pSetting )
+ {
+ if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
+ { // the particular data source setting is known
+
+ const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
+ const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
+ for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
+ {
+ if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
+ { // the driver also allows this setting
+ bAllowSetting = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if ( bAllowSetting || !pSetting->AsciiName )
+ { // if the driver allows this particular setting, or if the setting is completely unknown,
+ // we pass it to the driver
+ aRet.push_back( *pDataSourceSetting );
+ }
+ }
+ if ( !aRet.empty() )
+ return comphelper::containerToSequence(aRet);
+ }
+ return Sequence< PropertyValue >();
+ }
+
+ typedef std::map< OUString, sal_Int32 > PropertyAttributeCache;
+
+ struct IsDefaultAndNotRemoveable
+ {
+ private:
+ const PropertyAttributeCache& m_rAttribs;
+
+ public:
+ explicit IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
+
+ bool operator()( const PropertyValue& _rProp )
+ {
+ if ( _rProp.State != PropertyState_DEFAULT_VALUE )
+ return false;
+
+ bool bRemoveable = true;
+
+ PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
+ OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
+ if ( pos != m_rAttribs.end() )
+ bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
+
+ return !bRemoveable;
+ }
+ };
+}
+
+
+ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
+ :ModelDependentComponent( _pImpl )
+ ,ODatabaseSource_Base( getMutex() )
+ ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
+ , m_Bookmarks(*this, getMutex())
+ ,m_aFlushListeners( getMutex() )
+{
+ // some kind of default
+ SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
+}
+
+ODatabaseSource::~ODatabaseSource()
+{
+ SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
+ if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+}
+
+void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
+{
+ ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument );
+
+ SolarMutexGuard g;
+ if ( rModelImpl.m_pImpl.is() )
+ rModelImpl.m_pImpl->m_sName = _rNewName;
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > ODatabaseSource::getTypes()
+{
+ OTypeCollection aPropertyHelperTypes( cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get());
+
+ return ::comphelper::concatSequences(
+ ODatabaseSource_Base::getTypes(),
+ aPropertyHelperTypes.getTypes()
+ );
+}
+
+Sequence< sal_Int8 > ODatabaseSource::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any ODatabaseSource::queryInterface( const Type & rType )
+{
+ Any aIface = ODatabaseSource_Base::queryInterface( rType );
+ if ( !aIface.hasValue() )
+ aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
+ return aIface;
+}
+
+void ODatabaseSource::acquire() noexcept
+{
+ ODatabaseSource_Base::acquire();
+}
+
+void ODatabaseSource::release() noexcept
+{
+ ODatabaseSource_Base::release();
+}
+
+void SAL_CALL ODatabaseSource::disposing( const css::lang::EventObject& Source )
+{
+ if ( m_pImpl.is() )
+ m_pImpl->disposing(Source);
+}
+
+// XServiceInfo
+OUString ODatabaseSource::getImplementationName( )
+{
+ return "com.sun.star.comp.dba.ODatabaseSource";
+}
+
+Sequence< OUString > ODatabaseSource::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_DATASOURCE, "com.sun.star.sdb.DocumentDataSource" };
+}
+
+sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+// OComponentHelper
+void ODatabaseSource::disposing()
+{
+ SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
+ ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
+ OPropertySetHelper::disposing();
+
+ EventObject aDisposeEvent(static_cast<XWeak*>(this));
+ m_aFlushListeners.disposeAndClear( aDisposeEvent );
+
+ ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
+ ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
+ m_pImpl.clear();
+}
+
+weld::Window* ODatabaseModelImpl::GetFrameWeld()
+{
+ if (m_xDialogParent.is())
+ return Application::GetFrameWeld(m_xDialogParent);
+
+ Reference<XModel> xModel = getModel_noCreate();
+ if (!xModel.is())
+ return nullptr;
+ Reference<XController> xController(xModel->getCurrentController());
+ if (!xController.is())
+ return nullptr;
+ Reference<XFrame> xFrame(xController->getFrame());
+ if (!xFrame.is())
+ return nullptr;
+ Reference<css::awt::XWindow> xWindow(xFrame->getContainerWindow());
+ return Application::GetFrameWeld(xWindow);
+}
+
+Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
+{
+ Reference< XConnection > xReturn;
+
+ Reference< XDriverManager > xManager;
+
+#if ENABLE_FIREBIRD_SDBC
+ bool bIgnoreMigration = false;
+ bool bNeedMigration = false;
+ Reference< XModel > xModel = m_pImpl->getModel_noCreate();
+ if ( xModel)
+ {
+ //See ODbTypeWizDialogSetup::SaveDatabaseDocument
+ ::comphelper::NamedValueCollection::get(xModel->getArgs(), u"IgnoreFirebirdMigration") >>= bIgnoreMigration;
+ }
+ else
+ {
+ //ignore when we don't have a model. E.g. Mailmerge, data sources, fields...
+ bIgnoreMigration = true;
+ }
+
+ if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
+ bIgnoreMigration = true;
+
+ if(!bIgnoreMigration && m_pImpl->m_sConnectURL == "sdbc:embedded:hsqldb")
+ {
+ Reference<XStorage> const xRootStorage = m_pImpl->getOrCreateRootStorage();
+ OUString sMigrEnvVal;
+ osl_getEnvironment(OUString("DBACCESS_HSQL_MIGRATION").pData,
+ &sMigrEnvVal.pData);
+ if(!sMigrEnvVal.isEmpty())
+ bNeedMigration = true;
+ else
+ {
+ Reference<XPropertySet> const xPropSet(xRootStorage, UNO_QUERY_THROW);
+ sal_Int32 nOpenMode(0);
+ if ((xPropSet->getPropertyValue("OpenMode") >>= nOpenMode)
+ && (nOpenMode & css::embed::ElementModes::WRITE)
+ && (!Application::IsHeadlessModeEnabled()))
+ {
+ MigrationWarnDialog aWarnDlg(m_pImpl->GetFrameWeld());
+ bNeedMigration = aWarnDlg.run() == RET_OK;
+ }
+ }
+ if (bNeedMigration)
+ {
+ // back up content xml file if migration was successful
+ static constexpr OUStringLiteral BACKUP_XML_NAME = u"content_before_migration.xml";
+ try
+ {
+ if(xRootStorage->isStreamElement(BACKUP_XML_NAME))
+ xRootStorage->removeElement(BACKUP_XML_NAME);
+ }
+ catch (NoSuchElementException&)
+ {
+ SAL_INFO("dbaccess", "No file content_before_migration.xml found" );
+ }
+ xRootStorage->copyElementTo("content.xml", xRootStorage,
+ BACKUP_XML_NAME);
+
+ m_pImpl->m_sConnectURL = "sdbc:embedded:firebird";
+ }
+ }
+#endif
+
+ try {
+ xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
+ } catch( const Exception& ) { }
+ if ( !xManager.is() )
+ // no connection pool installed, fall back to driver manager
+ xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
+
+ OUString sUser(_rUid);
+ OUString sPwd(_rPwd);
+ if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
+ { // ease the usage of this method. data source which are intended to have a user automatically
+ // fill in the user/password combination if the caller of this method does not specify otherwise
+ sUser = m_pImpl->m_sUser;
+ if (!m_pImpl->m_aPassword.isEmpty())
+ sPwd = m_pImpl->m_aPassword;
+ }
+
+ TranslateId pExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
+ if (xManager.is())
+ {
+ sal_Int32 nAdditionalArgs(0);
+ if (!sUser.isEmpty()) ++nAdditionalArgs;
+ if (!sPwd.isEmpty()) ++nAdditionalArgs;
+
+ Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
+ auto aUserPwdRange = asNonConstRange(aUserPwd);
+ sal_Int32 nArgPos = 0;
+ if (!sUser.isEmpty())
+ {
+ aUserPwdRange[ nArgPos ].Name = "user";
+ aUserPwdRange[ nArgPos ].Value <<= sUser;
+ ++nArgPos;
+ }
+ if (!sPwd.isEmpty())
+ {
+ aUserPwdRange[ nArgPos ].Name = "password";
+ aUserPwdRange[ nArgPos ].Value <<= sPwd;
+ }
+ Reference< XDriver > xDriver;
+ try
+ {
+
+ // choose driver
+ Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
+ if ( xAccessDrivers.is() )
+ xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error" );
+ }
+ if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
+ {
+ // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
+ // This is because registration nowadays happens at compile time (by adding respective configuration data),
+ // but acceptance is decided at runtime.
+ pExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
+ }
+ else
+ {
+ Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
+ xDriver,
+ m_pImpl->m_sConnectURL,
+ m_pImpl->m_xSettings->getPropertyValues(),
+ dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings()
+ );
+
+ if ( m_pImpl->isEmbeddedDatabase() )
+ {
+ sal_Int32 nCount = aDriverInfo.getLength();
+ aDriverInfo.realloc(nCount + 3 );
+ auto pDriverInfo = aDriverInfo.getArray();
+
+ pDriverInfo[nCount].Name = "URL";
+ pDriverInfo[nCount++].Value <<= m_pImpl->getURL();
+
+ pDriverInfo[nCount].Name = "Storage";
+ Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
+ pDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
+
+ pDriverInfo[nCount].Name = "Document";
+ pDriverInfo[nCount++].Value <<= getDatabaseDocument();
+ }
+ if (nAdditionalArgs)
+ xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
+ else
+ xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
+
+ if ( m_pImpl->isEmbeddedDatabase() )
+ {
+ // see ODatabaseSource::flushed for comment on why we register as FlushListener
+ // at the connection
+ Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
+ if ( xFlushable.is() )
+ FlushNotificationAdapter::installAdapter( xFlushable, this );
+ }
+ }
+ }
+ else
+ pExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
+
+ if ( !xReturn.is() )
+ {
+ OUString sMessage = DBA_RES(pExceptionMessageId)
+ .replaceAll("$name$", m_pImpl->m_sConnectURL);
+
+ SQLContext aContext;
+ aContext.Message = DBA_RES(RID_STR_CONNECTION_REQUEST).
+ replaceFirst("$name$", m_pImpl->m_sConnectURL);
+
+ throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), Any( aContext ) );
+ }
+
+#if ENABLE_FIREBIRD_SDBC
+ if( bNeedMigration )
+ {
+ Reference< css::document::XDocumentSubStorageSupplier> xDocSup(
+ m_pImpl->getDocumentSubStorageSupplier() );
+ dbahsql::HsqlImporter importer(xReturn,
+ xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE) );
+ importer.importHsqlDatabase(m_pImpl->GetFrameWeld());
+ }
+#endif
+
+ return xReturn;
+}
+
+// OPropertySetHelper
+Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_INFO, PROPERTY_ID_INFO, cppu::UnoType<Sequence< PropertyValue >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISPASSWORDREQUIRED, PROPERTY_ID_ISPASSWORDREQUIRED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, cppu::UnoType<Sequence< PropertyValue >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_NUMBERFORMATSSUPPLIER, PROPERTY_ID_NUMBERFORMATSSUPPLIER, cppu::UnoType<XNumberFormatsSupplier>::get(),
+ css::beans::PropertyAttribute::READONLY | css::beans::PropertyAttribute::TRANSIENT },
+ { PROPERTY_PASSWORD, PROPERTY_ID_PASSWORD, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::TRANSIENT },
+ { PROPERTY_SETTINGS, PROPERTY_ID_SETTINGS, cppu::UnoType<XPropertySet>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SUPPRESSVERSIONCL, PROPERTY_ID_SUPPRESSVERSIONCL, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_TABLEFILTER, PROPERTY_ID_TABLEFILTER, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_TABLETYPEFILTER, PROPERTY_ID_TABLETYPEFILTER, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_URL, PROPERTY_ID_URL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_USER, PROPERTY_ID_USER, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bModified(false);
+ if ( m_pImpl.is() )
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_TABLEFILTER:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
+ break;
+ case PROPERTY_ID_TABLETYPEFILTER:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
+ break;
+ case PROPERTY_ID_USER:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
+ break;
+ case PROPERTY_ID_PASSWORD:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
+ break;
+ case PROPERTY_ID_ISPASSWORDREQUIRED:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
+ break;
+ case PROPERTY_ID_SUPPRESSVERSIONCL:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
+ break;
+ case PROPERTY_ID_LAYOUTINFORMATION:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
+ break;
+ case PROPERTY_ID_URL:
+ {
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
+ } break;
+ case PROPERTY_ID_INFO:
+ {
+ Sequence<PropertyValue> aValues;
+ if (!(rValue >>= aValues))
+ throw IllegalArgumentException();
+
+ for ( auto const & checkName : std::as_const(aValues) )
+ {
+ if ( checkName.Name.isEmpty() )
+ throw IllegalArgumentException();
+ }
+
+ Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
+ bModified = aSettings.getLength() != aValues.getLength();
+ if ( !bModified )
+ {
+ const PropertyValue* pInfoIter = aSettings.getConstArray();
+ const PropertyValue* checkValue = aValues.getConstArray();
+ for ( ;!bModified && checkValue != std::cend(aValues) ; ++checkValue,++pInfoIter)
+ {
+ bModified = checkValue->Name != pInfoIter->Name;
+ if ( !bModified )
+ {
+ bModified = checkValue->Value != pInfoIter->Value;
+ }
+ }
+ }
+
+ rConvertedValue = rValue;
+ rOldValue <<= aSettings;
+ }
+ break;
+ default:
+ SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
+ }
+ }
+ return bModified;
+}
+
+namespace
+{
+ struct SelectPropertyName
+ {
+ public:
+ const OUString& operator()( const PropertyValue& _lhs )
+ {
+ return _lhs.Name;
+ }
+ };
+
+ /** sets a new set of property values for a given property bag instance
+
+ The method takes a property bag, and a sequence of property values to set for this bag.
+ Upon return, every property which is not part of the given sequence is
+ <ul><li>removed from the bag, if it's a removable property</li>
+ <li><em>or</em>reset to its default value, if it's not a removable property</li>
+ </ul>.
+
+ @param _rxPropertyBag
+ the property bag to operate on
+ @param _rAllNewPropertyValues
+ the new property values to set for the bag
+ */
+ void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
+ {
+ // sequences are ugly to operate on
+ std::set<OUString> aToBeSetPropertyNames;
+ std::transform(
+ _rAllNewPropertyValues.begin(),
+ _rAllNewPropertyValues.end(),
+ std::inserter( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
+ SelectPropertyName()
+ );
+
+ try
+ {
+ // obtain all properties currently known at the bag
+ Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_SET_THROW );
+ const Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
+
+ Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
+
+ // loop through them, and reset resp. default properties which are not to be set
+ for ( auto const & existentProperty : aAllExistentProperties )
+ {
+ if ( aToBeSetPropertyNames.find( existentProperty.Name ) != aToBeSetPropertyNames.end() )
+ continue;
+
+ // this property is not to be set, but currently exists in the bag.
+ // -> Remove it, or reset it to the default.
+ if ( ( existentProperty.Attributes & PropertyAttribute::REMOVABLE ) != 0 )
+ _rxPropertyBag->removeProperty( existentProperty.Name );
+ else
+ xPropertyState->setPropertyToDefault( existentProperty.Name );
+ }
+
+ // finally, set the new property values
+ _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ if ( !m_pImpl.is() )
+ return;
+
+ switch(nHandle)
+ {
+ case PROPERTY_ID_TABLEFILTER:
+ rValue >>= m_pImpl->m_aTableFilter;
+ break;
+ case PROPERTY_ID_TABLETYPEFILTER:
+ rValue >>= m_pImpl->m_aTableTypeFilter;
+ break;
+ case PROPERTY_ID_USER:
+ rValue >>= m_pImpl->m_sUser;
+ // if the user name has changed, reset the password
+ m_pImpl->m_aPassword.clear();
+ break;
+ case PROPERTY_ID_PASSWORD:
+ rValue >>= m_pImpl->m_aPassword;
+ break;
+ case PROPERTY_ID_ISPASSWORDREQUIRED:
+ m_pImpl->m_bPasswordRequired = any2bool(rValue);
+ break;
+ case PROPERTY_ID_SUPPRESSVERSIONCL:
+ m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
+ break;
+ case PROPERTY_ID_URL:
+ rValue >>= m_pImpl->m_sConnectURL;
+ break;
+ case PROPERTY_ID_INFO:
+ {
+ Sequence< PropertyValue > aInfo;
+ OSL_VERIFY( rValue >>= aInfo );
+ lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
+ }
+ break;
+ case PROPERTY_ID_LAYOUTINFORMATION:
+ rValue >>= m_pImpl->m_aLayoutInformation;
+ break;
+ }
+ m_pImpl->setModified(true);
+}
+
+void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ if ( !m_pImpl.is() )
+ return;
+
+ switch (nHandle)
+ {
+ case PROPERTY_ID_TABLEFILTER:
+ rValue <<= m_pImpl->m_aTableFilter;
+ break;
+ case PROPERTY_ID_TABLETYPEFILTER:
+ rValue <<= m_pImpl->m_aTableTypeFilter;
+ break;
+ case PROPERTY_ID_USER:
+ rValue <<= m_pImpl->m_sUser;
+ break;
+ case PROPERTY_ID_PASSWORD:
+ rValue <<= m_pImpl->m_aPassword;
+ break;
+ case PROPERTY_ID_ISPASSWORDREQUIRED:
+ rValue <<= m_pImpl->m_bPasswordRequired;
+ break;
+ case PROPERTY_ID_SUPPRESSVERSIONCL:
+ rValue <<= m_pImpl->m_bSuppressVersionColumns;
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ rValue <<= m_pImpl->m_bReadOnly;
+ break;
+ case PROPERTY_ID_INFO:
+ {
+ try
+ {
+ // collect the property attributes of all current settings
+ Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_SET_THROW );
+ const Sequence< Property > aSettings( xPST->getProperties() );
+ std::map< OUString, sal_Int32 > aPropertyAttributes;
+ for ( auto const & setting : aSettings )
+ {
+ aPropertyAttributes[ setting.Name ] = setting.Attributes;
+ }
+
+ // get all current settings with their values
+ Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
+
+ // transform them so that only property values which fulfill certain
+ // criteria survive
+ Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
+ auto [begin, end] = asNonConstRange(aValues);
+ auto pCopyStart = aNonDefaultOrUserDefined.getArray();
+ const PropertyValue* pCopyEnd = std::remove_copy_if(
+ begin,
+ end,
+ pCopyStart,
+ IsDefaultAndNotRemoveable( aPropertyAttributes )
+ );
+ aNonDefaultOrUserDefined.realloc( pCopyEnd - pCopyStart );
+ rValue <<= aNonDefaultOrUserDefined;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ break;
+ case PROPERTY_ID_SETTINGS:
+ rValue <<= m_pImpl->m_xSettings;
+ break;
+ case PROPERTY_ID_URL:
+ rValue <<= m_pImpl->m_sConnectURL;
+ break;
+ case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
+ rValue <<= m_pImpl->getNumberFormatsSupplier();
+ break;
+ case PROPERTY_ID_NAME:
+ rValue <<= m_pImpl->m_sName;
+ break;
+ case PROPERTY_ID_LAYOUTINFORMATION:
+ rValue <<= m_pImpl->m_aLayoutInformation;
+ break;
+ default:
+ SAL_WARN("dbaccess","unknown Property");
+ }
+}
+
+// XDataSource
+void ODatabaseSource::setLoginTimeout(sal_Int32 seconds)
+{
+ ModelMethodGuard aGuard( *this );
+ m_pImpl->m_nLoginTimeout = seconds;
+}
+
+sal_Int32 ODatabaseSource::getLoginTimeout()
+{
+ ModelMethodGuard aGuard( *this );
+ return m_pImpl->m_nLoginTimeout;
+}
+
+// XCompletedConnection
+Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
+{
+ return connectWithCompletion(_rxHandler,false);
+}
+
+Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password)
+{
+ return getConnection(user,password,false);
+}
+
+Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password )
+{
+ return getConnection(user,password,true);
+}
+
+Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
+{
+ return connectWithCompletion(_rxHandler,true);
+}
+
+Reference< XConnection > ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated )
+{
+ ModelMethodGuard aGuard( *this );
+
+ if (!_rxHandler.is())
+ {
+ SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
+ return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
+ }
+
+ OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
+ bool bNewPasswordGiven = false;
+
+ if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
+ { // we need a password, but don't have one yet.
+ // -> ask the user
+
+ // build an interaction request
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OAuthenticationContinuation> pAuthenticate = new OAuthenticationContinuation;
+
+ // the name which should be referred in the login dialog
+ OUString sServerName( m_pImpl->m_sName );
+ INetURLObject aURLCheck( sServerName );
+ if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
+ sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
+
+ // the request
+ AuthenticationRequest aRequest;
+ aRequest.ServerName = sServerName;
+ aRequest.HasRealm = aRequest.HasAccount = false;
+ aRequest.HasUserName = aRequest.HasPassword = true;
+ aRequest.UserName = m_pImpl->m_sUser;
+ aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ pRequest->addContinuation(pAbort);
+ pRequest->addContinuation(pAuthenticate);
+
+ // handle the request
+ try
+ {
+ _rxHandler->handle(pRequest);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if (!pAuthenticate->wasSelected())
+ return Reference< XConnection >();
+
+ // get the result
+ sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
+ sPassword = pAuthenticate->getPassword();
+
+ if (pAuthenticate->getRememberPassword())
+ {
+ m_pImpl->m_aPassword = pAuthenticate->getPassword();
+ bNewPasswordGiven = true;
+ }
+ m_pImpl->m_sFailedPassword.clear();
+ }
+
+ try
+ {
+ return getConnection(sUser, sPassword,_bIsolated);
+ }
+ catch(Exception&)
+ {
+ if (bNewPasswordGiven)
+ {
+ m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
+ // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
+ // the user gave us a password and the order to remember it, never allow a password input again (at least
+ // not without restarting the session)
+ m_pImpl->m_aPassword.clear();
+ }
+ throw;
+ }
+}
+
+Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
+{
+ Reference< XConnection > xConn;
+ Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
+ OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
+ // buildLowLevelConnection is expected to always succeed
+ if ( xSdbcConn.is() )
+ {
+ // build a connection server and return it (no stubs)
+ xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
+ }
+ return xConn;
+}
+
+Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated)
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XConnection > xConn;
+ if ( _bIsolated )
+ {
+ xConn = buildIsolatedConnection(user,password);
+ }
+ else
+ { // create a new proxy for the connection
+ if ( !m_pImpl->m_xSharedConnectionManager.is() )
+ {
+ // TODO ideally we could just have one field, but to make that work
+ // we'd need to move OSharedConnectionManager into its own file and header
+ rtl::Reference<OSharedConnectionManager> manager =
+ new OSharedConnectionManager( m_pImpl->m_aContext );
+ m_pImpl->m_pSharedConnectionManager = manager.get();
+ m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
+ }
+ xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
+ m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
+ }
+
+ if ( xConn.is() )
+ {
+ Reference< XComponent> xComp(xConn,UNO_QUERY);
+ if ( xComp.is() )
+ xComp->addEventListener( static_cast< XContainerListener* >( this ) );
+ m_pImpl->m_aConnections.emplace_back(xConn);
+ }
+
+ return xConn;
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( )
+{
+ ModelMethodGuard aGuard( *this );
+ // tdf#114596 this may look nutty but see OBookmarkContainer::acquire()
+ return static_cast<XNameContainer*>(&m_Bookmarks);
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( )
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
+ if ( !xContainer.is() )
+ {
+ Any aValue;
+ css::uno::Reference< css::uno::XInterface > xMy(*this);
+ if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
+ {
+ OUString sSupportService;
+ aValue >>= sSupportService;
+ if ( !sSupportService.isEmpty() )
+ {
+ Sequence<Any> aArgs{ Any(NamedValue("DataSource",Any(xMy))) };
+ xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY);
+ }
+ }
+ if ( !xContainer.is() )
+ {
+ TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
+ xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
+ }
+ m_pImpl->m_xCommandDefinitions = xContainer;
+ }
+ return xContainer;
+}
+
+// XTablesSupplier
+Reference< XNameAccess > ODatabaseSource::getTables()
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
+ if ( !xContainer.is() )
+ {
+ TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
+ xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true );
+ m_pImpl->m_xTableDefinitions = xContainer;
+ }
+ return xContainer;
+}
+
+void SAL_CALL ODatabaseSource::flush( )
+{
+ try
+ {
+ // SYNCHRONIZED ->
+ {
+ ModelMethodGuard aGuard( *this );
+
+ typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
+ SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
+
+ if ( !xModel.is() )
+ xModel.reset( m_pImpl->createNewModel_deliverOwnership(), SharedModel::TakeOwnership );
+
+ Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
+ xStorable->store();
+ }
+ // <- SYNCHRONIZED
+
+ css::lang::EventObject aFlushedEvent(*this);
+ m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ )
+{
+ ModelMethodGuard aGuard( *this );
+
+ // Okay, this is some hack.
+ //
+ // In general, we have the problem that embedded databases write into their underlying storage, which
+ // logically is one of our sub storage, and practically is a temporary file maintained by the
+ // package implementation. As long as we did not commit this storage and our main storage,
+ // the changes made by the embedded database engine are not really reflected in the database document
+ // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
+ // data, and then crashing: For a database application, you would expect that the data still is present
+ // when you connect to the database next time.
+ //
+ // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
+ // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
+ // we cannot completely fix this. However, we can relax the problem by committing more often - often
+ // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance
+ // decrease.
+ //
+ // For this, we introduced a few places which XFlushable::flush their connections, and register as
+ // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
+ // Then, when the connection is flushed, we commit both the database storage and our main storage.
+ //
+ // #i55274#
+
+ OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
+ bool bWasModified = m_pImpl->m_bModified;
+ m_pImpl->commitEmbeddedStorage();
+ m_pImpl->setModified( bWasModified );
+}
+
+void SAL_CALL ODatabaseSource::addFlushListener( const Reference< css::util::XFlushListener >& _xListener )
+{
+ m_aFlushListeners.addInterface(_xListener);
+}
+
+void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< css::util::XFlushListener >& _xListener )
+{
+ m_aFlushListeners.removeInterface(_xListener);
+}
+
+void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ )
+{
+ ModelMethodGuard aGuard( *this );
+ if ( m_pImpl.is() )
+ m_pImpl->setModified(true);
+}
+
+void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ )
+{
+ ModelMethodGuard aGuard( *this );
+ if ( m_pImpl.is() )
+ m_pImpl->setModified(true);
+}
+
+void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ )
+{
+ ModelMethodGuard aGuard( *this );
+ if ( m_pImpl.is() )
+ m_pImpl->setModified(true);
+}
+
+// XDocumentDataSource
+Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument()
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
+ if ( !xModel.is() )
+ xModel = m_pImpl->createNewModel_deliverOwnership();
+
+ return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
+}
+
+void SAL_CALL ODatabaseSource::initialize( css::uno::Sequence< css::uno::Any > const & rArguments)
+{
+ ::comphelper::NamedValueCollection aProperties( rArguments );
+ if (aProperties.has("ParentWindow"))
+ aProperties.get("ParentWindow") >>= m_pImpl->m_xDialogParent;
+}
+
+Reference< XInterface > ODatabaseSource::getThis() const
+{
+ return *const_cast< ODatabaseSource* >( this );
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ css::uno::Reference<XInterface> inst(
+ DatabaseContext::create(context)->createInstance());
+ inst->acquire();
+ return inst.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/datasource.hxx b/dbaccess/source/core/dataaccess/datasource.hxx
new file mode 100644
index 000000000..5b5985eac
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/datasource.hxx
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/sdb/XBookmarksSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <com/sun/star/sdbc/XIsolatedConnection.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <cppuhelper/propshlp.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <apitools.hxx>
+#include <bookmarkcontainer.hxx>
+#include <rtl/ref.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <ContentHelper.hxx>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <ModelImpl.hxx>
+
+namespace dbaccess
+{
+
+class OSharedConnectionManager;
+
+// ODatabaseSource
+typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo
+ , css::sdbc::XDataSource
+ , css::sdb::XBookmarksSupplier
+ , css::sdb::XQueryDefinitionsSupplier
+ , css::sdb::XCompletedConnection
+ , css::container::XContainerListener
+ , css::sdbc::XIsolatedConnection
+ , css::sdbcx::XTablesSupplier
+ , css::util::XFlushable
+ , css::util::XFlushListener
+ , css::sdb::XDocumentDataSource
+ , css::lang::XInitialization
+ > ODatabaseSource_Base;
+
+class ODatabaseSource :public ModelDependentComponent // must be first
+ ,public ODatabaseSource_Base
+ ,public ::cppu::OPropertySetHelper
+ ,public ::comphelper::OPropertyArrayUsageHelper < ODatabaseSource >
+{
+ friend class ODatabaseContext;
+ friend class OConnection;
+ friend class OSharedConnectionManager;
+
+private:
+ using ODatabaseSource_Base::rBHelper;
+ // note: this thing uses the ref-count of "this", see OBookmarkContainer::acquire!
+ OBookmarkContainer m_Bookmarks;
+ ::comphelper::OInterfaceContainerHelper3<css::util::XFlushListener> m_aFlushListeners;
+
+private:
+ virtual ~ODatabaseSource() override;
+
+public:
+ explicit ODatabaseSource( const ::rtl::Reference< ODatabaseModelImpl >& _pImpl );
+
+ struct DBContextAccess { friend class ODatabaseContext; private: DBContextAccess() { } };
+
+ /** sets a new name for the data source
+
+ The name of a data source (our m_sName member) is the registration name, *if* the
+ data source actually *is* registered at the database context.
+
+ Normally, this name is passed at time of creation of the ODatabaseModelImpl instance,
+ but if a newly created data source is registered, then it must be possible to propagate
+ the new registration name.
+ */
+ static void setName(
+ const css::uno::Reference< css::sdb::XDocumentDataSource >& _rxDocument,
+ const OUString& _rNewName,
+ DBContextAccess
+ );
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+ // css::sdbcx::XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+
+// css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+// comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+// cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+// css::sdb::XCompletedConnection
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connectWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler ) override;
+
+// css::sdbc::XDataSource
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& user, const OUString& password ) override;
+ virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override;
+ virtual sal_Int32 SAL_CALL getLoginTimeout( ) override;
+
+//::css::sdb::XBookmarksSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getBookmarks( ) override;
+
+//::css::sdb::XQueryDefinitionsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getQueryDefinitions( ) override;
+
+// css::sdbc::XIsolatedConnection
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getIsolatedConnection( const OUString& user, const OUString& password ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getIsolatedConnectionWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler ) override;
+
+// XFlushable
+ virtual void SAL_CALL flush( ) override;
+ virtual void SAL_CALL addFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+ virtual void SAL_CALL removeFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+
+ // XFlushListener
+ virtual void SAL_CALL flushed( const css::lang::EventObject& rEvent ) override;
+
+ // XDocumentDataSource
+ virtual css::uno::Reference< css::sdb::XOfficeDatabaseDocument > SAL_CALL getDatabaseDocument() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+protected:
+ // ModelDependentComponent overridables
+ virtual css::uno::Reference< css::uno::XInterface > getThis() const override;
+
+private:
+// helper
+ /** open a connection for the current settings. this is the simple connection we get from the driver
+ manager, so it can be used as a master for a "high level" sdb connection.
+ */
+ css::uno::Reference< css::sdbc::XConnection > buildLowLevelConnection(
+ const OUString& _rUid, const OUString& _rPwd
+ );
+
+ css::uno::Reference< css::sdbc::XConnection > buildIsolatedConnection(
+ const OUString& user, const OUString& password
+ );
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > getConnection( const OUString& user, const OUString& password , bool _bIsolated);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > connectWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler , bool _bIsolated);
+
+protected:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/definitioncontainer.cxx b/dbaccess/source/core/dataaccess/definitioncontainer.cxx
new file mode 100644
index 000000000..81d8b0302
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/definitioncontainer.cxx
@@ -0,0 +1,679 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <definitioncontainer.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/enumhelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ref.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::ucb;
+
+namespace dbaccess
+{
+
+// ODefinitionContainer_Impl
+void ODefinitionContainer_Impl::erase( const TContentPtr& _pDefinition )
+{
+ NamedDefinitions::const_iterator aPos = find( _pDefinition );
+ if ( aPos != end() )
+ m_aDefinitions.erase( aPos );
+}
+
+ODefinitionContainer_Impl::const_iterator ODefinitionContainer_Impl::find( const TContentPtr& _pDefinition ) const
+{
+ return std::find_if(
+ m_aDefinitions.begin(),
+ m_aDefinitions.end(),
+ [&_pDefinition] (const NamedDefinitions::value_type& namedDef) {
+ return namedDef.second == _pDefinition;
+ });
+}
+
+ODefinitionContainer_Impl::iterator ODefinitionContainer_Impl::find( const TContentPtr& _pDefinition )
+{
+ return std::find_if(
+ m_aDefinitions.begin(),
+ m_aDefinitions.end(),
+ [&_pDefinition] (const NamedDefinitions::value_type& namedDef) {
+ return namedDef.second == _pDefinition;
+ });
+}
+
+// ODefinitionContainer
+
+ODefinitionContainer::ODefinitionContainer( const Reference< XComponentContext >& _xORB
+ , const Reference< XInterface >& _xParentContainer
+ , const TContentPtr& _pImpl
+ , bool _bCheckSlash
+ )
+ :OContentHelper(_xORB,_xParentContainer,_pImpl)
+ ,m_aApproveListeners(m_aMutex)
+ ,m_aContainerListeners(m_aMutex)
+ ,m_bInPropertyChange(false)
+ ,m_bCheckSlash(_bCheckSlash)
+{
+ assert(m_pImpl);
+ m_pImpl->m_aProps.bIsDocument = false;
+ m_pImpl->m_aProps.bIsFolder = true;
+
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ for (auto const& definition : rDefinitions)
+ m_aDocuments.push_back(
+ m_aDocumentMap.emplace(definition.first, Documents::mapped_type() ).first );
+
+}
+
+void SAL_CALL ODefinitionContainer::disposing()
+{
+ OContentHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ // say goodbye to our listeners
+ EventObject aEvt(*this);
+ m_aApproveListeners.disposeAndClear(aEvt);
+ m_aContainerListeners.disposeAndClear(aEvt);
+
+ // dispose our elements
+ for (auto const& elem : m_aDocumentMap)
+ {
+ Reference<XContent> xProp = elem.second;
+ if ( xProp.is() )
+ {
+ removeObjectListener(xProp);
+ ::comphelper::disposeComponent(xProp);
+ }
+ }
+
+ // remove our elements
+ m_aDocuments.clear();
+ // !!! do this before clearing the map which the vector elements refer to !!!
+ m_aDocumentMap.clear();
+}
+
+ODefinitionContainer::~ODefinitionContainer()
+{
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( ODefinitionContainer,OContentHelper,ODefinitionContainer_Base)
+css::uno::Sequence< css::uno::Type > ODefinitionContainer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OContentHelper::getTypes( ),
+ ODefinitionContainer_Base::getTypes( )
+ );
+}
+
+
+css::uno::Sequence<sal_Int8> ODefinitionContainer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+OUString SAL_CALL ODefinitionContainer::getImplementationName( )
+{
+ return "com.sun.star.sdb.ODefinitionContainer";
+}
+
+Sequence< OUString > SAL_CALL ODefinitionContainer::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.DefinitionContainer", "com.sun.star.ucb.Content" };
+}
+
+// XNameContainer
+void SAL_CALL ODefinitionContainer::insertByName( const OUString& _rName, const Any& aElement )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // approve the new object
+ Reference< XContent > xNewElement(aElement,UNO_QUERY);
+ approveNewObject( _rName, xNewElement ); // will throw if necessary
+
+ notifyByName( aGuard, _rName, xNewElement, nullptr, E_INSERTED, ApproveListeners );
+ implAppend( _rName, xNewElement );
+ notifyByName( aGuard, _rName, xNewElement, nullptr, E_INSERTED, ContainerListemers );
+}
+
+void SAL_CALL ODefinitionContainer::removeByName( const OUString& _rName )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException(_rName,*this);
+
+ // the old element (for the notifications)
+ Reference< XContent > xOldElement = implGetByName( _rName, impl_haveAnyListeners_nothrow() );
+
+ // do the removal
+ notifyByName( aGuard, _rName, nullptr, xOldElement, E_REMOVED, ApproveListeners );
+ implRemove( _rName );
+ notifyByName( aGuard, _rName, nullptr, xOldElement, E_REMOVED, ContainerListemers );
+
+ removeObjectListener( xOldElement );
+ disposeComponent(xOldElement);
+}
+
+// XNameReplace
+void SAL_CALL ODefinitionContainer::replaceByName( const OUString& _rName, const Any& aElement )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ try
+ {
+ // let derived classes approve the new object
+ Reference< XContent > xNewElement(aElement,UNO_QUERY);
+ approveNewObject( _rName, xNewElement ); // will throw if necessary
+
+ // the old element (for the notifications)
+ Reference< XContent > xOldElement = implGetByName( _rName, impl_haveAnyListeners_nothrow() );
+
+ notifyByName( aGuard, _rName, xNewElement, xOldElement, E_REPLACED, ApproveListeners );
+ implReplace( _rName, xNewElement );
+ notifyByName( aGuard, _rName, xNewElement, xOldElement, E_REPLACED, ContainerListemers );
+
+ // and dispose it
+ disposeComponent(xOldElement);
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const NoSuchElementException&)
+ {
+ throw;
+ }
+ catch (const WrappedTargetException&)
+ {
+ throw;
+ }
+ catch (const Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+}
+
+namespace
+{
+ typedef Reference< XVeto > ( SAL_CALL XContainerApproveListener::*ContainerApprovalMethod )( const ContainerEvent& );
+
+ struct RaiseExceptionFromVeto
+ {
+ private:
+ ContainerApprovalMethod m_pMethod;
+ const ContainerEvent& m_rEvent;
+
+ public:
+ explicit RaiseExceptionFromVeto( ContainerApprovalMethod _pMethod, const ContainerEvent& _rEvent )
+ :m_pMethod( _pMethod )
+ ,m_rEvent( _rEvent )
+ {
+ }
+
+ void operator()( const Reference< XContainerApproveListener >& Listener ) const
+ {
+ Reference< XVeto > xVeto = (Listener.get()->*m_pMethod)( m_rEvent );
+ if ( !xVeto.is() )
+ return;
+
+ Any eVetoDetails = xVeto->getDetails();
+
+ IllegalArgumentException aIllegalArgumentError;
+ if ( eVetoDetails >>= aIllegalArgumentError )
+ throw aIllegalArgumentError;
+
+ WrappedTargetException aWrappedError;
+ if ( eVetoDetails >>= aWrappedError )
+ throw aWrappedError;
+
+ throw WrappedTargetException( xVeto->getReason(), Listener, eVetoDetails );
+ }
+ };
+}
+
+void ODefinitionContainer::notifyByName( ResettableMutexGuard& _rGuard, const OUString& _rName,
+ const Reference< XContent >& _xNewElement, const Reference< XContent >& _xOldElement,
+ ContainerOperation _eOperation, ListenerType _eType )
+{
+ bool bApprove = ( _eType == ApproveListeners );
+
+ ::comphelper::OInterfaceContainerHelper2& rContainer( bApprove ? m_aApproveListeners : m_aContainerListeners );
+ if ( !rContainer.getLength() )
+ return;
+
+ ContainerEvent aEvent( *this, Any( _rName ), Any( _xNewElement ), Any( _xOldElement ) );
+
+ _rGuard.clear();
+ switch ( _eOperation )
+ {
+ case E_INSERTED:
+ if ( bApprove )
+ rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >(
+ RaiseExceptionFromVeto( &XContainerApproveListener::approveInsertElement, aEvent ) );
+ else
+ rContainer.notifyEach( &XContainerListener::elementInserted, aEvent );
+ break;
+ case E_REPLACED:
+ if ( bApprove )
+ rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >(
+ RaiseExceptionFromVeto( &XContainerApproveListener::approveReplaceElement, aEvent ) );
+ else
+ rContainer.notifyEach( &XContainerListener::elementReplaced, aEvent );
+ break;
+ case E_REMOVED:
+ if ( bApprove )
+ rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >(
+ RaiseExceptionFromVeto( &XContainerApproveListener::approveRemoveElement, aEvent ) );
+ else
+ rContainer.notifyEach( &XContainerListener::elementRemoved, aEvent );
+ break;
+ }
+
+ if ( bApprove )
+ _rGuard.reset();
+}
+
+void SAL_CALL ODefinitionContainer::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ if (_rxListener.is())
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL ODefinitionContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ if (_rxListener.is())
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+void SAL_CALL ODefinitionContainer::addContainerApproveListener( const Reference< XContainerApproveListener >& Listener )
+{
+ if ( Listener.is() )
+ m_aApproveListeners.addInterface( Listener );
+}
+
+void SAL_CALL ODefinitionContainer::removeContainerApproveListener( const Reference< XContainerApproveListener >& Listener )
+{
+ if ( Listener.is() )
+ m_aApproveListeners.removeInterface( Listener );
+}
+
+// XElementAccess
+Type SAL_CALL ODefinitionContainer::getElementType( )
+{
+ return cppu::UnoType<XContent>::get();
+}
+
+sal_Bool SAL_CALL ODefinitionContainer::hasElements( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return !m_aDocuments.empty();
+}
+
+// XEnumerationAccess
+Reference< XEnumeration > SAL_CALL ODefinitionContainer::createEnumeration( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this));
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL ODefinitionContainer::getCount( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_aDocuments.size();
+}
+
+Any SAL_CALL ODefinitionContainer::getByIndex( sal_Int32 _nIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if ((_nIndex < 0) || (o3tl::make_unsigned(_nIndex) >= m_aDocuments.size()))
+ throw IndexOutOfBoundsException();
+
+ Documents::iterator aPos = m_aDocuments[_nIndex];
+ Reference<XContent> xProp = aPos->second;
+ if (!xProp.is())
+ { // that's the first access to the object
+ // -> create it
+ xProp = createObject(aPos->first);
+ aPos->second = Documents::mapped_type();
+ // and update the name-access map
+ }
+
+ return Any(xProp);
+}
+
+Any SAL_CALL ODefinitionContainer::getByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ return Any( implGetByName( _rName, true ) );
+}
+
+Reference< XContent > ODefinitionContainer::implGetByName(const OUString& _rName, bool _bReadIfNecessary)
+{
+ Documents::iterator aMapPos = m_aDocumentMap.find(_rName);
+ if (aMapPos == m_aDocumentMap.end())
+ throw NoSuchElementException(_rName,*this);
+
+ Reference< XContent > xProp = aMapPos->second;
+
+ if (_bReadIfNecessary && !xProp.is())
+ { // the object has never been accessed before, so we have to read it now
+ // (that's the expensive part)
+
+ // create the object and insert it into the map
+ xProp = createObject(_rName);
+ aMapPos->second = xProp;
+ addObjectListener(xProp);
+ }
+
+ return xProp;
+}
+
+Sequence< OUString > SAL_CALL ODefinitionContainer::getElementNames( )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ Sequence< OUString > aNames(m_aDocumentMap.size());
+ OUString* pNames = aNames.getArray();
+ for (auto const& elem : m_aDocumentMap)
+ {
+ *pNames = elem.first;
+ ++pNames;
+ }
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL ODefinitionContainer::hasByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ return checkExistence(_rName);
+}
+
+void SAL_CALL ODefinitionContainer::disposing( const EventObject& _rSource )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference< XContent > xSource(_rSource.Source, UNO_QUERY);
+ // it's one of our documents...
+ for (auto & elem : m_aDocumentMap)
+ {
+ if ( xSource == elem.second.get() )
+ {
+ removeObjectListener(xSource);
+ // and clear our document map/vector, so the object will be recreated on next access
+ elem.second = Documents::mapped_type();
+ }
+ }
+}
+
+void ODefinitionContainer::implRemove(const OUString& _rName)
+{
+ // from the object maps
+ Documents::const_iterator aFind = m_aDocumentMap.find(_rName);
+ if ( aFind != m_aDocumentMap.end() )
+ {
+ m_aDocuments.erase( std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind));
+ m_aDocumentMap.erase(aFind);
+
+ getDefinitions().erase( _rName );
+
+ notifyDataSourceModified();
+ }
+}
+
+namespace
+{
+ bool lcl_ensureName( const Reference< XContent >& _rxContent, const OUString& _rName )
+ {
+ if ( !_rxContent.is() )
+ return true;
+
+ // obtain the current name. If it's the same as the new one,
+ // don't do anything
+ try
+ {
+ Reference< XPropertySet > xProps( _rxContent, UNO_QUERY );
+ if ( xProps.is() )
+ {
+ OUString sCurrentName;
+ OSL_VERIFY( xProps->getPropertyValue( PROPERTY_NAME ) >>= sCurrentName );
+ if ( sCurrentName == _rName )
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "lcl_ensureName: caught an exception while obtaining the current name!" );
+ }
+
+ // set the new name
+ Reference< XRename > xRename( _rxContent, UNO_QUERY );
+ OSL_ENSURE( xRename.is(), "lcl_ensureName: invalid content (not renameable)!" );
+ if ( !xRename.is() )
+ return false;
+ try
+ {
+ xRename->rename( _rName );
+ return true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "lcl_ensureName" );
+ }
+ return false;
+ }
+}
+
+void ODefinitionContainer::implAppend(const OUString& _rName, const Reference< XContent >& _rxNewObject)
+{
+ MutexGuard aGuard(m_aMutex);
+ try
+ {
+ Reference<XChild> xChild(_rxNewObject,UNO_QUERY);
+ if ( xChild.is() )
+ xChild->setParent(static_cast<OWeakObject*>(this));
+
+ ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( _rName );
+ if ( aFind == rDefinitions.end() )
+ {
+ // ensure that the new object has the proper name.
+ // Somebody could create an object with name "foo", and insert it as "bar"
+ // into a container. In this case, we need to ensure that the object name
+ // is also "bar"
+ // #i44786#
+ lcl_ensureName( _rxNewObject, _rName );
+
+ ::rtl::Reference< OContentHelper > pContent = comphelper::getFromUnoTunnel<OContentHelper>( _rxNewObject );
+ if ( pContent.is() )
+ {
+ TContentPtr pImpl = pContent->getImpl();
+ rDefinitions.erase( pImpl );
+ pImpl->m_aProps.aTitle = _rName;
+ rDefinitions.insert( _rName, pImpl );
+ }
+ }
+
+ m_aDocuments.push_back(m_aDocumentMap.emplace(_rName,_rxNewObject).first);
+ notifyDataSourceModified();
+ // now update our structures
+ if ( _rxNewObject.is() )
+ addObjectListener(_rxNewObject);
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("ODefinitionContainer::implAppend: caught something !");
+ }
+}
+
+void ODefinitionContainer::implReplace(const OUString& _rName, const Reference< XContent >& _rxNewObject)
+{
+ OSL_ENSURE(checkExistence(_rName), "ODefinitionContainer::implReplace : invalid name !");
+
+ Documents::iterator aFind = m_aDocumentMap.find(_rName);
+ removeObjectListener(aFind->second);
+ aFind->second = _rxNewObject;
+ addObjectListener(aFind->second);
+}
+
+void ODefinitionContainer::approveNewObject(const OUString& _sName,const Reference< XContent >& _rxObject) const
+{
+ // check the arguments
+ if ( _sName.isEmpty() )
+ throw IllegalArgumentException(
+ DBA_RES( RID_STR_NAME_MUST_NOT_BE_EMPTY ),
+ *this,
+ 0 );
+
+ if ( m_bCheckSlash && _sName.indexOf( '/' ) != -1 )
+ throw IllegalArgumentException(
+ m_aErrorHelper.getErrorMessage( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES ),
+ *this,
+ 0 );
+
+ if ( !_rxObject.is() )
+ throw IllegalArgumentException(
+ DBA_RES( RID_STR_NO_NULL_OBJECTS_IN_CONTAINER ),
+ *this,
+ 0 );
+
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ if ( rDefinitions.find( _sName ) != rDefinitions.end() )
+ throw ElementExistException(
+ DBA_RES( RID_STR_NAME_ALREADY_USED ),
+ *this );
+
+ ::rtl::Reference< OContentHelper > pContent( comphelper::getFromUnoTunnel<OContentHelper>( _rxObject ) );
+ if ( !pContent.is() )
+ throw IllegalArgumentException(
+ DBA_RES( RID_STR_OBJECT_CONTAINER_MISMATCH ),
+ *this,
+ 1 );
+
+ if ( rDefinitions.find( pContent->getImpl() ) != rDefinitions.end() )
+ throw ElementExistException(
+ DBA_RES( RID_STR_OBJECT_ALREADY_CONTAINED ),
+ *this );
+}
+
+// XPropertyChangeListener
+void SAL_CALL ODefinitionContainer::propertyChange( const PropertyChangeEvent& evt )
+{
+ if( evt.PropertyName != PROPERTY_NAME && evt.PropertyName != "Title" )
+ return;
+
+ MutexGuard aGuard(m_aMutex);
+
+ m_bInPropertyChange = true;
+ try
+ {
+ OUString sNewName,sOldName;
+ evt.OldValue >>= sOldName;
+ evt.NewValue >>= sNewName;
+ Reference<XContent> xContent( evt.Source, UNO_QUERY );
+ removeObjectListener( xContent );
+ implRemove( sOldName );
+ implAppend( sNewName, xContent );
+ }
+ catch(const Exception& ex)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( ex.Message,
+ nullptr, anyEx );
+ }
+ m_bInPropertyChange = false;
+}
+
+// XVetoableChangeListener
+void SAL_CALL ODefinitionContainer::vetoableChange( const PropertyChangeEvent& aEvent )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if( aEvent.PropertyName == PROPERTY_NAME || aEvent.PropertyName == "Title" )
+ {
+ OUString sNewName;
+ aEvent.NewValue >>= sNewName;
+ if(hasByName(sNewName))
+ throw PropertyVetoException();
+ }
+}
+
+void ODefinitionContainer::addObjectListener(const Reference< XContent >& _xNewObject)
+{
+ OSL_ENSURE(_xNewObject.is(),"ODefinitionContainer::addObjectListener: Object is null!");
+ Reference<XPropertySet> xProp(_xNewObject,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->addPropertyChangeListener(PROPERTY_NAME, this);
+ xProp->addVetoableChangeListener(PROPERTY_NAME, this);
+ }
+}
+
+void ODefinitionContainer::removeObjectListener(const Reference< XContent >& _xNewObject)
+{
+ Reference<XPropertySet> xProp(_xNewObject,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->removePropertyChangeListener(PROPERTY_NAME, this);
+ xProp->removeVetoableChangeListener(PROPERTY_NAME, this);
+ }
+}
+
+bool ODefinitionContainer::checkExistence(const OUString& _rName)
+{
+ return m_aDocumentMap.find(_rName) != m_aDocumentMap.end();
+}
+
+}
+
+// namespace dbaccess
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentcontainer.cxx b/dbaccess/source/core/dataaccess/documentcontainer.cxx
new file mode 100644
index 000000000..6a9f17adb
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentcontainer.cxx
@@ -0,0 +1,770 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "documentcontainer.hxx"
+#include <stringconstants.hxx>
+#include "documentdefinition.hxx"
+#include <ModelImpl.hxx>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <connectivity/dbtools.hxx>
+#include "myucp_resultset.hxx"
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
+#include <com/sun/star/ucb/InsertCommandArgument.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <comphelper/mimeconfighelper.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::io;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+namespace {
+
+// LocalNameApproval
+class LocalNameApproval : public IContainerApprove
+{
+ ::connectivity::SQLError m_aErrors;
+
+public:
+ void approveElement( const OUString& _rName ) override;
+};
+
+}
+
+void LocalNameApproval::approveElement( const OUString& _rName )
+{
+ if ( _rName.indexOf( '/' ) != -1 )
+ throw IllegalArgumentException(
+ m_aErrors.getErrorMessage( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES ),
+ nullptr,
+ 0
+ );
+}
+
+// ODocumentContainer
+
+ODocumentContainer::ODocumentContainer(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ , bool _bFormsContainer
+ )
+ :ODefinitionContainer(_xORB,_xParentContainer,_pImpl)
+ ,OPropertyStateContainer(OContentHelper::rBHelper)
+ ,m_bFormsContainer(_bFormsContainer)
+{
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY | PropertyAttribute::CONSTRAINED,
+ &m_pImpl->m_aProps.aTitle, cppu::UnoType<decltype(m_pImpl->m_aProps.aTitle)>::get());
+
+ setElementApproval( std::make_shared<LocalNameApproval>() );
+}
+
+ODocumentContainer::~ODocumentContainer()
+{
+
+ if ( !OContentHelper::rBHelper.bInDispose && !OContentHelper::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3( ODocumentContainer,ODefinitionContainer,ODocumentContainer_Base,OPropertyStateContainer)
+
+css::uno::Sequence<sal_Int8> ODocumentContainer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > ODocumentContainer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ ODefinitionContainer::getTypes( ),
+ OPropertyStateContainer::getTypes( ),
+ ODocumentContainer_Base::getTypes( )
+ );
+}
+OUString SAL_CALL ODocumentContainer::getImplementationName()
+ {
+ return "com.sun.star.comp.dba.ODocumentContainer";
+ };
+sal_Bool SAL_CALL ODocumentContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ };
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODocumentContainer::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+::cppu::IPropertyArrayHelper& ODocumentContainer::getInfoHelper()
+{
+ return *ODocumentContainer::getArrayHelper();
+}
+::cppu::IPropertyArrayHelper* ODocumentContainer::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+Sequence< OUString > SAL_CALL ODocumentContainer::getSupportedServiceNames( )
+{
+ return { m_bFormsContainer ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION) };
+}
+
+OUString ODocumentContainer::determineContentType() const
+{
+ return OUString();
+}
+
+Reference< XContent > ODocumentContainer::createObject( const OUString& _rName)
+{
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( _rName );
+ OSL_ENSURE( aFind != rDefinitions.end(), "ODocumentContainer::createObject:Invalid entry in map!" );
+ if ( aFind->second->m_aProps.bIsFolder )
+ return new ODocumentContainer( m_aContext, *this, aFind->second, m_bFormsContainer );
+ return new ODocumentDefinition( *this, m_aContext, aFind->second, m_bFormsContainer );
+}
+
+Reference< XInterface > SAL_CALL ODocumentContainer::createInstance( const OUString& aServiceSpecifier )
+{
+ return createInstanceWithArguments( aServiceSpecifier, Sequence< Any >() );
+}
+
+namespace
+{
+ template< class TYPE >
+ void lcl_extractAndRemove( ::comphelper::NamedValueCollection& io_rArguments, const OUString& i_rName, TYPE& o_rValue )
+ {
+ if ( io_rArguments.has( i_rName ) )
+ {
+ io_rArguments.get_ensureType( i_rName, o_rValue );
+ io_rArguments.remove( i_rName );
+ }
+ }
+}
+
+Reference< XInterface > SAL_CALL ODocumentContainer::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& _aArguments )
+{
+ Reference< XInterface > xRet;
+ Reference< XContent > xContent;
+ if ( ServiceSpecifier == SERVICE_SDB_DOCUMENTDEFINITION )
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ // extract known arguments
+ OUString sName, sPersistentName, sURL, sMediaType, sDocServiceName;
+ Reference< XCommandProcessor > xCopyFrom;
+ Reference< XConnection > xConnection;
+ bool bAsTemplate( false );
+ Sequence< sal_Int8 > aClassID;
+
+ ::comphelper::NamedValueCollection aArgs( _aArguments );
+ lcl_extractAndRemove( aArgs, PROPERTY_NAME, sName );
+ lcl_extractAndRemove( aArgs, PROPERTY_PERSISTENT_NAME, sPersistentName );
+ lcl_extractAndRemove( aArgs, PROPERTY_URL, sURL );
+ lcl_extractAndRemove( aArgs, PROPERTY_EMBEDDEDOBJECT, xCopyFrom );
+ lcl_extractAndRemove( aArgs, PROPERTY_ACTIVE_CONNECTION, xConnection );
+ lcl_extractAndRemove( aArgs, PROPERTY_AS_TEMPLATE, bAsTemplate );
+ lcl_extractAndRemove( aArgs, INFO_MEDIATYPE, sMediaType );
+ lcl_extractAndRemove( aArgs, "DocumentServiceName" , sDocServiceName );
+
+ // ClassID has two allowed types, so a special treatment here
+ Any aClassIDArg = aArgs.get( "ClassID" );
+ if ( aClassIDArg.hasValue() )
+ {
+ if ( !( aClassIDArg >>= aClassID ) )
+ {
+ // Extended for usage also with a string
+ OUString sClassIDString;
+ if ( !( aClassIDArg >>= sClassIDString ) )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+
+ aClassID = ::comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation( sClassIDString );
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ OUString sClassIDString = ::comphelper::MimeConfigurationHelper::GetStringClassIDRepresentation( aClassID );
+ (void)sClassIDString;
+#endif
+ aArgs.remove( "ClassID" );
+ }
+ // Everything which now is still present in the arguments is passed to the embedded object
+ const Sequence< PropertyValue > aCreationArgs( aArgs.getPropertyValues() );
+
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ bool bNew = sPersistentName.isEmpty();
+ if ( bNew )
+ {
+ sPersistentName = "Obj" + OUString::number(rDefinitions.size() + 1);
+ Reference<XNameAccess> xElements = getContainerStorage();
+ if ( xElements.is() )
+ sPersistentName = ::dbtools::createUniqueName(xElements,sPersistentName);
+
+ const bool bNeedClassID = !aClassID.hasElements() && sURL.isEmpty() ;
+ if ( xCopyFrom.is() )
+ {
+ Sequence<Any> aIni{ Any(getContainerStorage()), Any(sPersistentName) };
+ Command aCommand;
+ aCommand.Name = "copyTo";
+ aCommand.Argument <<= aIni;
+
+ xCopyFrom->execute(aCommand,-1,Reference< XCommandEnvironment >());
+ Reference<XPropertySet> xProp(xCopyFrom,UNO_QUERY);
+ if ( xProp.is() && xProp->getPropertySetInfo().is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_AS_TEMPLATE) )
+ xProp->getPropertyValue(PROPERTY_AS_TEMPLATE) >>= bAsTemplate;
+
+ // if we do not have an own class ID, see if we can determine one from the copy we just created
+ if ( bNeedClassID )
+ ODocumentDefinition::GetDocumentServiceFromMediaType( getContainerStorage(), sPersistentName, m_aContext, aClassID );
+ }
+ else
+ {
+ if ( bNeedClassID )
+ {
+ if ( !sMediaType.isEmpty() )
+ ODocumentDefinition::GetDocumentServiceFromMediaType( sMediaType, m_aContext, aClassID );
+ else if ( !sDocServiceName.isEmpty() )
+ {
+ ::comphelper::MimeConfigurationHelper aConfigHelper( m_aContext );
+ const Sequence< NamedValue > aProps( aConfigHelper.GetObjectPropsByDocumentName( sDocServiceName ) );
+ const ::comphelper::NamedValueCollection aMediaTypeProps( aProps );
+ aClassID = aMediaTypeProps.getOrDefault( "ClassID", Sequence< sal_Int8 >() );
+ }
+ }
+ }
+ }
+
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( sName );
+ TContentPtr pElementImpl;
+ if ( bNew || ( aFind == rDefinitions.end() ) )
+ {
+ pElementImpl = std::make_shared<OContentHelper_Impl>();
+ if ( !bNew )
+ pElementImpl->m_aProps.aTitle = sName;
+
+ pElementImpl->m_aProps.sPersistentName = sPersistentName;
+ pElementImpl->m_aProps.bAsTemplate = bAsTemplate;
+ pElementImpl->m_pDataSource = m_pImpl->m_pDataSource;
+ }
+ else
+ pElementImpl = aFind->second;
+
+ ::rtl::Reference< ODocumentDefinition > pDocDef = new ODocumentDefinition( *this, m_aContext, pElementImpl, m_bFormsContainer );
+ if ( aClassID.hasElements() )
+ {
+ pDocDef->initialLoad( aClassID, aCreationArgs, xConnection );
+ }
+ else
+ {
+ OSL_ENSURE( !aCreationArgs.hasElements(), "ODocumentContainer::createInstance: additional creation args are lost, if you do not provide a class ID." );
+ }
+ xContent = pDocDef.get();
+
+ if ( !sURL.isEmpty() )
+ {
+ Sequence<Any> aIni{ Any(sURL) };
+ Command aCommand;
+ aCommand.Name = "insert";
+ aCommand.Argument <<= aIni;
+ Reference< XCommandProcessor > xCommandProcessor(xContent,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ xCommandProcessor->execute(aCommand,-1,Reference< XCommandEnvironment >());
+ }
+ }
+ }
+ else if ( ServiceSpecifier == SERVICE_NAME_FORM_COLLECTION || SERVICE_NAME_REPORT_COLLECTION == ServiceSpecifier )
+ {
+ const Any* pBegin = _aArguments.getConstArray();
+ const Any* pEnd = pBegin + _aArguments.getLength();
+ PropertyValue aValue;
+ OUString sName;
+ Reference<XNameAccess> xCopyFrom;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ *pBegin >>= aValue;
+ if ( aValue.Name == PROPERTY_NAME)
+ {
+ aValue.Value >>= sName;
+ }
+ else if ( aValue.Name == PROPERTY_EMBEDDEDOBJECT)
+ {
+ xCopyFrom.set(aValue.Value,UNO_QUERY);
+ }
+ }
+ OSL_ENSURE(!sName.isEmpty(),"Invalid name for a document container!");
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( sName );
+ TContentPtr pElementImpl;
+ if ( aFind == rDefinitions.end() )
+ {
+ pElementImpl = std::make_shared<ODefinitionContainer_Impl>();
+ pElementImpl->m_aProps.aTitle = sName;
+ pElementImpl->m_pDataSource = m_pImpl->m_pDataSource;
+ }
+ else
+ pElementImpl = aFind->second;
+ OSL_ENSURE( pElementImpl ," Invalid entry in map!");
+ xContent = new ODocumentContainer( m_aContext, *this, pElementImpl, ServiceSpecifier == SERVICE_NAME_FORM_COLLECTION );
+
+ // copy children
+ if ( xCopyFrom.is() )
+ {
+ Sequence< OUString> aSeq = xCopyFrom->getElementNames();
+ const OUString* elements = aSeq.getConstArray();
+ const OUString* elementsEnd = elements + aSeq.getLength();
+ Reference<XContent> xObjectToCopy;
+
+ Reference<XMultiServiceFactory> xORB(xContent,UNO_QUERY);
+ OSL_ENSURE(xORB.is(),"No service factory given");
+ if ( xORB.is() )
+ {
+ for(;elements != elementsEnd;++elements)
+ {
+ xCopyFrom->getByName(*elements) >>= xObjectToCopy;
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"Name", Any(*elements)}, // set as folder
+ {"Parent", Any(xContent)},
+ {PROPERTY_EMBEDDEDOBJECT, Any(xObjectToCopy)},
+ }));
+
+ OUString sServiceName;
+ if ( Reference< XNameAccess >( xObjectToCopy, UNO_QUERY ).is() )
+ {
+ if ( m_bFormsContainer )
+ sServiceName = SERVICE_NAME_FORM_COLLECTION;
+ else
+ sServiceName = SERVICE_NAME_REPORT_COLLECTION;
+ }
+ else
+ sServiceName = SERVICE_SDB_DOCUMENTDEFINITION;
+
+ Reference<XContent > xNew(xORB->createInstanceWithArguments(sServiceName,aArguments),UNO_QUERY);
+ Reference<XNameContainer> xNameContainer(xContent,UNO_QUERY);
+ if ( xNameContainer.is() )
+ xNameContainer->insertByName(*elements,Any(xNew));
+ }
+ }
+ }
+ }
+ xRet = xContent;
+ return xRet;
+}
+
+Sequence< OUString > SAL_CALL ODocumentContainer::getAvailableServiceNames( )
+{
+ return
+ {
+ SERVICE_SDB_DOCUMENTDEFINITION,
+ SERVICE_NAME_FORM_COLLECTION,
+ SERVICE_NAME_REPORT_COLLECTION
+ };
+}
+
+Any SAL_CALL ODocumentContainer::execute( const Command& aCommand, sal_Int32 CommandId, const Reference< XCommandEnvironment >& Environment )
+{
+ Any aRet;
+ if ( aCommand.Name == "open" )
+ {
+ // open command for a folder content
+ OpenCommandArgument2 aOpenCommand;
+ if ( !( aCommand.Argument >>= aOpenCommand ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ bool bOpenFolder =
+ ( ( aOpenCommand.Mode == OpenMode::ALL ) ||
+ ( aOpenCommand.Mode == OpenMode::FOLDERS ) ||
+ ( aOpenCommand.Mode == OpenMode::DOCUMENTS ) );
+
+ if ( bOpenFolder )
+ {
+ // open as folder - return result set
+
+ Reference< XDynamicResultSet > xSet
+ = new DynamicResultSet( m_aContext,
+ this,
+ aOpenCommand,
+ Environment );
+ aRet <<= xSet;
+ }
+ else
+ {
+ // Unsupported.
+ ucbhelper::cancelCommandExecution(
+ Any( UnsupportedOpenModeException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ sal_Int16( aOpenCommand.Mode ) ) ),
+ Environment );
+ // Unreachable
+ }
+ }
+ else if ( aCommand.Name == "insert" )
+ {
+ // insert
+
+ InsertCommandArgument arg;
+ if ( !( aCommand.Argument >>= arg ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ }
+ else if ( aCommand.Name == "delete" )
+ {
+ // delete
+ Sequence< OUString> aSeq = getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ removeByName(*pIter);
+
+ dispose();
+ }
+ else
+ aRet = OContentHelper::execute(aCommand,CommandId,Environment);
+ return aRet;
+}
+
+namespace
+{
+ bool lcl_queryContent(std::u16string_view _sName,Reference< XNameContainer >& _xNameContainer,Any& _rRet,OUString& _sSimpleName)
+ {
+ sal_Int32 nIndex = 0;
+ OUString sName( o3tl::getToken(_sName,0,'/',nIndex) );
+ bool bRet = _xNameContainer->hasByName(sName);
+ if ( bRet )
+ {
+ _sSimpleName = sName;
+ _rRet = _xNameContainer->getByName(_sSimpleName);
+ while ( nIndex != -1 && bRet )
+ {
+ sName = o3tl::getToken(_sName,0,'/',nIndex);
+ _xNameContainer.set(_rRet,UNO_QUERY);
+ bRet = _xNameContainer.is();
+ if ( bRet )
+ {
+ bRet = _xNameContainer->hasByName(sName);
+ _sSimpleName = sName;
+ if ( bRet )
+ _rRet = _xNameContainer->getByName(sName);
+ }
+ }
+ }
+ if ( nIndex == -1 )
+ _sSimpleName = sName; // a content
+ else
+ _xNameContainer.clear(); // a sub folder doesn't exist
+ return bRet;
+ }
+}
+
+Reference< XComponent > SAL_CALL ODocumentContainer::loadComponentFromURL( const OUString& _sURL
+ , const OUString& /*TargetFrameName*/
+ , sal_Int32 /*SearchFlags*/
+ , const Sequence< PropertyValue >& Arguments )
+{
+ ::SolarMutexGuard aSolarGuard;
+
+ MutexGuard aGuard(m_aMutex);
+ Reference< XComponent > xComp;
+ try
+ {
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ if ( !lcl_queryContent(_sURL,xNameContainer,aContent,sName) )
+ {
+ OUString sMessage(
+ DBA_RES(RID_STR_NAME_NOT_FOUND).replaceFirst("$name$", _sURL));
+ throw IllegalArgumentException( sMessage, *this, 1 );
+ }
+
+ Reference< XCommandProcessor > xContent(aContent,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ Command aCommand;
+
+ ::comphelper::NamedValueCollection aArgs( Arguments );
+ aCommand.Name = aArgs.getOrDefault( "OpenMode", OUString("open") );
+ aArgs.remove( "OpenMode" );
+
+ OpenCommandArgument2 aOpenCommand;
+ aOpenCommand.Mode = OpenMode::DOCUMENT;
+ aArgs.put( "OpenCommandArgument", aOpenCommand );
+
+ aCommand.Argument <<= aArgs.getPropertyValues();
+ xComp.set(xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()),UNO_QUERY);
+ }
+ }
+ catch(const NoSuchElementException&)
+ {
+ throw IllegalArgumentException();
+ }
+ catch(const WrappedTargetException &e)
+ {
+ throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
+ }
+ return xComp;
+}
+
+Any SAL_CALL ODocumentContainer::getByHierarchicalName( const OUString& _sName )
+{
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ if ( lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ return aContent;
+ throw NoSuchElementException(_sName,*this);
+}
+
+sal_Bool SAL_CALL ODocumentContainer::hasByHierarchicalName( const OUString& _sName )
+{
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ return lcl_queryContent(_sName,xNameContainer,aContent,sName);
+}
+
+// XHierarchicalNameContainer
+void SAL_CALL ODocumentContainer::insertByHierarchicalName( const OUString& _sName, const Any& _aElement )
+{
+ Reference< XContent > xContent(_aElement,UNO_QUERY);
+ if ( !xContent.is() )
+ throw IllegalArgumentException();
+
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ if ( lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ throw ElementExistException(_sName,*this);
+
+ if ( !xNameContainer.is() )
+ {
+ sal_Int32 index = sName.getLength();
+ OUString sMessage(
+ DBA_RES(RID_STR_NO_SUB_FOLDER).replaceFirst("$folder$",
+ o3tl::getToken(_sName, 0,'/',index)));
+ throw IllegalArgumentException( sMessage, *this, 1 );
+ }
+
+ xNameContainer->insertByName(sName,_aElement);
+}
+
+void SAL_CALL ODocumentContainer::removeByHierarchicalName( const OUString& _sName )
+{
+ if ( _sName.isEmpty() )
+ throw NoSuchElementException(_sName,*this);
+
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ OUString sName;
+ Reference< XNameContainer > xNameContainer(this);
+ if ( !lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ throw NoSuchElementException(_sName,*this);
+
+ xNameContainer->removeByName(sName);
+}
+
+// XHierarchicalNameReplace
+void SAL_CALL ODocumentContainer::replaceByHierarchicalName( const OUString& _sName, const Any& _aElement )
+{
+ Reference< XContent > xContent(_aElement,UNO_QUERY);
+ if ( !xContent.is() )
+ throw IllegalArgumentException();
+
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ OUString sName;
+ Reference< XNameContainer > xNameContainer(this);
+ if ( !lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ throw NoSuchElementException(_sName,*this);
+
+ xNameContainer->replaceByName(sName,_aElement);
+}
+
+OUString SAL_CALL ODocumentContainer::getHierarchicalName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return impl_getHierarchicalName( false );
+}
+
+OUString SAL_CALL ODocumentContainer::composeHierarchicalName( const OUString& i_rRelativeName )
+{
+ OUString aBuffer = getHierarchicalName() + "/" + i_rRelativeName;
+ return aBuffer;
+}
+
+::rtl::Reference<OContentHelper> ODocumentContainer::getContent(const OUString& _sName) const
+{
+ ::rtl::Reference<OContentHelper> pContent;
+ try
+ {
+ pContent = comphelper::getFromUnoTunnel<OContentHelper>(const_cast<ODocumentContainer*>(this)->implGetByName( _sName, true ));
+ }
+ catch(const Exception&)
+ {
+ }
+ return pContent;
+}
+
+void ODocumentContainer::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const
+{
+ _rDefault.clear();
+}
+
+void SAL_CALL ODocumentContainer::commit( )
+{
+ MutexGuard aGuard(m_aMutex);
+ for (auto const& elem : m_aDocumentMap)
+ {
+ Reference<XTransactedObject> xTrans(elem.second.get(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->commit();
+ }
+ Reference<XTransactedObject> xTrans(getContainerStorage(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->commit();
+}
+
+void SAL_CALL ODocumentContainer::revert( )
+{
+ MutexGuard aGuard(m_aMutex);
+ for (auto const& elem : m_aDocumentMap)
+ {
+ Reference<XTransactedObject> xTrans(elem.second.get(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->revert();
+ }
+ Reference<XTransactedObject> xTrans(getContainerStorage(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->revert();
+}
+
+Reference< XStorage> ODocumentContainer::getContainerStorage() const
+{
+ return m_pImpl->m_pDataSource
+ ? m_pImpl->m_pDataSource->getStorage( m_bFormsContainer ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT )
+ : Reference< XStorage>();
+}
+
+void SAL_CALL ODocumentContainer::removeByName( const OUString& _rName )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException(_rName,*this);
+
+ Reference< XCommandProcessor > xContent( implGetByName( _rName, true ), UNO_QUERY );
+ if ( xContent.is() )
+ {
+ Command aCommand;
+
+ aCommand.Name = "delete";
+ xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >());
+ }
+
+ // do the removal
+ implRemove(_rName);
+
+ notifyByName( aGuard, _rName, nullptr, nullptr, E_REMOVED, ContainerListemers );
+}
+
+void SAL_CALL ODocumentContainer::rename( const OUString& newName )
+{
+ try
+ {
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ if ( newName == m_pImpl->m_aProps.aTitle )
+ return;
+
+ sal_Int32 nHandle = PROPERTY_ID_NAME;
+ Any aOld(m_pImpl->m_aProps.aTitle);
+ Any aNew(newName);
+
+ aGuard.clear();
+ fire(&nHandle, &aNew, &aOld, 1, true );
+ m_pImpl->m_aProps.aTitle = newName;
+ fire(&nHandle, &aNew, &aOld, 1, false );
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(newName,*this);
+ }
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentcontainer.hxx b/dbaccess/source/core/dataaccess/documentcontainer.hxx
new file mode 100644
index 000000000..d47709e80
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentcontainer.hxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <definitioncontainer.hxx>
+#include <cppuhelper/implbase5.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/container/XHierarchicalName.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <comphelper/propertystatecontainer.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <rtl/ref.hxx>
+#include <apitools.hxx>
+
+namespace dbaccess
+{
+typedef ::cppu::ImplHelper5 < css::frame::XComponentLoader
+ , css::lang::XMultiServiceFactory
+ , css::container::XHierarchicalNameContainer
+ , css::container::XHierarchicalName
+ , css::embed::XTransactedObject
+ > ODocumentContainer_Base;
+// ODocumentContainer - collections of database documents (reports/forms)
+class ODocumentContainer : public ODefinitionContainer
+ , public ODocumentContainer_Base
+ , public ::comphelper::OPropertyStateContainer
+ , public ::comphelper::OPropertyArrayUsageHelper< ODocumentContainer >
+{
+ bool m_bFormsContainer;
+
+public:
+ /** constructs the container.<BR>
+ */
+ ODocumentContainer(
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ , const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ , bool _bFormsContainer
+ );
+
+ // css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XComponentLoader
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponentFromURL( const OUString& URL, const OUString& TargetFrameName, sal_Int32 SearchFlags, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // css::lang::XMultiServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( const OUString& aServiceSpecifier ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const OUString& ServiceSpecifier, const css::uno::Sequence< css::uno::Any >& Arguments ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames( ) override;
+
+ // XCommandProcessor
+ virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override ;
+
+ // XHierarchicalNameAccess
+ virtual css::uno::Any SAL_CALL getByHierarchicalName( const OUString& _sName ) override;
+ virtual sal_Bool SAL_CALL hasByHierarchicalName( const OUString& _sName ) override;
+
+ // XHierarchicalNameContainer
+ virtual void SAL_CALL insertByHierarchicalName( const OUString& aName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByHierarchicalName( const OUString& Name ) override;
+
+ // XHierarchicalName
+ virtual OUString SAL_CALL getHierarchicalName( ) override;
+ virtual OUString SAL_CALL composeHierarchicalName( const OUString& aRelativeName ) override;
+
+ // XNameContainer
+ virtual void SAL_CALL removeByName( const OUString& _rName ) override;
+
+ // XHierarchicalNameReplace
+ virtual void SAL_CALL replaceByHierarchicalName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XTransactedObject
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL revert( ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // helper
+ ::rtl::Reference<OContentHelper> getContent(const OUString& _sName) const;
+ css::uno::Reference< css::embed::XStorage > getContainerStorage() const;
+
+protected:
+ virtual ~ODocumentContainer() override;
+
+ /** OContentHelper
+ */
+ virtual OUString determineContentType() const override;
+
+ // ODefinitionContainer
+ virtual css::uno::Reference< css::ucb::XContent > createObject(
+ const OUString& _rName
+ ) override;
+
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentdefinition.cxx b/dbaccess/source/core/dataaccess/documentdefinition.cxx
new file mode 100644
index 000000000..98e84d6d4
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentdefinition.cxx
@@ -0,0 +1,2102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "documentdefinition.hxx"
+#include <ModelImpl.hxx>
+#include <stringconstants.hxx>
+#include <sdbcoretools.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <comphelper/sequence.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/frame/XUntitledNumbers.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XTitle.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/task/XJobExecutor.hpp>
+#include <com/sun/star/report/XReportDefinition.hpp>
+#include <com/sun/star/report/XReportEngine.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/embed/WrongStateException.hpp>
+#include <com/sun/star/embed/EmbeddedObjectCreator.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/OOoEmbeddedObjectFactory.hpp>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EntryInitModes.hpp>
+#include <com/sun/star/ucb/MissingPropertiesException.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/frame/XModule.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/embed/XCommonEmbedPersist.hpp>
+#include "intercept.hxx"
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/XInteractionDocumentSave.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/sdb/DocumentSaveRequest.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <comphelper/interaction.hxx>
+#include <connectivity/dbtools.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <com/sun/star/view/XViewSettingsSupplier.hpp>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/task/XInteractionApprove.hpp>
+#include <com/sun/star/task/XInteractionDisapprove.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/mimeconfighelper.hxx>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/util/XModifiable2.hpp>
+
+using namespace ::com::sun::star;
+using namespace view;
+using namespace uno;
+using namespace util;
+using namespace ucb;
+using namespace beans;
+using namespace lang;
+using namespace awt;
+using namespace embed;
+using namespace frame;
+using namespace document;
+using namespace sdbc;
+using namespace sdb;
+using namespace io;
+using namespace container;
+using namespace datatransfer;
+using namespace task;
+using namespace form;
+using namespace drawing;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+using sdb::application::XDatabaseDocumentUI;
+namespace DatabaseObject = sdb::application::DatabaseObject;
+
+#define DEFAULT_WIDTH 10000
+#define DEFAULT_HEIGHT 7500
+
+namespace dbaccess
+{
+
+ typedef ::std::optional< bool > optional_bool;
+
+ // helper
+ namespace
+ {
+ OUString lcl_determineContentType_nothrow( const Reference< XStorage >& _rxContainerStorage,
+ const OUString& _rEntityName )
+ {
+ OUString sContentType;
+ try
+ {
+ ::utl::SharedUNOComponent< XPropertySet > xStorageProps(
+ _rxContainerStorage->openStorageElement( _rEntityName, ElementModes::READ ), UNO_QUERY_THROW );
+ OSL_VERIFY( xStorageProps->getPropertyValue( INFO_MEDIATYPE ) >>= sContentType );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sContentType;
+ }
+ }
+
+ // OEmbedObjectHolder
+ typedef ::cppu::WeakComponentImplHelper< embed::XStateChangeListener > TEmbedObjectHolder;
+
+ namespace {
+
+ class OEmbedObjectHolder : public ::cppu::BaseMutex
+ ,public TEmbedObjectHolder
+ {
+ Reference< XEmbeddedObject > m_xBroadCaster;
+ ODocumentDefinition* m_pDefinition;
+ bool m_bInStateChange;
+ protected:
+ virtual void SAL_CALL disposing() override;
+ public:
+ OEmbedObjectHolder(const Reference< XEmbeddedObject >& _xBroadCaster,ODocumentDefinition* _pDefinition)
+ : TEmbedObjectHolder(m_aMutex)
+ ,m_xBroadCaster(_xBroadCaster)
+ ,m_pDefinition(_pDefinition)
+ ,m_bInStateChange(false)
+ {
+ osl_atomic_increment( &m_refCount );
+ {
+ if ( m_xBroadCaster.is() )
+ m_xBroadCaster->addStateChangeListener(this);
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
+ virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
+ virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
+ };
+
+ }
+
+ void SAL_CALL OEmbedObjectHolder::disposing()
+ {
+ if ( m_xBroadCaster.is() )
+ m_xBroadCaster->removeStateChangeListener(this);
+ m_xBroadCaster = nullptr;
+ m_pDefinition = nullptr;
+ }
+
+ void SAL_CALL OEmbedObjectHolder::changingState( const lang::EventObject& /*aEvent*/, ::sal_Int32 /*nOldState*/, ::sal_Int32 /*nNewState*/ )
+ {
+ }
+
+ void SAL_CALL OEmbedObjectHolder::stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState )
+ {
+ if ( !m_bInStateChange && nNewState == EmbedStates::RUNNING && nOldState == EmbedStates::ACTIVE && m_pDefinition )
+ {
+ m_bInStateChange = true;
+ Reference<XInterface> xHoldAlive(static_cast< ::cppu::OWeakObject* >(m_pDefinition),UNO_QUERY);
+ {
+ Reference<XEmbeddedObject> xEmbeddedObject(aEvent.Source,UNO_QUERY);
+ if ( xEmbeddedObject.is() )
+ xEmbeddedObject->changeState(EmbedStates::LOADED);
+ }
+ m_bInStateChange = false;
+ }
+ }
+
+ void SAL_CALL OEmbedObjectHolder::disposing( const lang::EventObject& /*Source*/ )
+ {
+ m_xBroadCaster = nullptr;
+ }
+
+ // OEmbeddedClientHelper
+ class OEmbeddedClientHelper : public ::cppu::WeakImplHelper<XEmbeddedClient>
+ {
+ public:
+ virtual void SAL_CALL saveObject( ) override
+ {
+ }
+ // XComponentSupplier
+ virtual Reference< util::XCloseable > SAL_CALL getComponent( ) override
+ {
+ return Reference< css::util::XCloseable >();
+ }
+
+ // XEmbeddedClient
+ virtual void SAL_CALL visibilityChanged( sal_Bool /*bVisible*/ ) override
+ {
+ }
+ };
+
+ namespace {
+
+ // LockModifiable
+ class LockModifiable
+ {
+ public:
+ explicit LockModifiable( const Reference< XInterface >& i_rModifiable )
+ :m_xModifiable( i_rModifiable, UNO_QUERY )
+ {
+ OSL_ENSURE( m_xModifiable.is(), "LockModifiable::LockModifiable: invalid component!" );
+ if ( m_xModifiable.is() )
+ {
+ if ( !m_xModifiable->isSetModifiedEnabled() )
+ {
+ // somebody already locked that, no need to lock it, again, and no need to unlock it later
+ m_xModifiable.clear();
+ }
+ else
+ {
+ m_xModifiable->disableSetModified();
+ }
+ }
+ }
+
+ ~LockModifiable()
+ {
+ if ( m_xModifiable.is() )
+ m_xModifiable->enableSetModified();
+ }
+
+ private:
+ Reference< XModifiable2 > m_xModifiable;
+ };
+
+ }
+
+ // LifetimeCoupler
+ typedef ::cppu::WeakImplHelper< css::lang::XEventListener
+ > LifetimeCoupler_Base;
+
+ namespace {
+
+ /** helper class which couples the lifetime of a component to the lifetime
+ of another component
+
+ Instances of this class are constructed with two components. The first is
+ simply held by reference, and thus kept alive. The second one is observed
+ for <code>disposing</code> calls - if they occur, i.e. if the component dies,
+ the reference to the first component is cleared.
+
+ This way, you can ensure that a certain component is kept alive as long
+ as a second component is not disposed.
+ */
+ class LifetimeCoupler : public LifetimeCoupler_Base
+ {
+ private:
+ Reference< XInterface > m_xClient;
+
+ public:
+ static void couple( const Reference< XInterface >& _rxClient, const Reference< XComponent >& _rxActor )
+ {
+ new LifetimeCoupler( _rxClient, _rxActor );
+ }
+
+ private:
+ LifetimeCoupler( const Reference< XInterface >& _rxClient, const Reference< XComponent >& _rxActor )
+ :m_xClient( _rxClient )
+ {
+ OSL_ENSURE( _rxActor.is(), "LifetimeCoupler::LifetimeCoupler: this will crash!" );
+ osl_atomic_increment( &m_refCount );
+ {
+ _rxActor->addEventListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ OSL_ENSURE( m_refCount, "LifetimeCoupler::LifetimeCoupler: the actor is not holding us by hard ref - this won't work!" );
+ }
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ protected:
+ };
+
+ }
+
+ void SAL_CALL LifetimeCoupler::disposing( const css::lang::EventObject& /*Source*/ )
+ {
+ m_xClient.clear();
+ }
+
+ namespace {
+
+ // ODocumentSaveContinuation
+ class ODocumentSaveContinuation : public OInteraction< XInteractionDocumentSave >
+ {
+ OUString m_sName;
+ Reference<XContent> m_xParentContainer;
+
+ public:
+ ODocumentSaveContinuation() { }
+
+ const Reference<XContent>& getContent() const { return m_xParentContainer; }
+ const OUString& getName() const { return m_sName; }
+
+ // XInteractionDocumentSave
+ virtual void SAL_CALL setName( const OUString& _sName,const Reference<XContent>& _xParent) override;
+ };
+
+ }
+
+ void SAL_CALL ODocumentSaveContinuation::setName( const OUString& _sName,const Reference<XContent>& _xParent)
+ {
+ m_sName = _sName;
+ m_xParentContainer = _xParent;
+ }
+
+OUString ODocumentDefinition::GetDocumentServiceFromMediaType( const Reference< XStorage >& _rxContainerStorage,
+ const OUString& _rEntityName, const Reference< XComponentContext >& _rContext,
+ Sequence< sal_Int8 >& _rClassId )
+{
+ return GetDocumentServiceFromMediaType(
+ lcl_determineContentType_nothrow( _rxContainerStorage, _rEntityName ),
+ _rContext, _rClassId );
+}
+
+OUString ODocumentDefinition::GetDocumentServiceFromMediaType( const OUString& _rMediaType,
+ const Reference< XComponentContext >& _rContext, Sequence< sal_Int8 >& _rClassId )
+{
+ OUString sResult;
+ try
+ {
+ ::comphelper::MimeConfigurationHelper aConfigHelper( _rContext );
+ sResult = aConfigHelper.GetDocServiceNameFromMediaType( _rMediaType );
+ _rClassId = comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation(aConfigHelper.GetExplicitlyRegisteredObjClassID( _rMediaType ));
+ if ( !_rClassId.hasElements() && !sResult.isEmpty() )
+ {
+ Reference< XNameAccess > xObjConfig = aConfigHelper.GetObjConfiguration();
+ if ( xObjConfig.is() )
+ {
+ const Sequence< OUString > aClassIDs = xObjConfig->getElementNames();
+ for ( OUString const & classId : aClassIDs )
+ {
+ Reference< XNameAccess > xObjectProps;
+ OUString aEntryDocName;
+
+ if ( ( xObjConfig->getByName( classId ) >>= xObjectProps ) && xObjectProps.is()
+ && ( xObjectProps->getByName("ObjectDocumentServiceName") >>= aEntryDocName )
+ && aEntryDocName == sResult )
+ {
+ _rClassId = comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation(classId);
+ break;
+ }
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 0
+ // alternative, shorter approach
+ const Sequence< NamedValue > aProps( aConfigHelper.GetObjectPropsByMediaType( _rMediaType ) );
+ const ::comphelper::NamedValueCollection aMediaTypeProps( aProps );
+ const OUString sAlternativeResult = aMediaTypeProps.getOrDefault( "ObjectDocumentServiceName", OUString() );
+ OSL_ENSURE( sAlternativeResult == sResult, "ODocumentDefinition::GetDocumentServiceFromMediaType: failed, this approach is *not* equivalent (1)!" );
+ const Sequence< sal_Int8 > aAlternativeClassID = aMediaTypeProps.getOrDefault( "ClassID", Sequence< sal_Int8 >() );
+ OSL_ENSURE( aAlternativeClassID == _rClassId, "ODocumentDefinition::GetDocumentServiceFromMediaType: failed, this approach is *not* equivalent (2)!" );
+#endif
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sResult;
+}
+
+// ODocumentDefinition
+
+ODocumentDefinition::ODocumentDefinition( const Reference< XInterface >& _rxContainer, const Reference< XComponentContext >& _xORB,
+ const TContentPtr& _pImpl, bool _bForm )
+ :OContentHelper(_xORB,_rxContainer,_pImpl)
+ ,OPropertyStateContainer(OContentHelper::rBHelper)
+ ,m_bForm(_bForm)
+ ,m_bOpenInDesign(false)
+ ,m_bInExecute(false)
+ ,m_bRemoveListener(false)
+{
+ registerProperties();
+}
+
+void ODocumentDefinition::initialLoad( const Sequence< sal_Int8 >& i_rClassID, const Sequence< PropertyValue >& i_rCreationArgs,
+ const Reference< XConnection >& i_rConnection )
+{
+ OSL_ENSURE( i_rClassID.hasElements(), "ODocumentDefinition::initialLoad: illegal class ID!" );
+ if ( !i_rClassID.hasElements() )
+ return;
+
+ loadEmbeddedObject( i_rConnection, i_rClassID, i_rCreationArgs, false, false );
+}
+
+ODocumentDefinition::~ODocumentDefinition()
+{
+ if ( !OContentHelper::rBHelper.bInDispose && !OContentHelper::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+
+ if ( m_pInterceptor.is() )
+ {
+ m_pInterceptor->dispose();
+ m_pInterceptor.clear();
+ }
+}
+
+void ODocumentDefinition::closeObject()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( m_xEmbeddedObject.is() )
+ {
+ try
+ {
+ m_xEmbeddedObject->close(true);
+ }
+ catch(const Exception&)
+ {
+ }
+ m_xEmbeddedObject = nullptr;
+ m_pClientHelper.clear();
+ }
+}
+
+void SAL_CALL ODocumentDefinition::disposing()
+{
+ OContentHelper::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ closeObject();
+ ::comphelper::disposeComponent(m_xListener);
+ if ( m_bRemoveListener )
+ {
+ Reference<util::XCloseable> xCloseable(m_pImpl->m_pDataSource->getModel_noCreate(),UNO_QUERY);
+ if ( xCloseable.is() )
+ xCloseable->removeCloseListener(this);
+ }
+}
+
+css::uno::Sequence<sal_Int8> ODocumentDefinition::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > ODocumentDefinition::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OContentHelper::getTypes( ),
+ OPropertyStateContainer::getTypes( ),
+ ODocumentDefinition_Base::getTypes( )
+ );
+}
+IMPLEMENT_FORWARD_XINTERFACE3( ODocumentDefinition,OContentHelper,OPropertyStateContainer,ODocumentDefinition_Base)
+
+void ODocumentDefinition::registerProperties()
+{
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::CONSTRAINED | PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ &m_pImpl->m_aProps.aTitle, cppu::UnoType<decltype(m_pImpl->m_aProps.aTitle)>::get());
+
+ registerProperty(PROPERTY_AS_TEMPLATE, PROPERTY_ID_AS_TEMPLATE, PropertyAttribute::READONLY, &m_pImpl->m_aProps.bAsTemplate,
+ cppu::UnoType<decltype(m_pImpl->m_aProps.bAsTemplate)>::get());
+
+ registerProperty(PROPERTY_PERSISTENT_NAME, PROPERTY_ID_PERSISTENT_NAME, PropertyAttribute::READONLY, &m_pImpl->m_aProps.sPersistentName,
+ cppu::UnoType<decltype(m_pImpl->m_aProps.sPersistentName)>::get());
+
+ registerProperty(PROPERTY_IS_FORM, PROPERTY_ID_IS_FORM, PropertyAttribute::READONLY, &m_bForm, cppu::UnoType<decltype(m_bForm)>::get());
+}
+
+void SAL_CALL ODocumentDefinition::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const
+{
+ if ( i_nHandle == PROPERTY_ID_PERSISTENT_PATH )
+ {
+ OUString sPersistentPath;
+ if ( !m_pImpl->m_aProps.sPersistentName.isEmpty() )
+ {
+ sPersistentPath = ODatabaseModelImpl::getObjectContainerStorageName( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT )
+ + "/" + m_pImpl->m_aProps.sPersistentName;
+ }
+ o_rValue <<= sPersistentPath;
+ return;
+ }
+
+ OPropertyStateContainer::getFastPropertyValue( o_rValue, i_nHandle );
+}
+
+Reference< XPropertySetInfo > SAL_CALL ODocumentDefinition::getPropertySetInfo( )
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+IPropertyArrayHelper& ODocumentDefinition::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+IPropertyArrayHelper* ODocumentDefinition::createArrayHelper( ) const
+{
+ // properties maintained by our base class (see registerProperties)
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+
+ // properties not maintained by our base class
+ Sequence< Property > aManualProps{ { /* Name */ PROPERTY_PERSISTENT_PATH,
+ /* Handle */ PROPERTY_ID_PERSISTENT_PATH,
+ /* Type */ ::cppu::UnoType<OUString>::get(),
+ /* Attributes */ PropertyAttribute::READONLY } };
+
+ return new OPropertyArrayHelper( ::comphelper::concatSequences( aProps, aManualProps ) );
+}
+
+namespace {
+
+class OExecuteImpl
+{
+ bool& m_rbSet;
+public:
+ explicit OExecuteImpl(bool& _rbSet) : m_rbSet(_rbSet){ m_rbSet=true; }
+ ~OExecuteImpl(){ m_rbSet = false; }
+};
+
+ bool lcl_extractOpenMode( const Any& _rValue, sal_Int32& _out_rMode )
+ {
+ OpenCommandArgument aOpenCommand;
+ if ( _rValue >>= aOpenCommand )
+ _out_rMode = aOpenCommand.Mode;
+ else
+ {
+ OpenCommandArgument2 aOpenCommand2;
+ if ( _rValue >>= aOpenCommand2 )
+ _out_rMode = aOpenCommand2.Mode;
+ else
+ return false;
+ }
+ return true;
+ }
+}
+
+void ODocumentDefinition::impl_removeFrameFromDesktop_throw( const Reference<XComponentContext> & _rxContext, const Reference< XFrame >& _rxFrame )
+{
+ Reference< XDesktop2 > xDesktop = Desktop::create( _rxContext );
+ Reference< XFrames > xFrames( xDesktop->getFrames(), UNO_SET_THROW );
+ xFrames->remove( _rxFrame );
+}
+
+void ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated )
+{
+ try
+ {
+ Reference< XModel > xModel( getComponent(), UNO_QUERY );
+ Reference< XController > xController( xModel.is() ? xModel->getCurrentController() : Reference< XController >() );
+ if ( !xController.is() )
+ return;
+
+ if ( !m_xListener.is() )
+ // it's the first time the embedded object has been activated
+ // create an OEmbedObjectHolder
+ m_xListener = new OEmbedObjectHolder( m_xEmbeddedObject, this );
+
+ // raise the window to top (especially necessary if this is not the first activation)
+ Reference< XFrame > xFrame( xController->getFrame(), UNO_SET_THROW );
+ Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW );
+ xTopWindow->toFront();
+
+ // remove the frame from the desktop's frame collection because we need full control of it.
+ impl_removeFrameFromDesktop_throw( m_aContext, xFrame );
+
+ // ensure that we ourself are kept alive as long as the embedded object's frame is
+ // opened
+ LifetimeCoupler::couple( *this, xFrame );
+
+ // init the edit view
+ if ( m_bForm && m_bOpenInDesign && !i_bReactivated )
+ impl_initFormEditView( xController );
+ }
+ catch( const RuntimeException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+namespace
+{
+ // PreserveVisualAreaSize
+ /** stack-guard for preserving the size of the VisArea of an XModel
+ */
+ class PreserveVisualAreaSize
+ {
+ private:
+ Reference< XVisualObject > m_xVisObject;
+ awt::Size m_aOriginalSize;
+
+ public:
+ explicit PreserveVisualAreaSize( const Reference< XModel >& _rxModel )
+ :m_xVisObject( _rxModel, UNO_QUERY )
+ {
+ if ( m_xVisObject.is() )
+ {
+ try
+ {
+ m_aOriginalSize = m_xVisObject->getVisualAreaSize( Aspects::MSOLE_CONTENT );
+ }
+ catch ( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "PreserveVisualAreaSize::PreserveVisualAreaSize" );
+ }
+ }
+ }
+
+ ~PreserveVisualAreaSize()
+ {
+ if ( m_xVisObject.is() && m_aOriginalSize.Width && m_aOriginalSize.Height )
+ {
+ try
+ {
+ m_xVisObject->setVisualAreaSize( Aspects::MSOLE_CONTENT, m_aOriginalSize );
+ }
+ catch ( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "PreserveVisualAreaSize::~PreserveVisualAreaSize" );
+ }
+ }
+ }
+ };
+
+ // LayoutManagerLock
+ /** helper class for stack-usage which during its lifetime locks a layout manager
+ */
+ class LayoutManagerLock
+ {
+ private:
+ Reference< XLayoutManager > m_xLayoutManager;
+
+ public:
+ explicit LayoutManagerLock( const Reference< XController >& _rxController )
+ {
+ OSL_ENSURE( _rxController.is(), "LayoutManagerLock::LayoutManagerLock: this will crash!" );
+ Reference< XFrame > xFrame( _rxController->getFrame() );
+ try
+ {
+ Reference< XPropertySet > xPropSet( xFrame, UNO_QUERY_THROW );
+ m_xLayoutManager.set(
+ xPropSet->getPropertyValue( "LayoutManager" ),
+ UNO_QUERY_THROW );
+ m_xLayoutManager->lock();
+
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "LayoutManagerLock::LayoutManagerLock" );
+ }
+ }
+
+ ~LayoutManagerLock()
+ {
+ try
+ {
+ // unlock the layout manager
+ if ( m_xLayoutManager.is() )
+ m_xLayoutManager->unlock();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "LayoutManagerLock::~LayoutManagerLock" );
+ }
+ }
+ };
+}
+
+void ODocumentDefinition::impl_initFormEditView( const Reference< XController >& _rxController )
+{
+ try
+ {
+ Reference< XViewSettingsSupplier > xSettingsSupplier( _rxController, UNO_QUERY_THROW );
+ Reference< XPropertySet > xViewSettings( xSettingsSupplier->getViewSettings(), UNO_SET_THROW );
+
+ // the below code could indirectly tamper with the "modified" flag of the model, temporarily disable this
+ LockModifiable aLockModify( _rxController->getModel() );
+
+ // The visual area size can be changed by the setting of the following properties
+ // so it should be restored later
+ PreserveVisualAreaSize aPreserveVisAreaSize( _rxController->getModel() );
+
+ // Layout manager should not layout while the size is still not restored
+ // so it will stay locked for this time
+ LayoutManagerLock aLockLayout( _rxController );
+
+ // setting of the visual properties
+ xViewSettings->setPropertyValue("ShowRulers",Any(true));
+ xViewSettings->setPropertyValue("ShowVertRuler",Any(true));
+ xViewSettings->setPropertyValue("ShowHoriRuler",Any(true));
+ xViewSettings->setPropertyValue("IsRasterVisible",Any(true));
+ xViewSettings->setPropertyValue("IsSnapToRaster",Any(true));
+ xViewSettings->setPropertyValue("ShowOnlineLayout",Any(true));
+ xViewSettings->setPropertyValue("RasterSubdivisionX",Any(sal_Int32(5)));
+ xViewSettings->setPropertyValue("RasterSubdivisionY",Any(sal_Int32(5)));
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODocumentDefinition::impl_showOrHideComponent_throw( const bool i_bShow )
+{
+ const sal_Int32 nCurrentState = m_xEmbeddedObject.is() ? m_xEmbeddedObject->getCurrentState() : EmbedStates::LOADED;
+ switch ( nCurrentState )
+ {
+ default:
+ case EmbedStates::LOADED:
+ throw embed::WrongStateException( OUString(), *this );
+
+ case EmbedStates::RUNNING:
+ if ( !i_bShow )
+ // fine, a running (and not yet active) object is never visible
+ return;
+ {
+ LockModifiable aLockModify( impl_getComponent_throw() );
+ m_xEmbeddedObject->changeState( EmbedStates::ACTIVE );
+ impl_onActivateEmbeddedObject_nothrow( false );
+ }
+ break;
+
+ case EmbedStates::ACTIVE:
+ {
+ Reference< XModel > xEmbeddedDoc( impl_getComponent_throw(), UNO_QUERY_THROW );
+ Reference< XController > xEmbeddedController( xEmbeddedDoc->getCurrentController(), UNO_SET_THROW );
+ Reference< XFrame > xEmbeddedFrame( xEmbeddedController->getFrame(), UNO_SET_THROW );
+ Reference< XWindow > xEmbeddedWindow( xEmbeddedFrame->getContainerWindow(), UNO_SET_THROW );
+ xEmbeddedWindow->setVisible( i_bShow );
+ }
+ break;
+ }
+}
+
+Any ODocumentDefinition::onCommandOpenSomething( const Any& _rOpenArgument, const bool _bActivate,
+ const Reference< XCommandEnvironment >& _rxEnvironment )
+{
+ OExecuteImpl aExecuteGuard( m_bInExecute );
+
+ Reference< XConnection > xConnection;
+ sal_Int32 nOpenMode = OpenMode::DOCUMENT;
+
+ ::comphelper::NamedValueCollection aDocumentArgs;
+
+ // for the document, default to the interaction handler as used for loading the DB doc
+ // This might be overwritten below, when examining _rOpenArgument.
+ const ::comphelper::NamedValueCollection& aDBDocArgs( m_pImpl->m_pDataSource->getMediaDescriptor() );
+ Reference< XInteractionHandler > xHandler( aDBDocArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) );
+ if ( xHandler.is() )
+ aDocumentArgs.put( "InteractionHandler", xHandler );
+
+ ::std::optional< sal_Int16 > aDocumentMacroMode;
+
+ if ( !lcl_extractOpenMode( _rOpenArgument, nOpenMode ) )
+ {
+ Sequence< PropertyValue > aArguments;
+ if ( _rOpenArgument >>= aArguments )
+ {
+ const PropertyValue* pIter = aArguments.getConstArray();
+ const PropertyValue* pEnd = pIter + aArguments.getLength();
+ for ( ;pIter != pEnd; ++pIter )
+ {
+ if ( pIter->Name == PROPERTY_ACTIVE_CONNECTION )
+ {
+ xConnection.set( pIter->Value, UNO_QUERY );
+ continue;
+ }
+
+ if ( lcl_extractOpenMode( pIter->Value, nOpenMode ) )
+ continue;
+
+ if ( pIter->Name == "MacroExecutionMode" )
+ {
+ sal_Int16 nMacroExecMode( !aDocumentMacroMode ? MacroExecMode::USE_CONFIG : *aDocumentMacroMode );
+ OSL_VERIFY( pIter->Value >>= nMacroExecMode );
+ aDocumentMacroMode = nMacroExecMode;
+ continue;
+ }
+
+ // unknown argument -> pass to the loaded document
+ aDocumentArgs.put( pIter->Name, pIter->Value );
+ }
+ }
+ }
+
+ bool bExecuteDBDocMacros = m_pImpl->m_pDataSource->checkMacrosOnLoading();
+ // Note that this call implies the user might be asked for the macro execution mode.
+ // Normally, this would happen when the database document is loaded, and subsequent calls
+ // will simply use the user's decision from this point in time.
+ // However, it is possible to programmatically load forms/reports, without actually
+ // loading the database document into a frame. In this case, the user will be asked
+ // here and now.
+ // #i87741#
+
+ // allow the command arguments to downgrade the macro execution mode, but not to upgrade
+ // it
+ if ( ( m_pImpl->m_pDataSource->getImposedMacroExecMode() == MacroExecMode::USE_CONFIG )
+ && bExecuteDBDocMacros
+ )
+ {
+ // while loading the whole database document, USE_CONFIG, was passed.
+ // Additionally, *by now* executing macros from the DB doc is allowed (this is what bExecuteDBDocMacros
+ // indicates). This means either one of:
+ // 1. The DB doc or one of the sub docs contained macros and
+ // 1a. the user explicitly allowed executing them
+ // 1b. the configuration allows executing them without asking the user
+ // 2. Neither the DB doc nor the sub docs contained macros, thus macro
+ // execution was silently enabled, assuming that any macro will be a
+ // user-created macro
+ //
+ // The problem with this: If the to-be-opened sub document has macros embedded in
+ // the content.xml (which is valid ODF, but normally not produced by OOo itself),
+ // then this has not been detected while loading the database document - it would
+ // be too expensive, as it effectively would require loading all forms/reports.
+ //
+ // So, in such a case, and with 2. above, we would silently execute those macros,
+ // regardless of the global security settings - which would be a security issue, of
+ // course.
+ if ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eNoMacros )
+ {
+ // this is case 2. from above
+ // So, pass a USE_CONFIG to the to-be-loaded document. This means that
+ // the user will be prompted with a security message upon opening this
+ // sub document, in case the settings require this, *and* the document
+ // contains scripts in the content.xml. But this is better than the security
+ // issue we had before ...
+ aDocumentMacroMode = MacroExecMode::USE_CONFIG;
+ }
+ }
+
+ if ( !aDocumentMacroMode )
+ {
+ // nobody so far felt responsible for setting it
+ // => use the DBDoc-wide macro exec mode for the document, too
+ aDocumentMacroMode = bExecuteDBDocMacros ? MacroExecMode::ALWAYS_EXECUTE_NO_WARN
+ : MacroExecMode::NEVER_EXECUTE;
+ }
+ aDocumentArgs.put( "MacroExecutionMode", *aDocumentMacroMode );
+
+ if ( ( nOpenMode == OpenMode::ALL )
+ || ( nOpenMode == OpenMode::FOLDERS )
+ || ( nOpenMode == OpenMode::DOCUMENTS )
+ || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_NONE )
+ || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_WRITE )
+ )
+ {
+ // not supported
+ ucbhelper::cancelCommandExecution(
+ Any( UnsupportedOpenModeException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ sal_Int16( nOpenMode ) ) ),
+ _rxEnvironment );
+ // Unreachable
+ OSL_FAIL( "unreachable" );
+ }
+
+ OSL_ENSURE( !m_pImpl->m_aProps.sPersistentName.isEmpty(),
+ "ODocumentDefinition::onCommandOpenSomething: no persistent name - cannot load!" );
+ if ( m_pImpl->m_aProps.sPersistentName.isEmpty() )
+ return Any();
+
+ // embedded objects themself do not support the hidden flag. We implement support for
+ // it by changing the STATE to RUNNING only, instead of ACTIVE.
+ bool bOpenHidden = aDocumentArgs.getOrDefault( "Hidden", false );
+ aDocumentArgs.remove( "Hidden" );
+
+ loadEmbeddedObject( xConnection, Sequence< sal_Int8 >(), aDocumentArgs.getPropertyValues(), false, !m_bOpenInDesign );
+ OSL_ENSURE( m_xEmbeddedObject.is(), "ODocumentDefinition::onCommandOpenSomething: what's this?" );
+ if ( !m_xEmbeddedObject.is() )
+ return Any();
+
+ Reference< XModel > xModel( getComponent(), UNO_QUERY );
+ Reference< report::XReportDefinition > xReportDefinition(xModel,UNO_QUERY);
+
+ Reference< XModule > xModule( xModel, UNO_QUERY );
+ if ( xModule.is() )
+ {
+ if ( m_bForm )
+ xModule->setIdentifier( "com.sun.star.sdb.FormDesign" );
+ else if ( !xReportDefinition.is() )
+ xModule->setIdentifier( "com.sun.star.text.TextDocument" );
+
+ updateDocumentTitle();
+ }
+
+ bool bIsAliveNewStyleReport = ( !m_bOpenInDesign && xReportDefinition.is() );
+ if ( bIsAliveNewStyleReport )
+ {
+ // we are in ReadOnly mode
+ // we would like to open the Writer or Calc with the report direct, without design it.
+ Reference< report::XReportEngine > xReportEngine( m_aContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.report.OReportEngineJFree", m_aContext), UNO_QUERY_THROW );
+
+ xReportEngine->setReportDefinition(xReportDefinition);
+ xReportEngine->setActiveConnection(m_xLastKnownConnection);
+ if ( bOpenHidden )
+ return Any( xReportEngine->createDocumentModel() );
+ return Any( xReportEngine->createDocumentAlive( nullptr ) );
+ }
+
+ if ( _bActivate && !bOpenHidden )
+ {
+ LockModifiable aLockModify( impl_getComponent_throw() );
+ m_xEmbeddedObject->changeState( EmbedStates::ACTIVE );
+ impl_onActivateEmbeddedObject_nothrow( false );
+ }
+ else
+ {
+ // ensure that we ourself are kept alive as long as the document is open
+ LifetimeCoupler::couple( *this, xModel );
+ }
+
+ if ( !m_bForm && m_pImpl->m_aProps.bAsTemplate && !m_bOpenInDesign )
+ ODocumentDefinition::fillReportData( m_aContext, getComponent(), xConnection );
+
+ return Any( xModel );
+}
+
+Any SAL_CALL ODocumentDefinition::execute( const Command& aCommand, sal_Int32 CommandId, const Reference< XCommandEnvironment >& Environment )
+{
+ Any aRet;
+
+ bool bOpen = aCommand.Name == "open";
+ bool bOpenInDesign = aCommand.Name == "openDesign";
+ bool bOpenForMail = aCommand.Name == "openForMail";
+ if ( bOpen || bOpenInDesign || bOpenForMail )
+ {
+ // opening the document involves a lot of VCL code, which is not thread-safe, but needs the SolarMutex locked.
+ // Unfortunately, the DocumentDefinition, as well as the EmbeddedObject implementation, calls into VCL-dependent
+ // components *without* releasing the own mutex, which is a guaranteed recipe for deadlocks.
+ // We have control over this implementation here, and in modifying it to release the own mutex before calling into
+ // the VCL-dependent components is not too difficult (was there, seen it).
+ // However, we do /not/ have control over the EmbeddedObject implementation, and from a first look, it seems as
+ // making it release the own mutex before calling SolarMutex-code is ... difficult, at least.
+ // So, to be on the same side, we lock the SolarMutex here. Yes, it sucks.
+ ::SolarMutexGuard aSolarGuard;
+ osl::MutexGuard aGuard(m_aMutex);
+ if ( m_bInExecute )
+ return aRet;
+
+ bool bActivateObject = true;
+ if ( bOpenForMail )
+ {
+ OSL_FAIL( "ODocumentDefinition::execute: 'openForMail' should not be used anymore - use the 'Hidden' parameter instead!" );
+ bActivateObject = false;
+ }
+
+ // if the object is already opened, do nothing
+ if ( m_xEmbeddedObject.is() )
+ {
+ sal_Int32 nCurrentState = m_xEmbeddedObject->getCurrentState();
+ bool bIsActive = ( nCurrentState == EmbedStates::ACTIVE );
+
+ if ( bIsActive )
+ {
+ // exception: new-style reports always create a new document when "open" is executed
+ Reference< report::XReportDefinition > xReportDefinition( impl_getComponent_throw( false ), UNO_QUERY );
+ bool bIsAliveNewStyleReport = ( xReportDefinition.is() && ( bOpen || bOpenForMail ) );
+
+ if ( !bIsAliveNewStyleReport )
+ {
+ impl_onActivateEmbeddedObject_nothrow( true );
+ return Any( getComponent() );
+ }
+ }
+ }
+
+ m_bOpenInDesign = bOpenInDesign || bOpenForMail;
+ return onCommandOpenSomething( aCommand.Argument, bActivateObject, Environment );
+ }
+
+ osl::MutexGuard aGuard(m_aMutex);
+ if ( m_bInExecute )
+ return aRet;
+
+ if ( aCommand.Name == "copyTo" )
+ {
+ Sequence<Any> aIni;
+ aCommand.Argument >>= aIni;
+ if ( aIni.getLength() != 2 )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ Reference< XStorage> xDest(aIni[0],UNO_QUERY);
+ OUString sPersistentName;
+ aIni[1] >>= sPersistentName;
+ Reference< XStorage> xStorage = getContainerStorage();
+
+ xStorage->copyElementTo(m_pImpl->m_aProps.sPersistentName,xDest,sPersistentName);
+ }
+ else if ( aCommand.Name == "preview" )
+ {
+ onCommandPreview(aRet);
+ }
+ else if ( aCommand.Name == "insert" )
+ {
+ Sequence<Any> aIni;
+ aCommand.Argument >>= aIni;
+ if ( !aIni.hasElements() )
+ {
+ OSL_FAIL( "Wrong argument count!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ OUString sURL;
+ aIni[0] >>= sURL;
+ onCommandInsert( sURL, Environment );
+ }
+ else if ( aCommand.Name == "getdocumentinfo" // compatibility
+ || aCommand.Name == "getDocumentInfo" )
+ {
+ onCommandGetDocumentProperties( aRet );
+ }
+ else if ( aCommand.Name == "delete" )
+ {
+ // delete
+ closeObject();
+ Reference< XStorage> xStorage = getContainerStorage();
+ if ( xStorage.is() )
+ xStorage->removeElement(m_pImpl->m_aProps.sPersistentName);
+
+ dispose();
+
+ }
+ else if ( aCommand.Name == "storeOwn" // compatibility
+ || aCommand.Name == "store"
+ )
+ {
+ impl_store_throw();
+ }
+ else if ( aCommand.Name == "shutdown" // compatibility
+ || aCommand.Name == "close"
+ )
+ {
+ aRet <<= impl_close_throw();
+ }
+ else if ( aCommand.Name == "show" )
+ {
+ impl_showOrHideComponent_throw( true );
+ }
+ else if ( aCommand.Name == "hide" )
+ {
+ impl_showOrHideComponent_throw( false );
+ }
+ else
+ {
+ aRet = OContentHelper::execute(aCommand,CommandId,Environment);
+ }
+
+ return aRet;
+}
+
+namespace
+{
+ void lcl_resetChildFormsToEmptyDataSource( const Reference< XIndexAccess>& _rxFormsContainer )
+ {
+ OSL_PRECOND( _rxFormsContainer.is(), "lcl_resetChildFormsToEmptyDataSource: illegal call!" );
+ sal_Int32 count = _rxFormsContainer->getCount();
+ for ( sal_Int32 i = 0; i < count; ++i )
+ {
+ Reference< XForm > xForm( _rxFormsContainer->getByIndex( i ), UNO_QUERY );
+ if ( !xForm.is() )
+ continue;
+
+ // if the element is a form, reset its DataSourceName property to an empty string
+ try
+ {
+ Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW );
+ xFormProps->setPropertyValue( PROPERTY_DATASOURCENAME, Any( OUString() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // if the element is a container itself, step down the component hierarchy
+ Reference< XIndexAccess > xContainer( xForm, UNO_QUERY );
+ if ( xContainer.is() )
+ lcl_resetChildFormsToEmptyDataSource( xContainer );
+ }
+ }
+
+ void lcl_resetFormsToEmptyDataSource( const Reference< XEmbeddedObject>& _rxEmbeddedObject )
+ {
+ try
+ {
+ Reference< XDrawPageSupplier > xSuppPage( _rxEmbeddedObject->getComponent(), UNO_QUERY_THROW );
+ // if this interface does not exist, then either getComponent returned NULL,
+ // or the document is a multi-page document. The latter is allowed, but currently
+ // simply not handled by this code, as it would not normally happen.
+
+ Reference< XFormsSupplier > xSuppForms( xSuppPage->getDrawPage(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xForms( xSuppForms->getForms(), UNO_QUERY_THROW );
+ lcl_resetChildFormsToEmptyDataSource( xForms );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ }
+}
+
+void ODocumentDefinition::onCommandInsert( const OUString& _sURL, const Reference< XCommandEnvironment >& Environment )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
+
+ // Check, if all required properties were set.
+ if ( _sURL.isEmpty() || m_xEmbeddedObject.is() )
+ {
+ OSL_FAIL( "Content::onCommandInsert - property value missing!" );
+
+ Sequence<OUString> aProps { PROPERTY_URL };
+ ucbhelper::cancelCommandExecution(
+ Any( MissingPropertiesException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ aProps ) ),
+ Environment );
+ // Unreachable
+ }
+
+ if ( !m_xEmbeddedObject.is() )
+ {
+ Reference< XStorage> xStorage = getContainerStorage();
+ if ( xStorage.is() )
+ {
+ Reference< XEmbeddedObjectCreator> xEmbedFactory = EmbeddedObjectCreator::create(m_aContext);
+ Sequence<PropertyValue> aEmpty;
+ Sequence<PropertyValue> aMediaDesc{ comphelper::makePropertyValue(PROPERTY_URL,
+ _sURL) };
+ m_xEmbeddedObject.set(xEmbedFactory->createInstanceInitFromMediaDescriptor( xStorage
+ ,m_pImpl->m_aProps.sPersistentName
+ ,aMediaDesc
+ ,aEmpty),UNO_QUERY);
+
+ lcl_resetFormsToEmptyDataSource( m_xEmbeddedObject );
+ // #i57669#
+
+ Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY);
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ }
+ try
+ {
+ if ( m_xEmbeddedObject.is() )
+ m_xEmbeddedObject->close(true);
+ }
+ catch(const Exception&)
+ {
+ }
+ m_xEmbeddedObject = nullptr;
+ }
+ }
+
+ aGuard.clear();
+}
+
+bool ODocumentDefinition::save(bool _bApprove, const css::uno::Reference<css::awt::XTopWindow>& rDialogParent)
+{
+ // default handling: instantiate an interaction handler and let it handle the parameter request
+ if ( !m_bOpenInDesign )
+ return false;
+ try
+ {
+
+ {
+ ::SolarMutexGuard aSolarGuard;
+
+ // the request
+ Reference<XNameAccess> xName(m_xParentContainer,UNO_QUERY);
+ DocumentSaveRequest aRequest;
+ aRequest.Name = m_pImpl->m_aProps.aTitle;
+ if ( aRequest.Name.isEmpty() )
+ {
+ if ( m_bForm )
+ aRequest.Name = DBA_RES( RID_STR_FORM );
+ else
+ aRequest.Name = DBA_RES( RID_STR_REPORT );
+ aRequest.Name = ::dbtools::createUniqueName(xName,aRequest.Name);
+ }
+
+ aRequest.Content.set(m_xParentContainer,UNO_QUERY);
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ // two continuations allowed: OK and Cancel
+ rtl::Reference<ODocumentSaveContinuation> pDocuSave;
+
+ if ( m_pImpl->m_aProps.aTitle.isEmpty() )
+ {
+ pDocuSave = new ODocumentSaveContinuation;
+ pRequest->addContinuation(pDocuSave);
+ }
+ if ( _bApprove )
+ {
+ rtl::Reference<OInteraction< XInteractionApprove >> pApprove = new OInteraction< XInteractionApprove >;
+ pRequest->addContinuation(pApprove);
+ }
+
+ rtl::Reference<OInteraction< XInteractionDisapprove >> pDisApprove = new OInteraction< XInteractionDisapprove >;
+ pRequest->addContinuation(pDisApprove);
+
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ pRequest->addContinuation(pAbort);
+
+ Reference<XWindow> xDialogParent(rDialogParent, UNO_QUERY);
+
+ // create the handler, let it handle the request
+ Reference<XInteractionHandler2> xHandler(InteractionHandler::createWithParent(m_aContext, xDialogParent));
+ xHandler->handle(pRequest);
+
+ if ( pAbort->wasSelected() )
+ return false;
+ if ( pDisApprove->wasSelected() )
+ return true;
+ if ( pDocuSave && pDocuSave->wasSelected() )
+ {
+ Reference<XNameContainer> xNC( pDocuSave->getContent(), UNO_QUERY_THROW );
+
+ ::osl::ResettableMutexGuard aGuard( m_aMutex );
+ NameChangeNotifier aNameChangeAndNotify( *this, pDocuSave->getName(), aGuard );
+ m_pImpl->m_aProps.aTitle = pDocuSave->getName();
+
+ Reference< XContent> xContent = this;
+ xNC->insertByName(pDocuSave->getName(),Any(xContent));
+
+ updateDocumentTitle();
+ }
+ }
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY);
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ notifyDataSourceModified();
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "ODocumentDefinition::save: caught an Exception (tried to let the InteractionHandler handle it)!");
+ }
+ return true;
+}
+
+void ODocumentDefinition::saveAs()
+{
+ // default handling: instantiate an interaction handler and let it handle the parameter request
+ if ( !m_bOpenInDesign )
+ return;
+
+ {
+ osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
+ if ( m_pImpl->m_aProps.aTitle.isEmpty() )
+ {
+ aGuard.clear();
+ save(false, css::uno::Reference<css::awt::XTopWindow>()); // (sal_False) : we don't want an approve dialog
+ return;
+ }
+ }
+ try
+ {
+ ::SolarMutexGuard aSolarGuard;
+
+ // the request
+ DocumentSaveRequest aRequest;
+ aRequest.Name = m_pImpl->m_aProps.aTitle;
+
+ aRequest.Content.set(m_xParentContainer,UNO_QUERY);
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ // two continuations allowed: OK and Cancel
+ rtl::Reference<ODocumentSaveContinuation> pDocuSave = new ODocumentSaveContinuation;
+ pRequest->addContinuation(pDocuSave);
+ rtl::Reference<OInteraction< XInteractionDisapprove >> pDisApprove = new OInteraction< XInteractionDisapprove >;
+ pRequest->addContinuation(pDisApprove);
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ pRequest->addContinuation(pAbort);
+
+ // create the handler, let it handle the request
+ Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(m_aContext, nullptr) );
+ xHandler->handle(pRequest);
+
+ if ( pAbort->wasSelected() )
+ return;
+ if ( pDisApprove->wasSelected() )
+ return;
+ if ( pDocuSave->wasSelected() )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ Reference<XNameContainer> xNC(pDocuSave->getContent(),UNO_QUERY);
+ if ( xNC.is() )
+ {
+ if ( m_pImpl->m_aProps.aTitle != pDocuSave->getName() )
+ {
+ try
+ {
+ Reference< XStorage> xStorage = getContainerStorage();
+
+ OUString sPersistentName = ::dbtools::createUniqueName(xStorage,"Obj");
+ xStorage->copyElementTo(m_pImpl->m_aProps.sPersistentName,xStorage,sPersistentName);
+
+ OUString sOldName = m_pImpl->m_aProps.aTitle;
+ rename(pDocuSave->getName());
+ updateDocumentTitle();
+
+ uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {PROPERTY_NAME, uno::Any(sOldName)}, // set as folder
+ {PROPERTY_PERSISTENT_NAME, uno::Any(sPersistentName)},
+ {PROPERTY_AS_TEMPLATE, uno::Any(m_pImpl->m_aProps.bAsTemplate)},
+ }));
+ Reference< XMultiServiceFactory > xORB( m_xParentContainer, UNO_QUERY_THROW );
+ Reference< XInterface > xComponent( xORB->createInstanceWithArguments( SERVICE_SDB_DOCUMENTDEFINITION, aArguments ) );
+ Reference< XNameContainer > xNameContainer( m_xParentContainer, UNO_QUERY_THROW );
+ xNameContainer->insertByName( sOldName, Any( xComponent ) );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY);
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ notifyDataSourceModified();
+ }
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "ODocumentDefinition::save: caught an Exception (tried to let the InteractionHandler handle it)!");
+ }
+}
+
+namespace
+{
+ void lcl_putLoadArgs( ::comphelper::NamedValueCollection& _io_rArgs, const optional_bool& _bSuppressMacros, const optional_bool& _bReadOnly )
+ {
+ if ( !!_bSuppressMacros )
+ {
+ if ( *_bSuppressMacros )
+ {
+ // if we're to suppress macros, do exactly this
+ _io_rArgs.put( "MacroExecutionMode", MacroExecMode::NEVER_EXECUTE );
+ }
+ else
+ {
+ // otherwise, put the setting only if not already present
+ if ( !_io_rArgs.has( "MacroExecutionMode" ) )
+ {
+ _io_rArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
+ }
+ }
+ }
+
+ if ( !!_bReadOnly )
+ _io_rArgs.put( "ReadOnly", *_bReadOnly );
+ }
+}
+
+namespace
+{
+ Reference< XFrame > lcl_getDatabaseDocumentFrame( ODatabaseModelImpl const & _rImpl )
+ {
+ Reference< XModel > xDatabaseDocumentModel( _rImpl.getModel_noCreate() );
+
+ Reference< XController > xDatabaseDocumentController;
+ if ( xDatabaseDocumentModel.is() )
+ xDatabaseDocumentController = xDatabaseDocumentModel->getCurrentController();
+
+ Reference< XFrame > xFrame;
+ if ( xDatabaseDocumentController.is() )
+ xFrame = xDatabaseDocumentController->getFrame();
+
+ return xFrame;
+ }
+}
+
+bool ODocumentDefinition::objectSupportsEmbeddedScripts() const
+{
+ bool bAllowDocumentMacros = !m_pImpl->m_pDataSource
+ || ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eSubDocumentMacros );
+
+ // if *any* of the objects of the database document already has macros, we
+ // continue to allow it to have them, until the user does a migration.
+ // If there are no macros, we don't allow them to be created.
+
+ return bAllowDocumentMacros;
+}
+
+OUString ODocumentDefinition::determineContentType() const
+{
+ return lcl_determineContentType_nothrow( getContainerStorage(), m_pImpl->m_aProps.sPersistentName );
+}
+
+void ODocumentDefinition::separateOpenCommandArguments( const Sequence< PropertyValue >& i_rOpenCommandArguments,
+ ::comphelper::NamedValueCollection& o_rDocumentLoadArgs, ::comphelper::NamedValueCollection& o_rEmbeddedObjectDescriptor )
+{
+ ::comphelper::NamedValueCollection aOpenCommandArguments( i_rOpenCommandArguments );
+
+ static const std::u16string_view sObjectDescriptorArgs[] = { u"RecoveryStorage" };
+ for (const auto& rObjectDescriptorArg : sObjectDescriptorArgs)
+ {
+ const OUString sObjectDescriptorArg(rObjectDescriptorArg);
+ if ( aOpenCommandArguments.has( sObjectDescriptorArg ) )
+ {
+ o_rEmbeddedObjectDescriptor.put( sObjectDescriptorArg, aOpenCommandArguments.get( sObjectDescriptorArg ) );
+ aOpenCommandArguments.remove( sObjectDescriptorArg );
+ }
+ }
+
+ o_rDocumentLoadArgs.merge( aOpenCommandArguments, false );
+}
+
+Sequence< PropertyValue > ODocumentDefinition::fillLoadArgs( const Reference< XConnection>& _xConnection, const bool _bSuppressMacros, const bool _bReadOnly,
+ const Sequence< PropertyValue >& i_rOpenCommandArguments, Sequence< PropertyValue >& _out_rEmbeddedObjectDescriptor )
+{
+ // (re-)create interceptor, and put it into the descriptor of the embedded object
+ if ( m_pInterceptor.is() )
+ {
+ m_pInterceptor->dispose();
+ m_pInterceptor.clear();
+ }
+
+ m_pInterceptor = new OInterceptor( this );
+ Reference<XDispatchProviderInterceptor> xInterceptor = m_pInterceptor;
+
+ ::comphelper::NamedValueCollection aEmbeddedDescriptor;
+ aEmbeddedDescriptor.put( "OutplaceDispatchInterceptor", xInterceptor );
+
+ ::comphelper::NamedValueCollection aMediaDesc;
+ separateOpenCommandArguments( i_rOpenCommandArguments, aMediaDesc, aEmbeddedDescriptor );
+
+ // create the OutplaceFrameProperties, and put them into the descriptor of the embedded object
+ ::comphelper::NamedValueCollection OutplaceFrameProperties;
+ OutplaceFrameProperties.put( "TopWindow", true );
+ OutplaceFrameProperties.put( "SupportPersistentWindowState", true );
+
+ Reference< XFrame > xParentFrame;
+ if ( m_pImpl->m_pDataSource )
+ xParentFrame = lcl_getDatabaseDocumentFrame( *m_pImpl->m_pDataSource );
+ if ( !xParentFrame.is() )
+ { // i87957 we need a parent frame
+ Reference< XDesktop2 > xDesktop = Desktop::create( m_aContext );
+ xParentFrame.set( xDesktop, UNO_QUERY_THROW );
+ Reference<util::XCloseable> xCloseable(m_pImpl->m_pDataSource->getModel_noCreate(),UNO_QUERY);
+ if ( xCloseable.is() )
+ {
+ xCloseable->addCloseListener(this);
+ m_bRemoveListener = true;
+ }
+ }
+ OSL_ENSURE( xParentFrame.is(), "ODocumentDefinition::fillLoadArgs: no parent frame!" );
+ if ( xParentFrame.is() )
+ OutplaceFrameProperties.put( "ParentFrame", xParentFrame );
+
+ aEmbeddedDescriptor.put( "OutplaceFrameProperties", OutplaceFrameProperties.getNamedValues() );
+
+ // tell the embedded object to have (or not have) script support
+ aEmbeddedDescriptor.put( "EmbeddedScriptSupport", objectSupportsEmbeddedScripts() );
+
+ // tell the embedded object to not participate in the document recovery game - the DB doc will handle it
+ aEmbeddedDescriptor.put( "DocumentRecoverySupport", false );
+
+ // pass the descriptor of the embedded object to the caller
+ aEmbeddedDescriptor >>= _out_rEmbeddedObjectDescriptor;
+
+ // create the ComponentData, and put it into the document's media descriptor
+ {
+ ::comphelper::NamedValueCollection aComponentData;
+ aComponentData.put( "ActiveConnection", _xConnection );
+ aComponentData.put( "ApplyFormDesignMode", !_bReadOnly );
+ aMediaDesc.put( "ComponentData", aComponentData.getPropertyValues() );
+ }
+
+ if ( !m_pImpl->m_aProps.aTitle.isEmpty() )
+ aMediaDesc.put( "DocumentTitle", m_pImpl->m_aProps.aTitle );
+
+ aMediaDesc.put( "DocumentBaseURL", m_pImpl->m_pDataSource->getURL() );
+
+ // put the common load arguments into the document's media descriptor
+ lcl_putLoadArgs( aMediaDesc, optional_bool( _bSuppressMacros ), optional_bool( _bReadOnly ) );
+
+ return aMediaDesc.getPropertyValues();
+}
+
+void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& i_rConnection, const Sequence< sal_Int8 >& _aClassID,
+ const Sequence< PropertyValue >& i_rOpenCommandArguments, const bool _bSuppressMacros, const bool _bReadOnly )
+{
+ if ( !m_xEmbeddedObject.is() )
+ {
+ Reference< XStorage> xStorage = getContainerStorage();
+ if ( xStorage.is() )
+ {
+ Reference< XEmbeddedObjectCreator> xEmbedFactory = OOoEmbeddedObjectFactory::create(m_aContext);
+ OUString sDocumentService;
+ bool bSetSize = false;
+ sal_Int32 nEntryConnectionMode = EntryInitModes::DEFAULT_INIT;
+ Sequence< sal_Int8 > aClassID = _aClassID;
+ if ( aClassID.hasElements() )
+ {
+ nEntryConnectionMode = EntryInitModes::TRUNCATE_INIT;
+ bSetSize = true;
+ }
+ else
+ {
+ sDocumentService = GetDocumentServiceFromMediaType( getContentType(), m_aContext, aClassID );
+ // check if we are not a form and
+ // the org.libreoffice.report.pentaho.SOReportJobFactory is not present.
+ if ( !m_bForm && sDocumentService != "com.sun.star.text.TextDocument")
+ {
+ // we seem to be a "new style" report, check if report extension is present.
+ Reference< XContentEnumerationAccess > xEnumAccess( m_aContext->getServiceManager(), UNO_QUERY );
+ const OUString sReportEngineServiceName = ::dbtools::getDefaultReportEngineServiceName(m_aContext);
+ Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(sReportEngineServiceName);
+ if ( !xEnumDrivers.is() || !xEnumDrivers->hasMoreElements() )
+ {
+ css::io::WrongFormatException aWFE;
+ aWFE.Message = DBA_RES( RID_STR_MISSING_EXTENSION );
+ throw aWFE;
+ }
+ }
+ if ( !aClassID.hasElements() )
+ {
+ if ( m_bForm )
+ aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_SW_CLASSID);
+ else
+ {
+ aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_RPT_CLASSID_90);
+ }
+ }
+ }
+
+ OSL_ENSURE( aClassID.hasElements(),"No Class ID" );
+
+ Sequence< PropertyValue > aEmbeddedObjectDescriptor;
+ Sequence< PropertyValue > aLoadArgs( fillLoadArgs(
+ i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) );
+
+ m_xEmbeddedObject.set(xEmbedFactory->createInstanceUserInit(aClassID
+ ,sDocumentService
+ ,xStorage
+ ,m_pImpl->m_aProps.sPersistentName
+ ,nEntryConnectionMode
+ ,aLoadArgs
+ ,aEmbeddedObjectDescriptor
+ ),UNO_QUERY);
+ if ( m_xEmbeddedObject.is() )
+ {
+ if ( !m_pClientHelper.is() )
+ {
+ m_pClientHelper = new OEmbeddedClientHelper;
+ }
+ m_xEmbeddedObject->setClientSite(m_pClientHelper);
+ m_xEmbeddedObject->changeState(EmbedStates::RUNNING);
+ if ( bSetSize )
+ {
+ LockModifiable aLockModify( impl_getComponent_throw( false ) );
+
+ awt::Size aSize( DEFAULT_WIDTH, DEFAULT_HEIGHT );
+ m_xEmbeddedObject->setVisualAreaSize(Aspects::MSOLE_CONTENT,aSize);
+ }
+ }
+ }
+ }
+ else
+ {
+ sal_Int32 nCurrentState = m_xEmbeddedObject->getCurrentState();
+ if ( nCurrentState == EmbedStates::LOADED )
+ {
+ if ( !m_pClientHelper.is() )
+ {
+ m_pClientHelper = new OEmbeddedClientHelper;
+ }
+ m_xEmbeddedObject->setClientSite(m_pClientHelper);
+
+ Sequence< PropertyValue > aEmbeddedObjectDescriptor;
+ Sequence< PropertyValue > aLoadArgs( fillLoadArgs(
+ i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) );
+
+ Reference<XCommonEmbedPersist> xCommon(m_xEmbeddedObject,UNO_QUERY);
+ OSL_ENSURE(xCommon.is(),"unsupported interface!");
+ if ( xCommon.is() )
+ xCommon->reload( aLoadArgs, aEmbeddedObjectDescriptor );
+ m_xEmbeddedObject->changeState(EmbedStates::RUNNING);
+ }
+ else
+ {
+ OSL_ENSURE( ( nCurrentState == EmbedStates::RUNNING ) || ( nCurrentState == EmbedStates::ACTIVE ),
+ "ODocumentDefinition::loadEmbeddedObject: unexpected state!" );
+
+ // if the document was already loaded (which means the embedded object is in state RUNNING or ACTIVE),
+ // then just re-set some model parameters
+ try
+ {
+ // ensure the media descriptor doesn't contain any values which are intended for the
+ // EmbeddedObjectDescriptor only
+ ::comphelper::NamedValueCollection aEmbeddedObjectDescriptor;
+ ::comphelper::NamedValueCollection aNewMediaDesc;
+ separateOpenCommandArguments( i_rOpenCommandArguments, aNewMediaDesc, aEmbeddedObjectDescriptor );
+
+ // merge the new media descriptor into the existing media descriptor
+ const Reference< XModel > xModel( getComponent(), UNO_QUERY_THROW );
+ const Sequence< PropertyValue > aArgs = xModel->getArgs();
+ ::comphelper::NamedValueCollection aExistentMediaDesc( aArgs );
+ aExistentMediaDesc.merge( aNewMediaDesc, false );
+
+ lcl_putLoadArgs( aExistentMediaDesc, optional_bool(), optional_bool() );
+ // don't put _bSuppressMacros and _bReadOnly here - if the document was already
+ // loaded, we should not tamper with its settings.
+ // #i88977# #i86872#
+
+ xModel->attachResource( xModel->getURL(), aExistentMediaDesc.getPropertyValues() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ // set the OfficeDatabaseDocument instance as parent of the embedded document
+ // #i40358#
+ Reference< XChild > xDepdendDocAsChild( getComponent(), UNO_QUERY );
+ if ( xDepdendDocAsChild.is() )
+ {
+ try
+ {
+ if ( !xDepdendDocAsChild->getParent().is() )
+ { // first encounter
+ xDepdendDocAsChild->setParent( getDataSource( m_xParentContainer ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ if ( i_rConnection.is() )
+ m_xLastKnownConnection = i_rConnection;
+}
+
+void ODocumentDefinition::onCommandPreview(Any& _rImage)
+{
+ loadEmbeddedObjectForPreview();
+ if ( !m_xEmbeddedObject.is() )
+ return;
+
+ try
+ {
+ Reference<XTransferable> xTransfer(getComponent(),UNO_QUERY);
+ if ( xTransfer.is() )
+ {
+ DataFlavor aFlavor;
+ aFlavor.MimeType = "image/png";
+ aFlavor.HumanPresentableName = "Portable Network Graphics";
+ aFlavor.DataType = cppu::UnoType<Sequence < sal_Int8 >>::get();
+
+ _rImage = xTransfer->getTransferData( aFlavor );
+ }
+ }
+ catch( const Exception& )
+ {
+ }
+}
+
+void ODocumentDefinition::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const
+{
+ _rDefault.clear();
+}
+
+void ODocumentDefinition::onCommandGetDocumentProperties( Any& _rProps )
+{
+ loadEmbeddedObjectForPreview();
+ if ( !m_xEmbeddedObject.is() )
+ return;
+
+ try
+ {
+ Reference<XDocumentPropertiesSupplier> xDocSup(
+ getComponent(), UNO_QUERY );
+ if ( xDocSup.is() )
+ _rProps <<= xDocSup->getDocumentProperties();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference< util::XCloseable > ODocumentDefinition::impl_getComponent_throw( const bool i_ForceCreate )
+{
+ OSL_ENSURE(m_xEmbeddedObject.is(),"Illegal call for embeddedObject");
+ Reference< util::XCloseable > xComp;
+ if ( m_xEmbeddedObject.is() )
+ {
+ int nState = m_xEmbeddedObject->getCurrentState();
+ if ( ( nState == EmbedStates::LOADED ) && i_ForceCreate )
+ {
+ m_xEmbeddedObject->changeState( EmbedStates::RUNNING );
+ nState = m_xEmbeddedObject->getCurrentState();
+ OSL_ENSURE( nState == EmbedStates::RUNNING, "ODocumentDefinition::impl_getComponent_throw: could not switch to RUNNING!" );
+ }
+
+ if ( nState == EmbedStates::ACTIVE || nState == EmbedStates::RUNNING )
+ {
+ if ( m_xEmbeddedObject.is() )
+ {
+ xComp = m_xEmbeddedObject->getComponent();
+ OSL_ENSURE(xComp.is(),"No valid component");
+ }
+ }
+ }
+ return xComp;
+}
+
+Reference< util::XCloseable > ODocumentDefinition::getComponent()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return impl_getComponent_throw();
+}
+
+namespace
+{
+ Reference< XDatabaseDocumentUI > lcl_getDatabaseDocumentUI( ODatabaseModelImpl const & _rModelImpl )
+ {
+ Reference< XDatabaseDocumentUI > xUI;
+
+ Reference< XModel > xModel( _rModelImpl.getModel_noCreate() );
+ if ( xModel.is() )
+ xUI.set( xModel->getCurrentController(), UNO_QUERY );
+ return xUI;
+ }
+}
+
+Reference< XComponent > ODocumentDefinition::impl_openUI_nolck_throw( bool _bForEditing )
+{
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ if ( !m_pImpl || !m_pImpl->m_pDataSource )
+ throw DisposedException();
+
+ Reference< XComponent > xComponent;
+ try
+ {
+ Reference< XDatabaseDocumentUI > xUI( lcl_getDatabaseDocumentUI( *m_pImpl->m_pDataSource ) );
+ if ( !xUI.is() )
+ {
+ // no XDatabaseDocumentUI -> just execute the respective command
+ m_bOpenInDesign = _bForEditing;
+ xComponent = Reference<XComponent>(onCommandOpenSomething(Any(), true, nullptr), UNO_QUERY);
+ OSL_ENSURE( xComponent.is(), "ODocumentDefinition::impl_openUI_nolck_throw: opening the thingie failed." );
+ return xComponent;
+ }
+
+
+ OUString sName( impl_getHierarchicalName( false ) );
+ sal_Int32 nObjectType = m_bForm ? DatabaseObject::FORM : DatabaseObject::REPORT;
+ aGuard.clear();
+
+ xComponent = xUI->loadComponent(
+ nObjectType, sName, _bForEditing
+ );
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException(
+ OUString(), *this, ::cppu::getCaughtException() );
+ }
+
+ return xComponent;
+}
+
+void ODocumentDefinition::impl_store_throw()
+{
+ Reference<XEmbedPersist> xPersist( m_xEmbeddedObject, UNO_QUERY );
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ notifyDataSourceModified();
+ }
+}
+
+bool ODocumentDefinition::impl_close_throw()
+{
+ bool bSuccess = prepareClose();
+ if ( bSuccess && m_xEmbeddedObject.is() )
+ {
+ m_xEmbeddedObject->changeState( EmbedStates::LOADED );
+ bSuccess = m_xEmbeddedObject->getCurrentState() == EmbedStates::LOADED;
+ }
+ return bSuccess;
+}
+
+Reference< XComponent > SAL_CALL ODocumentDefinition::open( )
+{
+ return impl_openUI_nolck_throw( false );
+}
+
+Reference< XComponent > SAL_CALL ODocumentDefinition::openDesign( )
+{
+ return impl_openUI_nolck_throw( true );
+}
+
+void SAL_CALL ODocumentDefinition::store( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ try
+ {
+ impl_store_throw();
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException(
+ OUString(), *this, ::cppu::getCaughtException() );
+ }
+}
+
+sal_Bool SAL_CALL ODocumentDefinition::close( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ bool bSuccess = false;
+ try
+ {
+ bSuccess = impl_close_throw();
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException(
+ OUString(), *this, ::cppu::getCaughtException() );
+ }
+ return bSuccess;
+}
+
+OUString SAL_CALL ODocumentDefinition::getHierarchicalName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return impl_getHierarchicalName( false );
+}
+
+OUString SAL_CALL ODocumentDefinition::composeHierarchicalName( const OUString& i_rRelativeName )
+{
+ return getHierarchicalName() + "/" + i_rRelativeName;
+}
+
+void SAL_CALL ODocumentDefinition::rename( const OUString& _rNewName )
+{
+ try
+ {
+ ::osl::ResettableMutexGuard aGuard(m_aMutex);
+ if ( _rNewName == m_pImpl->m_aProps.aTitle )
+ return;
+
+ // document definitions are organized in a hierarchical way, so reject names
+ // which contain a /, as this is reserved for hierarchy level separation
+ if ( _rNewName.indexOf( '/' ) != -1 )
+ m_aErrorHelper.raiseException( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES, *this );
+
+ NameChangeNotifier aNameChangeAndNotify( *this, _rNewName, aGuard );
+ m_pImpl->m_aProps.aTitle = _rNewName;
+
+ if ( m_xEmbeddedObject.is() && m_xEmbeddedObject->getCurrentState() == EmbedStates::ACTIVE )
+ updateDocumentTitle();
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(_rNewName,*this);
+ }
+}
+
+Reference< XStorage> ODocumentDefinition::getContainerStorage() const
+{
+ return m_pImpl->m_pDataSource
+ ? m_pImpl->m_pDataSource->getStorage( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT )
+ : Reference< XStorage>();
+}
+
+bool ODocumentDefinition::isModified()
+{
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ bool bRet = false;
+ if ( m_xEmbeddedObject.is() )
+ {
+ Reference<XModifiable> xModel(getComponent(),UNO_QUERY);
+ bRet = xModel.is() && xModel->isModified();
+ }
+ return bRet;
+}
+
+bool ODocumentDefinition::prepareClose()
+{
+ if ( !m_xEmbeddedObject.is() )
+ return true;
+
+ try
+ {
+ // suspend the controller. Embedded objects are not allowed to raise
+ // own UI at their own discretion, instead, this has always to be triggered
+ // by the embedding component. Thus, we do the suspend call here.
+ // #i49370#
+
+ Reference< util::XCloseable > xComponent( impl_getComponent_throw( false ) );
+ if ( !xComponent.is() )
+ return true;
+
+ Reference< XModel > xModel( xComponent, UNO_QUERY );
+ Reference< XController > xController;
+ if ( xModel.is() )
+ xController = xModel->getCurrentController();
+
+ OSL_ENSURE( xController.is() || ( m_xEmbeddedObject->getCurrentState() < EmbedStates::ACTIVE ),
+ "ODocumentDefinition::prepareClose: no controller!" );
+ if ( !xController.is() )
+ // document has not yet been activated, i.e. has no UI, yet
+ return true;
+
+ if (!xController->suspend(true))
+ // controller vetoed the closing
+ return false;
+
+ if ( isModified() )
+ {
+ Reference< XFrame > xFrame( xController->getFrame() );
+ Reference<XTopWindow> xTopWindow;
+ if ( xFrame.is() )
+ {
+ xTopWindow = Reference<XTopWindow>(xFrame->getContainerWindow(), UNO_QUERY_THROW);
+ xTopWindow->toFront();
+ }
+ if (!save(true, xTopWindow))
+ {
+ // revert suspension
+ xController->suspend(false);
+ // saving failed or was cancelled
+ return false;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return true;
+}
+
+void ODocumentDefinition::fillReportData( const Reference< XComponentContext >& _rContext,
+ const Reference< util::XCloseable >& _rxComponent,
+ const Reference< XConnection >& _rxActiveConnection )
+{
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"TextDocument", uno::Any(_rxComponent)},
+ {"ActiveConnection", uno::Any(_rxActiveConnection)}
+ }));
+ try
+ {
+ Reference< XJobExecutor > xExecutable(
+ _rContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.wizards.report.CallReportWizard", aArgs, _rContext), UNO_QUERY_THROW );
+ xExecutable->trigger( "fill" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODocumentDefinition::updateDocumentTitle()
+{
+ OUString sName = m_pImpl->m_aProps.aTitle;
+ if ( m_pImpl->m_pDataSource )
+ {
+ if ( sName.isEmpty() )
+ {
+ if ( m_bForm )
+ sName = DBA_RES( RID_STR_FORM );
+ else
+ sName = DBA_RES( RID_STR_REPORT );
+ Reference< XUntitledNumbers > xUntitledProvider(m_pImpl->m_pDataSource->getModel_noCreate(), UNO_QUERY );
+ if ( xUntitledProvider.is() )
+ sName += OUString::number( xUntitledProvider->leaseNumber(getComponent()) );
+ }
+
+ Reference< XTitle > xDatabaseDocumentModel(m_pImpl->m_pDataSource->getModel_noCreate(),uno::UNO_QUERY);
+ if ( xDatabaseDocumentModel.is() )
+ sName = xDatabaseDocumentModel->getTitle() + " : " + sName;
+ }
+ Reference< XTitle> xTitle(getComponent(),UNO_QUERY);
+ if ( xTitle.is() )
+ xTitle->setTitle(sName);
+}
+
+void SAL_CALL ODocumentDefinition::queryClosing( const lang::EventObject&, sal_Bool )
+{
+ try
+ {
+ if ( !close() )
+ throw util::CloseVetoException();
+ }
+ catch(const lang::WrappedTargetException&)
+ {
+ throw util::CloseVetoException();
+ }
+}
+
+void SAL_CALL ODocumentDefinition::notifyClosing( const lang::EventObject& /*Source*/ )
+{
+}
+
+void SAL_CALL ODocumentDefinition::disposing( const lang::EventObject& /*Source*/ )
+{
+}
+
+void ODocumentDefinition::firePropertyChange( sal_Int32 i_nHandle, const Any& i_rNewValue, const Any& i_rOldValue,
+ bool i_bVetoable, const NotifierAccess& )
+{
+ fire( &i_nHandle, &i_rNewValue, &i_rOldValue, 1, i_bVetoable );
+}
+
+// NameChangeNotifier
+NameChangeNotifier::NameChangeNotifier( ODocumentDefinition& i_rDocumentDefinition, const OUString& i_rNewName,
+ ::osl::ResettableMutexGuard& i_rClearForNotify )
+ :m_rDocumentDefinition( i_rDocumentDefinition )
+ ,m_aOldValue( Any( i_rDocumentDefinition.getCurrentName() ) )
+ ,m_aNewValue( Any( i_rNewName ) )
+ ,m_rClearForNotify( i_rClearForNotify )
+{
+ impl_fireEvent_throw( true );
+}
+
+NameChangeNotifier::~NameChangeNotifier()
+{
+ impl_fireEvent_throw( false );
+}
+
+void NameChangeNotifier::impl_fireEvent_throw( const bool i_bVetoable )
+{
+ m_rClearForNotify.clear();
+ m_rDocumentDefinition.firePropertyChange(
+ PROPERTY_ID_NAME, m_aNewValue, m_aOldValue, i_bVetoable, ODocumentDefinition::NotifierAccess() );
+ m_rClearForNotify.reset();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentdefinition.hxx b/dbaccess/source/core/dataaccess/documentdefinition.hxx
new file mode 100644
index 000000000..5569276d4
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentdefinition.hxx
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/implbase4.hxx>
+#include <ContentHelper.hxx>
+#include <comphelper/propertystatecontainer.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <apitools.hxx>
+#include <comphelper/uno3.hxx>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/embed/XStateChangeListener.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/sdb/XSubDocument.hpp>
+#include <com/sun/star/util/XCloseListener.hpp>
+#include <com/sun/star/container/XHierarchicalName.hpp>
+#include <rtl/ref.hxx>
+
+namespace comphelper
+{
+ class NamedValueCollection;
+}
+
+namespace dbaccess
+{
+
+ class OInterceptor;
+ class OEmbeddedClientHelper;
+// ODocumentDefinition - a database "document" which is simply a link to a real
+// document
+
+typedef ::cppu::ImplHelper4 < css::embed::XComponentSupplier
+ , css::sdb::XSubDocument
+ , css::util::XCloseListener
+ , css::container::XHierarchicalName
+ > ODocumentDefinition_Base;
+
+class ODocumentDefinition
+ :public OContentHelper
+ ,public ::comphelper::OPropertyStateContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper< ODocumentDefinition >
+ ,public ODocumentDefinition_Base
+{
+ css::uno::Reference< css::embed::XEmbeddedObject> m_xEmbeddedObject;
+ css::uno::Reference< css::embed::XStateChangeListener > m_xListener;
+ css::uno::Reference< css::sdbc::XConnection > m_xLastKnownConnection;
+
+ rtl::Reference<OInterceptor> m_pInterceptor;
+ bool m_bForm; // <TRUE/> if it is a form
+ bool m_bOpenInDesign;
+ bool m_bInExecute;
+ bool m_bRemoveListener;
+ rtl::Reference<OEmbeddedClientHelper> m_pClientHelper;
+
+protected:
+ virtual ~ODocumentDefinition() override;
+
+public:
+
+ ODocumentDefinition(
+ const css::uno::Reference< css::uno::XInterface >& _rxContainer,
+ const css::uno::Reference< css::uno::XComponentContext >&,
+ const TContentPtr& _pImpl,
+ bool _bForm
+ );
+
+ void initialLoad(
+ const css::uno::Sequence< sal_Int8 >& i_rClassID,
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rCreationArgs,
+ const css::uno::Reference< css::sdbc::XConnection >& i_rConnection
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // OPropertySetHelper
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& o_rValue,
+ sal_Int32 i_nHandle
+ ) const override;
+
+ // XComponentSupplier
+ virtual css::uno::Reference< css::util::XCloseable > SAL_CALL getComponent( ) override;
+
+ // XSubDocument
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL open( ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL openDesign( ) override;
+ virtual void SAL_CALL store( ) override;
+ virtual sal_Bool SAL_CALL close( ) override;
+
+ // XHierarchicalName
+ virtual OUString SAL_CALL getHierarchicalName( ) override;
+ virtual OUString SAL_CALL composeHierarchicalName( const OUString& aRelativeName ) override;
+
+// OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // XCommandProcessor
+ virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override ;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // XCloseListener
+ virtual void SAL_CALL queryClosing( const css::lang::EventObject& Source, sal_Bool GetsOwnership ) override;
+ virtual void SAL_CALL notifyClosing( const css::lang::EventObject& Source ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ /** returns the forms/reports container storage, depending on m_bForm. Our own storage
+ inside this container storage is the one with the name as indicated by m_pImpl->m_aProps.sPersistentName.
+ */
+ css::uno::Reference< css::embed::XStorage >
+ getContainerStorage() const;
+
+ bool save(bool _bApprove, const css::uno::Reference<css::awt::XTopWindow>& rDialogParent);
+ void saveAs();
+ void closeObject();
+ bool isModified();
+ bool isNewReport() const { return !m_bForm && !m_pImpl->m_aProps.bAsTemplate; }
+
+ static void fillReportData(
+ const css::uno::Reference< css::uno::XComponentContext > & _rxContext,
+ const css::uno::Reference< css::util::XCloseable >& _rxComponent,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxActiveConnection
+ );
+
+ const css::uno::Reference< css::sdbc::XConnection >&
+ getConnection() const { return m_xLastKnownConnection; }
+
+ /** prepares closing the document component
+
+ The method suspends the controller associated with the document, and saves the document
+ if necessary.
+
+ @return
+ <TRUE/> if and only if the document component can be closed
+ */
+ bool prepareClose();
+
+ static OUString GetDocumentServiceFromMediaType(
+ const OUString& _rMediaType,
+ const css::uno::Reference< css::uno::XComponentContext > & _rxContext,
+ css::uno::Sequence< sal_Int8 >& _rClassId
+ );
+ static OUString GetDocumentServiceFromMediaType(
+ const css::uno::Reference< css::embed::XStorage >& _rxContainerStorage,
+ const OUString& _rEntityName,
+ const css::uno::Reference< css::uno::XComponentContext > & _rxContext,
+ css::uno::Sequence< sal_Int8 >& _rClassId
+ );
+
+ struct NotifierAccess { friend class NameChangeNotifier; private: NotifierAccess() { } };
+ const OUString& getCurrentName() const { return m_pImpl->m_aProps.aTitle; }
+ void firePropertyChange(
+ sal_Int32 i_nHandle,
+ const css::uno::Any& i_rNewValue,
+ const css::uno::Any& i_rOldValue,
+ bool i_bVetoable,
+ const NotifierAccess&
+ );
+
+private:
+ /** does necessary initializations after our embedded object has been switched to ACTIVE
+ */
+ void impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated );
+
+ /** initializes a newly created view/controller of a form which is displaying our embedded object
+
+ Has only to be called if the respective embedded object has been loaded for design (and
+ not for data entry)
+
+ @param _rxController
+ the controller which belongs to the XModel of our (active) embedded object
+ */
+ static void impl_initFormEditView( const css::uno::Reference< css::frame::XController >& _rxController );
+
+ /** removes the given frame from the desktop's frame collection
+ @throws css::uno::RuntimeException
+ */
+ static void impl_removeFrameFromDesktop_throw(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::frame::XFrame >& _rxFrame
+ );
+
+ /** opens the UI for this sub document
+ */
+ css::uno::Reference< css::lang::XComponent >
+ impl_openUI_nolck_throw( bool _bForEditing );
+
+ /** stores our document, if it's already loaded
+ */
+ void impl_store_throw();
+
+ /** closes our document, if it's open
+ */
+ bool impl_close_throw();
+
+ /** returns our component, creates it if necessary
+ */
+ css::uno::Reference< css::util::XCloseable >
+ impl_getComponent_throw( const bool i_ForceCreate = true );
+
+ /** shows or hides our component
+
+ The embedded object must exist, and be in state LOADED, at least.
+ */
+ void impl_showOrHideComponent_throw( const bool i_bShow );
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ // helper
+ virtual void SAL_CALL disposing() override;
+
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+ /** fills the load arguments
+ */
+ css::uno::Sequence< css::beans::PropertyValue >
+ fillLoadArgs(
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const bool _bSuppressMacros,
+ const bool _bReadOnly,
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rOpenCommandArguments,
+ css::uno::Sequence< css::beans::PropertyValue >& _out_rEmbeddedObjectDescriptor
+ );
+
+ /** splits the given arguments to an "open*" command into arguments for loading the document, and arguments to be
+ put into the EmbeddedObjectDescriptor
+
+ Any values already present in <code>o_rDocumentLoadArgs</code> and <code>o_rEmbeddedObjectDescriptor</code>
+ will be overwritten by values from <code>i_rOpenCommandArguments</code>, if applicable, otherwise they will
+ be preserved.
+
+ @param i_rOpenCommandArguments
+ the arguments passed to the "open*" command at the content
+ @param o_rDocumentLoadArgs
+ the arguments to be passed when actually loading the embedded document.
+ @param o_rEmbeddedObjectDescriptor
+ the EmbeddedObjectDescriptor to be passed when initializing the embedded object
+ */
+ static void separateOpenCommandArguments(
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rOpenCommandArguments,
+ ::comphelper::NamedValueCollection& o_rDocumentLoadArgs,
+ ::comphelper::NamedValueCollection& o_rEmbeddedObjectDescriptor
+ );
+
+ /** loads the EmbeddedObject if not already loaded
+ @param _aClassID
+ If set, it will be used to create the embedded object.
+ */
+ void loadEmbeddedObject(
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const css::uno::Sequence< sal_Int8 >& _aClassID,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rAdditionalArgs,
+ const bool _bSuppressMacros,
+ const bool _bReadOnly
+ );
+
+ /** loads the embedded object for preview. Macros will be suppressed, and the document will
+ be read-only.
+ */
+ void loadEmbeddedObjectForPreview()
+ {
+ loadEmbeddedObject(
+ nullptr,
+ css::uno::Sequence< sal_Int8 >(),
+ css::uno::Sequence< css::beans::PropertyValue >(),
+ true,
+ true
+ );
+ }
+
+ /** searches for read-only flag in the args of the model and sets it to the given value,
+ if the value was not found, it will be appended.
+ @param _bReadOnly
+ If <TRUE/> the document will be switched to readonly mode
+ */
+ void updateDocumentTitle();
+
+ void registerProperties();
+
+ /** determines whether the document we represent supports embedded scripts and macros
+ */
+ bool objectSupportsEmbeddedScripts() const;
+
+ //- commands
+
+ void onCommandGetDocumentProperties( css::uno::Any& _rProps );
+ /// @throws css::uno::Exception
+ void onCommandInsert( const OUString& _sURL, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment );
+ void onCommandPreview( css::uno::Any& _rImage );
+ css::uno::Any
+ onCommandOpenSomething(
+ const css::uno::Any& _rArgument,
+ const bool _bActivate,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& _rxEnvironment
+ );
+private:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+class NameChangeNotifier
+{
+public:
+ NameChangeNotifier(
+ ODocumentDefinition& i_rDocumentDefinition,
+ const OUString& i_rNewName,
+ ::osl::ResettableMutexGuard& i_rClearForNotify
+ );
+ ~NameChangeNotifier();
+
+private:
+ ODocumentDefinition& m_rDocumentDefinition;
+ const css::uno::Any m_aOldValue;
+ const css::uno::Any m_aNewValue;
+ ::osl::ResettableMutexGuard& m_rClearForNotify;
+
+ void impl_fireEvent_throw( const bool i_bVetoable );
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.cxx b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx
new file mode 100644
index 000000000..3d16ee6eb
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "documenteventexecutor.hxx"
+
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::WeakReference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::document::XDocumentEventBroadcaster;
+ using ::com::sun::star::document::XEventsSupplier;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::util::URLTransformer;
+ using ::com::sun::star::util::XURLTransformer;
+ using ::com::sun::star::frame::XDispatchProvider;
+ using ::com::sun::star::frame::XDispatch;
+ using ::com::sun::star::util::URL;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::document::DocumentEvent;
+
+ using namespace ::com::sun::star;
+
+ // DocumentEventExecutor_Data
+ struct DocumentEventExecutor_Data
+ {
+ WeakReference< XEventsSupplier > xDocument;
+ Reference< XURLTransformer > xURLTransformer;
+
+ explicit DocumentEventExecutor_Data( const Reference< XEventsSupplier >& _rxDocument )
+ :xDocument( _rxDocument )
+ {
+ }
+ };
+
+ namespace
+ {
+ void lcl_dispatchScriptURL_throw( DocumentEventExecutor_Data const & _rDocExecData,
+ const OUString& _rScriptURL, const DocumentEvent& _rTrigger )
+ {
+ Reference< XModel > xDocument( _rDocExecData.xDocument.get(), UNO_QUERY_THROW );
+
+ Reference< XController > xController( xDocument->getCurrentController() );
+ Reference< XDispatchProvider > xDispProv;
+ if ( xController.is() )
+ xDispProv.set( xController->getFrame(), UNO_QUERY );
+ if ( !xDispProv.is() )
+ {
+ OSL_FAIL( "lcl_dispatchScriptURL_throw: no controller/frame? How should I dispatch?" );
+ return;
+ }
+
+ URL aScriptURL;
+ aScriptURL.Complete = _rScriptURL;
+ if ( _rDocExecData.xURLTransformer.is() )
+ _rDocExecData.xURLTransformer->parseStrict( aScriptURL );
+
+ // unfortunately, executing a script can trigger all kind of complex stuff, and unfortunately, not
+ // every component involved into this properly cares for thread safety. To be on the safe side,
+ // we lock the solar mutex here.
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XDispatch > xDispatch( xDispProv->queryDispatch( aScriptURL, OUString(), 0 ) );
+ if ( !xDispatch.is() )
+ {
+ OSL_FAIL( "lcl_dispatchScriptURL_throw: no dispatcher for the script URL!" );
+ return;
+ }
+
+ PropertyValue aEventParam;
+ aEventParam.Value <<= _rTrigger;
+ Sequence< PropertyValue > aDispatchArgs( &aEventParam, 1 );
+ xDispatch->dispatch( aScriptURL, aDispatchArgs );
+ }
+ }
+
+ // DocumentEventExecutor
+ DocumentEventExecutor::DocumentEventExecutor( const Reference<XComponentContext> & _rContext,
+ const Reference< XEventsSupplier >& _rxDocument )
+ :m_pData( new DocumentEventExecutor_Data( _rxDocument ) )
+ {
+ Reference< XDocumentEventBroadcaster > xBroadcaster( _rxDocument, UNO_QUERY_THROW );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ xBroadcaster->addDocumentEventListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+
+ try
+ {
+ m_pData->xURLTransformer = URLTransformer::create(_rContext);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ DocumentEventExecutor::~DocumentEventExecutor()
+ {
+ }
+
+ void SAL_CALL DocumentEventExecutor::documentEventOccured( const DocumentEvent& Event )
+ {
+ Reference< XEventsSupplier > xEventsSupplier( m_pData->xDocument.get(), UNO_QUERY );
+ if ( !xEventsSupplier.is() )
+ {
+ OSL_FAIL( "DocumentEventExecutor::documentEventOccurred: no document anymore, but still being notified?" );
+ return;
+ }
+
+ Reference< XModel > xDocument( xEventsSupplier, UNO_QUERY_THROW );
+
+ try
+ {
+ Reference< XNameAccess > xDocEvents( xEventsSupplier->getEvents(), UNO_SET_THROW );
+ if ( !xDocEvents->hasByName( Event.EventName ) )
+ {
+ // this is worth an assertion: We are listener at the very same document which we just asked
+ // for its events. So when EventName is fired, why isn't it supported by xDocEvents?
+ OSL_FAIL( "DocumentEventExecutor::documentEventOccurred: an unsupported event is notified!" );
+ return;
+ }
+
+ const ::comphelper::NamedValueCollection aScriptDescriptor( xDocEvents->getByName( Event.EventName ) );
+
+ OUString sEventType;
+ bool bScriptAssigned = aScriptDescriptor.get_ensureType( "EventType", sEventType );
+
+ OUString sScript;
+ bScriptAssigned = bScriptAssigned && aScriptDescriptor.get_ensureType( "Script", sScript );
+
+ if ( !bScriptAssigned )
+ // no script is assigned to this event
+ return;
+
+ bool bDispatchScriptURL = ( sEventType == "Script" || sEventType == "Service" );
+ bool bNonEmptyScript = !sScript.isEmpty();
+
+ OSL_ENSURE( bDispatchScriptURL && bNonEmptyScript,
+ "DocumentEventExecutor::documentEventOccurred: invalid/unsupported script descriptor" );
+
+ if ( bDispatchScriptURL && bNonEmptyScript )
+ {
+ lcl_dispatchScriptURL_throw( *m_pData, sScript, Event );
+ }
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void SAL_CALL DocumentEventExecutor::disposing( const lang::EventObject& /*_Source*/ )
+ {
+ // not interested in
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.hxx b/dbaccess/source/core/dataaccess/documenteventexecutor.hxx
new file mode 100644
index 000000000..90dc9083c
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventexecutor.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/document/XDocumentEventListener.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace dbaccess
+{
+
+ struct DocumentEventExecutor_Data;
+ // DocumentEventExecutor
+ typedef ::cppu::WeakImplHelper < css::document::XDocumentEventListener
+ > DocumentEventExecutor_Base;
+ class DocumentEventExecutor : public DocumentEventExecutor_Base
+ {
+ public:
+ DocumentEventExecutor(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::document::XEventsSupplier >& _rxDocument );
+
+ protected:
+ virtual ~DocumentEventExecutor() override;
+
+ // css.document.XDocumentEventListener
+ virtual void SAL_CALL documentEventOccured( const css::document::DocumentEvent& Event ) override;
+ // css.lang.XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ private:
+ std::unique_ptr< DocumentEventExecutor_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.cxx b/dbaccess/source/core/dataaccess/documenteventnotifier.cxx
new file mode 100644
index 000000000..6a7088f95
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventnotifier.cxx
@@ -0,0 +1,290 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "documenteventnotifier.hxx"
+
+#include <com/sun/star/frame/DoubleInitializationException.hpp>
+
+#include <comphelper/asyncnotification.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/weak.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::frame::DoubleInitializationException;
+ using ::com::sun::star::document::XDocumentEventListener;
+ using ::com::sun::star::document::DocumentEvent;
+ using ::com::sun::star::frame::XController2;
+
+ using namespace ::com::sun::star;
+
+ // DocumentEventHolder
+ typedef ::comphelper::EventHolder< DocumentEvent > DocumentEventHolder;
+
+ // DocumentEventNotifier_Impl
+ class DocumentEventNotifier_Impl : public ::comphelper::IEventProcessor
+ {
+ oslInterlockedCount m_refCount;
+ ::cppu::OWeakObject& m_rDocument;
+ ::osl::Mutex& m_rMutex;
+ bool m_bInitialized;
+ bool m_bDisposed;
+ std::shared_ptr<::comphelper::AsyncEventNotifierAutoJoin> m_pEventBroadcaster;
+ ::comphelper::OInterfaceContainerHelper3<css::document::XEventListener> m_aLegacyEventListeners;
+ ::comphelper::OInterfaceContainerHelper3<XDocumentEventListener> m_aDocumentEventListeners;
+
+ public:
+ DocumentEventNotifier_Impl( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex )
+ :m_refCount( 0 )
+ ,m_rDocument( _rBroadcasterDocument )
+ ,m_rMutex( _rMutex )
+ ,m_bInitialized( false )
+ ,m_bDisposed( false )
+ ,m_aLegacyEventListeners( _rMutex )
+ ,m_aDocumentEventListeners( _rMutex )
+ {
+ }
+
+ // IEventProcessor
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ void addLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_aLegacyEventListeners.addInterface( Listener );
+ }
+
+ void removeLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_aLegacyEventListeners.removeInterface( Listener );
+ }
+
+ void addDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_aDocumentEventListeners.addInterface( Listener );
+ }
+
+ void removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_aDocumentEventListeners.removeInterface( Listener );
+ }
+
+ void disposing();
+
+ void onDocumentInitialized();
+
+ void notifyDocumentEvent( const OUString& EventName, const Reference< XController2 >& ViewController,
+ const Any& Supplement )
+ {
+ impl_notifyEvent_nothrow( DocumentEvent(
+ m_rDocument, EventName, ViewController, Supplement ) );
+ }
+
+ void notifyDocumentEventAsync( const OUString& EventName, const Reference< XController2 >& ViewController,
+ const Any& Supplement )
+ {
+ impl_notifyEventAsync_nothrow( DocumentEvent(
+ m_rDocument, EventName, ViewController, Supplement ) );
+ }
+
+ protected:
+ virtual ~DocumentEventNotifier_Impl()
+ {
+ }
+
+ // IEventProcessor
+ virtual void processEvent( const ::comphelper::AnyEvent& _rEvent ) override;
+
+ private:
+ void impl_notifyEvent_nothrow( const DocumentEvent& _rEvent );
+ void impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent );
+ };
+
+ void SAL_CALL DocumentEventNotifier_Impl::acquire() noexcept
+ {
+ osl_atomic_increment( &m_refCount );
+ }
+
+ void SAL_CALL DocumentEventNotifier_Impl::release() noexcept
+ {
+ if ( 0 == osl_atomic_decrement( &m_refCount ) )
+ delete this;
+ }
+
+ void DocumentEventNotifier_Impl::disposing()
+ {
+ // SYNCHRONIZED ->
+ // cancel any pending asynchronous events
+ ::osl::ResettableMutexGuard aGuard( m_rMutex );
+ if (m_pEventBroadcaster)
+ {
+ m_pEventBroadcaster->removeEventsForProcessor( this );
+ m_pEventBroadcaster->terminate();
+ }
+
+ auto xEventBroadcaster = std::exchange(m_pEventBroadcaster, {});
+
+ lang::EventObject aEvent( m_rDocument );
+ aGuard.clear();
+ // <-- SYNCHRONIZED
+
+ if (xEventBroadcaster)
+ {
+ comphelper::SolarMutex& rSolarMutex = Application::GetSolarMutex();
+ // unblock threads blocked on that so we can join
+ sal_uInt32 nLockCount = (rSolarMutex.IsCurrentThread()) ? rSolarMutex.release(true) : 0;
+ xEventBroadcaster->join();
+ if (nLockCount)
+ rSolarMutex.acquire(nLockCount);
+ xEventBroadcaster.reset();
+ }
+ m_aLegacyEventListeners.disposeAndClear( aEvent );
+ m_aDocumentEventListeners.disposeAndClear( aEvent );
+
+ // SYNCHRONIZED ->
+ aGuard.reset();
+ m_bDisposed = true;
+ // <-- SYNCHRONIZED
+ }
+
+ void DocumentEventNotifier_Impl::onDocumentInitialized()
+ {
+ if ( m_bInitialized )
+ throw DoubleInitializationException();
+
+ m_bInitialized = true;
+ if (m_pEventBroadcaster)
+ {
+ // there are already pending asynchronous events
+ ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster);
+ }
+ }
+
+ void DocumentEventNotifier_Impl::impl_notifyEvent_nothrow( const DocumentEvent& _rEvent )
+ {
+ OSL_PRECOND( m_bInitialized,
+ "DocumentEventNotifier_Impl::impl_notifyEvent_nothrow: only to be called when the document is already initialized!" );
+ try
+ {
+ document::EventObject aLegacyEvent( _rEvent.Source, _rEvent.EventName );
+ m_aLegacyEventListeners.notifyEach( &document::XEventListener::notifyEvent, aLegacyEvent );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ try
+ {
+ m_aDocumentEventListeners.notifyEach( &XDocumentEventListener::documentEventOccured, _rEvent );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void DocumentEventNotifier_Impl::impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent )
+ {
+ if (!m_pEventBroadcaster)
+ {
+ m_pEventBroadcaster = ::comphelper::AsyncEventNotifierAutoJoin
+ ::newAsyncEventNotifierAutoJoin("DocumentEventNotifier");
+ if ( m_bInitialized )
+ {
+ // start processing the events if and only if we (our document, respectively) are
+ // already initialized
+ ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster);
+ }
+ }
+ m_pEventBroadcaster->addEvent( new DocumentEventHolder( _rEvent ), this );
+ }
+
+ void DocumentEventNotifier_Impl::processEvent( const ::comphelper::AnyEvent& _rEvent )
+ {
+ // beware, this is called from the notification thread
+ {
+ ::osl::MutexGuard aGuard( m_rMutex );
+ if ( m_bDisposed )
+ return;
+ }
+ const DocumentEventHolder& rEventHolder = dynamic_cast< const DocumentEventHolder& >( _rEvent );
+ impl_notifyEvent_nothrow( rEventHolder.getEventObject() );
+ }
+
+ // DocumentEventNotifier
+ DocumentEventNotifier::DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex )
+ :m_pImpl( new DocumentEventNotifier_Impl( _rBroadcasterDocument, _rMutex ) )
+ {
+ }
+
+ DocumentEventNotifier::~DocumentEventNotifier()
+ {
+ }
+
+ void DocumentEventNotifier::disposing()
+ {
+ m_pImpl->disposing();
+ }
+
+ void DocumentEventNotifier::onDocumentInitialized()
+ {
+ m_pImpl->onDocumentInitialized();
+ }
+
+ void DocumentEventNotifier::addLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_pImpl->addLegacyEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::removeLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_pImpl->removeLegacyEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::addDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_pImpl->addDocumentEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_pImpl->removeDocumentEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::notifyDocumentEvent( const OUString& EventName,
+ const Reference< XController2 >& ViewController, const Any& Supplement )
+ {
+ m_pImpl->notifyDocumentEvent( EventName, ViewController, Supplement );
+ }
+
+ void DocumentEventNotifier::notifyDocumentEventAsync( const OUString& EventName,
+ const Reference< XController2 >& ViewController, const Any& Supplement )
+ {
+ m_pImpl->notifyDocumentEventAsync( EventName, ViewController, Supplement );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.hxx b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx
new file mode 100644
index 000000000..6f3bffc4c
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/document/XDocumentEventListener.hpp>
+
+#include <rtl/ref.hxx>
+
+namespace cppu
+{
+ class OWeakObject;
+}
+
+namespace dbaccess
+{
+
+ class DocumentEventNotifier_Impl;
+ // DocumentEventNotifier
+ class DocumentEventNotifier
+ {
+ public:
+ DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex );
+ ~DocumentEventNotifier();
+
+ void addLegacyEventListener( const css::uno::Reference< css::document::XEventListener >& Listener );
+ void removeLegacyEventListener( const css::uno::Reference< css::document::XEventListener >& Listener );
+ void addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener );
+ void removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener );
+
+ /** disposes the instance
+ @precond
+ the mutex is not locked
+ */
+ void disposing();
+
+ /** tells the instance that its document is completely initialized now.
+
+ Before you call this method, no notification will actually happen
+
+ @precond
+ the mutex is locked
+ */
+ void onDocumentInitialized();
+
+ /** notifies a document event described by the given parameters
+
+ @precond
+ the mutex is not locked
+ @precond
+ ->onDocumentInitialized has been called
+ */
+ void notifyDocumentEvent(
+ const OUString& EventName,
+ const css::uno::Reference< css::frame::XController2 >& _rxViewController,
+ const css::uno::Any& Supplement
+ );
+
+ /** notifies a document event, described by the given parameters, asynchronously
+
+ Note that no event is actually notified before you called ->onDocumentInitialized.
+
+ @precond
+ the mutex is locked
+ */
+ void notifyDocumentEventAsync(
+ const OUString& EventName,
+ const css::uno::Reference< css::frame::XController2 >& ViewController,
+ const css::uno::Any& Supplement
+ );
+
+ /** notifies a document event to all registered listeners
+
+ @precond
+ the mutex is not locked
+ @precond
+ ->onDocumentInitialized has been called
+ */
+ void notifyDocumentEvent(
+ const char* _pAsciiEventName,
+ const css::uno::Reference< css::frame::XController2 >& _rxViewController = nullptr,
+ const css::uno::Any& _rSupplement = css::uno::Any()
+ )
+ {
+ notifyDocumentEvent( OUString::createFromAscii( _pAsciiEventName ), _rxViewController, _rSupplement );
+ }
+
+ /** notifies a document event to all registered listeners, asynchronously
+
+ Note that no event is actually notified before you called ->onDocumentInitialized.
+
+ @precond
+ the mutex is locked
+ */
+ void notifyDocumentEventAsync(
+ const char* _pAsciiEventName,
+ const css::uno::Reference< css::frame::XController2 >& _rxViewController = nullptr,
+ const css::uno::Any& _rSupplement = css::uno::Any()
+ )
+ {
+ notifyDocumentEventAsync( OUString::createFromAscii( _pAsciiEventName ), _rxViewController, _rSupplement );
+ }
+
+ private:
+ ::rtl::Reference< DocumentEventNotifier_Impl > m_pImpl;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentevents.cxx b/dbaccess/source/core/dataaccess/documentevents.cxx
new file mode 100644
index 000000000..571ad2c6f
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentevents.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <documentevents.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/sequence.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Type;
+
+ // DocumentEvents_Data
+ struct DocumentEvents_Data
+ {
+ ::cppu::OWeakObject& rParent;
+ ::osl::Mutex& rMutex;
+ DocumentEventsData& rEventsData;
+
+ DocumentEvents_Data( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData )
+ :rParent( _rParent )
+ ,rMutex( _rMutex )
+ ,rEventsData( _rEventsData )
+ {
+ }
+ DocumentEvents_Data(const DocumentEvents_Data&) = delete;
+ const DocumentEvents_Data& operator=(const DocumentEvents_Data&) = delete;
+ };
+
+ namespace {
+
+ // helper
+ struct DocumentEventData
+ {
+ const char* pAsciiEventName;
+ bool bNeedsSyncNotify;
+ };
+
+ const DocumentEventData* lcl_getDocumentEventData()
+ {
+ static const DocumentEventData s_aData[] = {
+ { "OnCreate", true },
+ { "OnLoadFinished", true },
+ { "OnNew", false }, // compatibility, see https://bz.apache.org/ooo/show_bug.cgi?id=46484
+ { "OnLoad", false }, // compatibility, see https://bz.apache.org/ooo/show_bug.cgi?id=46484
+ { "OnSaveAs", true },
+ { "OnSaveAsDone", false },
+ { "OnSaveAsFailed", false },
+ { "OnSave", true },
+ { "OnSaveDone", false },
+ { "OnSaveFailed", false },
+ { "OnSaveTo", true },
+ { "OnSaveToDone", false },
+ { "OnSaveToFailed", false },
+ { "OnPrepareUnload", true },
+ { "OnUnload", true },
+ { "OnFocus", false },
+ { "OnUnfocus", false },
+ { "OnModifyChanged", false },
+ { "OnViewCreated", false },
+ { "OnPrepareViewClosing", true },
+ { "OnViewClosed", false },
+ { "OnTitleChanged", false },
+ { "OnSubComponentOpened", false },
+ { "OnSubComponentClosed", false },
+ { nullptr, false }
+ };
+ return s_aData;
+ }
+ }
+
+ // DocumentEvents
+ DocumentEvents::DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData )
+ :m_pData( new DocumentEvents_Data( _rParent, _rMutex, _rEventsData ) )
+ {
+ const DocumentEventData* pEventData = lcl_getDocumentEventData();
+ while ( pEventData->pAsciiEventName )
+ {
+ OUString sEventName = OUString::createFromAscii( pEventData->pAsciiEventName );
+ DocumentEventsData::const_iterator existingPos = m_pData->rEventsData.find( sEventName );
+ if ( existingPos == m_pData->rEventsData.end() )
+ m_pData->rEventsData[ sEventName ] = Sequence< PropertyValue >();
+ ++pEventData;
+ }
+ }
+
+ DocumentEvents::~DocumentEvents()
+ {
+ }
+
+ void SAL_CALL DocumentEvents::acquire() noexcept
+ {
+ m_pData->rParent.acquire();
+ }
+
+ void SAL_CALL DocumentEvents::release() noexcept
+ {
+ m_pData->rParent.release();
+ }
+
+ bool DocumentEvents::needsSynchronousNotification( std::u16string_view _rEventName )
+ {
+ const DocumentEventData* pEventData = lcl_getDocumentEventData();
+ while ( pEventData->pAsciiEventName )
+ {
+ if ( o3tl::equalsAscii( _rEventName, pEventData->pAsciiEventName ) )
+ return pEventData->bNeedsSyncNotify;
+ ++pEventData;
+ }
+
+ // this is an unknown event ... assume async notification
+ return false;
+ }
+
+ void SAL_CALL DocumentEvents::replaceByName( const OUString& Name, const Any& Element )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ DocumentEventsData::iterator elementPos = m_pData->rEventsData.find( Name );
+ if ( elementPos == m_pData->rEventsData.end() )
+ throw NoSuchElementException( Name, *this );
+
+ Sequence< PropertyValue > aEventDescriptor;
+ if ( Element.hasValue() && !( Element >>= aEventDescriptor ) )
+ throw IllegalArgumentException( Element.getValueTypeName(), *this, 2 );
+
+ // Weird enough, the event assignment UI has (well: had) the idea of using an empty "EventType"/"Script"
+ // to indicate the event descriptor should be reset, instead of just passing an empty event descriptor.
+ ::comphelper::NamedValueCollection aCheck( aEventDescriptor );
+ if ( aCheck.has( "EventType" ) )
+ {
+ OUString sEventType = aCheck.getOrDefault( "EventType", OUString() );
+ OSL_ENSURE( !sEventType.isEmpty(), "DocumentEvents::replaceByName: doing a reset via an empty EventType is weird!" );
+ if ( sEventType.isEmpty() )
+ aEventDescriptor.realloc( 0 );
+ }
+ if ( aCheck.has( "Script" ) )
+ {
+ OUString sScript = aCheck.getOrDefault( "Script", OUString() );
+ OSL_ENSURE( !sScript.isEmpty(), "DocumentEvents::replaceByName: doing a reset via an empty Script is weird!" );
+ if ( sScript.isEmpty() )
+ aEventDescriptor.realloc( 0 );
+ }
+
+ elementPos->second = aEventDescriptor;
+ }
+
+ Any SAL_CALL DocumentEvents::getByName( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ DocumentEventsData::const_iterator elementPos = m_pData->rEventsData.find( Name );
+ if ( elementPos == m_pData->rEventsData.end() )
+ throw NoSuchElementException( Name, *this );
+
+ Any aReturn;
+ const Sequence< PropertyValue >& rEventDesc( elementPos->second );
+ if ( rEventDesc.hasElements() )
+ aReturn <<= rEventDesc;
+ return aReturn;
+ }
+
+ Sequence< OUString > SAL_CALL DocumentEvents::getElementNames( )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ return comphelper::mapKeysToSequence( m_pData->rEventsData );
+ }
+
+ sal_Bool SAL_CALL DocumentEvents::hasByName( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ return m_pData->rEventsData.find( Name ) != m_pData->rEventsData.end();
+ }
+
+ Type SAL_CALL DocumentEvents::getElementType( )
+ {
+ return ::cppu::UnoType< Sequence< PropertyValue > >::get();
+ }
+
+ sal_Bool SAL_CALL DocumentEvents::hasElements( )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+ return !m_pData->rEventsData.empty();
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/intercept.cxx b/dbaccess/source/core/dataaccess/intercept.cxx
new file mode 100644
index 000000000..bef079d47
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/intercept.cxx
@@ -0,0 +1,363 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "intercept.hxx"
+
+#include <tools/diagnose_ex.h>
+
+#include <memory>
+
+namespace dbaccess
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+#define DISPATCH_SAVEAS 0
+#define DISPATCH_SAVE 1
+#define DISPATCH_CLOSEDOC 2
+#define DISPATCH_CLOSEWIN 3
+#define DISPATCH_CLOSEFRAME 4
+#define DISPATCH_RELOAD 5
+// the OSL_ENSURE in CTOR has to be changed too, when adding new defines
+
+void OInterceptor::dispose()
+{
+ EventObject aEvt( *this );
+
+ osl::MutexGuard aGuard(m_aMutex);
+
+ if ( m_pStatCL )
+ m_pStatCL->disposeAndClear( aEvt );
+
+ m_xSlaveDispatchProvider.clear();
+ m_xMasterDispatchProvider.clear();
+
+ m_pContentHolder = nullptr;
+}
+
+
+OInterceptor::OInterceptor( ODocumentDefinition* _pContentHolder )
+ :m_pContentHolder( _pContentHolder )
+ ,m_aInterceptedURL{ /* DISPATCH_SAVEAS */ ".uno:SaveAs",
+ /* DISPATCH_SAVE */ ".uno:Save",
+ /* DISPATCH_CLOSEDOC */ ".uno:CloseDoc",
+ /* DISPATCH_CLOSEWIN */ ".uno:CloseWin",
+ /* DISPATCH_CLOSEFRAME */ ".uno:CloseFrame",
+ /* DISPATCH_RELOAD */ ".uno:Reload" }
+{
+ OSL_ENSURE(DISPATCH_RELOAD < m_aInterceptedURL.getLength(),"Illegal size.");
+}
+
+
+OInterceptor::~OInterceptor()
+{
+}
+
+namespace {
+
+struct DispatchHelper
+{
+ URL aURL;
+ Sequence<PropertyValue > aArguments;
+};
+
+}
+
+//XDispatch
+void SAL_CALL OInterceptor::dispatch( const URL& URL,const Sequence<PropertyValue >& Arguments )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_pContentHolder )
+ return;
+
+ if ( URL.Complete == m_aInterceptedURL[ DISPATCH_SAVE ] )
+ {
+ m_pContentHolder->save(false, css::uno::Reference<css::awt::XTopWindow>());
+ return;
+ }
+
+ if ( URL.Complete == m_aInterceptedURL[ DISPATCH_RELOAD ] )
+ {
+ ODocumentDefinition::fillReportData(
+ m_pContentHolder->getContext(),
+ m_pContentHolder->getComponent(),
+ m_pContentHolder->getConnection()
+ );
+ return;
+ }
+
+ if( URL.Complete == m_aInterceptedURL[ DISPATCH_SAVEAS ] )
+ {
+ if ( m_pContentHolder->isNewReport() )
+ {
+ m_pContentHolder->saveAs();
+ }
+ else if ( m_xSlaveDispatchProvider.is() )
+ {
+ Sequence< PropertyValue > aNewArgs = Arguments;
+ sal_Int32 nInd = 0;
+
+ while( nInd < aNewArgs.getLength() )
+ {
+ if ( aNewArgs[nInd].Name == "SaveTo" )
+ {
+ aNewArgs.getArray()[nInd].Value <<= true;
+ break;
+ }
+ nInd++;
+ }
+
+ if ( nInd == aNewArgs.getLength() )
+ {
+ aNewArgs.realloc( nInd + 1 );
+ auto pNewArgs = aNewArgs.getArray();
+ pNewArgs[nInd].Name = "SaveTo";
+ pNewArgs[nInd].Value <<= true;
+ }
+
+ Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch(URL, "_self", 0 );
+ if ( xDispatch.is() )
+ xDispatch->dispatch( URL, aNewArgs );
+ }
+ return;
+ }
+
+ if ( URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEDOC ]
+ || URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEWIN ]
+ || URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEFRAME ]
+ )
+ {
+ DispatchHelper* pHelper = new DispatchHelper;
+ pHelper->aArguments = Arguments;
+ pHelper->aURL = URL;
+ Application::PostUserEvent( LINK( this, OInterceptor, OnDispatch ), pHelper );
+ return;
+ }
+}
+
+IMPL_LINK( OInterceptor, OnDispatch, void*, _pDispatcher, void )
+{
+ std::unique_ptr<DispatchHelper> pHelper( static_cast< DispatchHelper* >( _pDispatcher ) );
+ try
+ {
+ if ( m_pContentHolder && m_pContentHolder->prepareClose() && m_xSlaveDispatchProvider.is() )
+ {
+ Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch(pHelper->aURL, "_self", 0 );
+ if ( xDispatch.is() )
+ {
+ Reference< XInterface > xKeepContentHolderAlive( *m_pContentHolder );
+ xDispatch->dispatch( pHelper->aURL,pHelper->aArguments);
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OInterceptor::addStatusListener(
+ const Reference<
+ XStatusListener >& Control,
+ const URL& URL )
+{
+ if(!Control.is())
+ return;
+
+ if ( m_pContentHolder && URL.Complete == m_aInterceptedURL[DISPATCH_SAVEAS] )
+ { // SaveAs
+
+ if ( !m_pContentHolder->isNewReport() )
+ {
+ FeatureStateEvent aStateEvent;
+ aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVEAS];
+ aStateEvent.FeatureDescriptor = "SaveCopyTo";
+ aStateEvent.IsEnabled = true;
+ aStateEvent.Requery = false;
+ aStateEvent.State <<= OUString("($3)");
+ Control->statusChanged(aStateEvent);
+ }
+
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if(!m_pStatCL)
+ m_pStatCL.reset( new StatusListenerContainer(m_aMutex) );
+ }
+
+ m_pStatCL->addInterface(URL.Complete,Control);
+ }
+ else if ( m_pContentHolder && URL.Complete == m_aInterceptedURL[DISPATCH_SAVE] )
+ { // Save
+ FeatureStateEvent aStateEvent;
+ aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVE];
+ aStateEvent.FeatureDescriptor = "Update";
+ aStateEvent.IsEnabled = true;
+ aStateEvent.Requery = false;
+
+ Control->statusChanged(aStateEvent);
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if(!m_pStatCL)
+ m_pStatCL.reset( new StatusListenerContainer(m_aMutex) );
+ }
+
+ m_pStatCL->addInterface(URL.Complete,Control);
+ }
+ else
+ {
+ sal_Int32 i = 2;
+ if(URL.Complete == m_aInterceptedURL[i] ||
+ URL.Complete == m_aInterceptedURL[++i] ||
+ URL.Complete == m_aInterceptedURL[++i] ||
+ URL.Complete == m_aInterceptedURL[i = DISPATCH_RELOAD] )
+ { // Close and return
+ FeatureStateEvent aStateEvent;
+ aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
+ aStateEvent.FeatureDescriptor = "Close and Return";
+ aStateEvent.IsEnabled = true;
+ aStateEvent.Requery = false;
+ Control->statusChanged(aStateEvent);
+
+
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if(!m_pStatCL)
+ m_pStatCL.reset( new StatusListenerContainer(m_aMutex) );
+ }
+
+ m_pStatCL->addInterface(URL.Complete,Control);
+ return;
+ }
+ }
+}
+
+
+void SAL_CALL OInterceptor::removeStatusListener(
+ const Reference<
+ XStatusListener >& Control,
+ const URL& URL )
+{
+ if(!(Control.is() && m_pStatCL))
+ return;
+ else
+ {
+ m_pStatCL->removeInterface(URL.Complete,Control);
+ return;
+ }
+}
+
+
+//XInterceptorInfo
+Sequence< OUString > SAL_CALL OInterceptor::getInterceptedURLs( )
+{
+ // now implemented as update
+ return m_aInterceptedURL;
+}
+
+
+// XDispatchProvider
+
+Reference< XDispatch > SAL_CALL OInterceptor::queryDispatch( const URL& URL,const OUString& TargetFrameName,sal_Int32 SearchFlags )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ const OUString* pIter = m_aInterceptedURL.getConstArray();
+ const OUString* pEnd = pIter + m_aInterceptedURL.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( URL.Complete == *pIter )
+ return static_cast<XDispatch*>(this);
+ }
+
+ if(m_xSlaveDispatchProvider.is())
+ return m_xSlaveDispatchProvider->queryDispatch(URL,TargetFrameName,SearchFlags);
+ else
+ return Reference<XDispatch>();
+}
+
+Sequence< Reference< XDispatch > > SAL_CALL OInterceptor::queryDispatches( const Sequence<DispatchDescriptor >& Requests )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ typedef Sequence<Reference<XDispatch>> DispatchSeq;
+ DispatchSeq aRet = m_xSlaveDispatchProvider.is() ?
+ m_xSlaveDispatchProvider->queryDispatches(Requests) :
+ DispatchSeq(Requests.getLength());
+
+ auto aRetRange = asNonConstRange(aRet);
+ for(sal_Int32 i = 0; i < Requests.getLength(); ++i)
+ {
+ const OUString* pIter = m_aInterceptedURL.getConstArray();
+ const OUString* pEnd = pIter + m_aInterceptedURL.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( Requests[i].FeatureURL.Complete == *pIter )
+ {
+ aRetRange[i] = static_cast<XDispatch*>(this);
+ break;
+ }
+ }
+ }
+
+ return aRet;
+}
+
+
+//XDispatchProviderInterceptor
+
+Reference< XDispatchProvider > SAL_CALL OInterceptor::getSlaveDispatchProvider( )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ return m_xSlaveDispatchProvider;
+}
+
+void SAL_CALL
+OInterceptor::setSlaveDispatchProvider( const Reference< XDispatchProvider >& NewDispatchProvider )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ m_xSlaveDispatchProvider = NewDispatchProvider;
+}
+
+
+Reference< XDispatchProvider > SAL_CALL OInterceptor::getMasterDispatchProvider( )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ return m_xMasterDispatchProvider;
+}
+
+
+void SAL_CALL OInterceptor::setMasterDispatchProvider(
+ const Reference< XDispatchProvider >& NewSupplier )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ m_xMasterDispatchProvider = NewSupplier;
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/intercept.hxx b/dbaccess/source/core/dataaccess/intercept.hxx
new file mode 100644
index 000000000..7ce53752f
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/intercept.hxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <osl/mutex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/interfacecontainer.hxx>
+#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
+#include <com/sun/star/frame/XInterceptorInfo.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include "documentdefinition.hxx"
+#include <vcl/svapp.hxx>
+
+namespace dbaccess
+{
+
+
+class OInterceptor : public ::cppu::WeakImplHelper< css::frame::XDispatchProviderInterceptor,
+ css::frame::XInterceptorInfo,
+ css::frame::XDispatch >
+{
+ DECL_LINK( OnDispatch, void*, void );
+protected:
+ virtual ~OInterceptor() override;
+public:
+
+ explicit OInterceptor( ODocumentDefinition* _pContentHolder );
+
+ /// @throws css::uno::RuntimeException
+ void dispose();
+
+ //XDispatch
+ virtual void SAL_CALL
+ dispatch(
+ const css::util::URL& URL,
+ const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ virtual void SAL_CALL
+ addStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& Control,
+ const css::util::URL& URL ) override;
+
+ virtual void SAL_CALL
+ removeStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& Control,
+ const css::util::URL& URL ) override;
+
+ //XInterceptorInfo
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getInterceptedURLs( ) override;
+
+ //XDispatchProvider ( inherited by XDispatchProviderInterceptor )
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL
+ queryDispatch(
+ const css::util::URL& URL,
+ const OUString& TargetFrameName,
+ sal_Int32 SearchFlags ) override;
+
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL
+ queryDispatches(
+ const css::uno::Sequence< css::frame::DispatchDescriptor >& Requests ) override;
+
+ //XDispatchProviderInterceptor
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL
+ getSlaveDispatchProvider( ) override;
+
+ virtual void SAL_CALL
+ setSlaveDispatchProvider(
+ const css::uno::Reference< css::frame::XDispatchProvider >& NewDispatchProvider ) override;
+
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL
+ getMasterDispatchProvider( ) override;
+
+ virtual void SAL_CALL
+ setMasterDispatchProvider(
+ const css::uno::Reference< css::frame::XDispatchProvider >& NewSupplier ) override;
+
+private:
+
+ osl::Mutex m_aMutex;
+
+ ODocumentDefinition* m_pContentHolder;
+
+ css::uno::Reference< css::frame::XDispatchProvider > m_xSlaveDispatchProvider;
+ css::uno::Reference< css::frame::XDispatchProvider > m_xMasterDispatchProvider;
+
+ css::uno::Sequence< OUString > m_aInterceptedURL;
+
+ typedef comphelper::OMultiTypeInterfaceContainerHelperVar3<css::frame::XStatusListener, OUString>
+ StatusListenerContainer;
+ std::unique_ptr<StatusListenerContainer> m_pStatCL;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx
new file mode 100644
index 000000000..e0d32d569
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx
@@ -0,0 +1,330 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+
+#include <ucbhelper/contentidentifier.hxx>
+
+#include "myucp_datasupplier.hxx"
+#include <ContentHelper.hxx>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::container;
+
+// @@@ Adjust namespace name.
+using namespace dbaccess;
+
+// @@@ Adjust namespace name.
+namespace dbaccess
+{
+
+namespace {
+
+// struct ResultListEntry.
+struct ResultListEntry
+{
+ OUString aId;
+ Reference< XContentIdentifier > xId;
+ ::rtl::Reference< OContentHelper > xContent;
+ Reference< XRow > xRow;
+ const ContentProperties& rData;
+
+ explicit ResultListEntry(const ContentProperties& rEntry) : rData( rEntry ) {}
+};
+
+}
+
+// struct DataSupplier_Impl.
+struct DataSupplier_Impl
+{
+ osl::Mutex m_aMutex;
+ std::vector< std::unique_ptr<ResultListEntry> > m_aResults;
+ rtl::Reference< ODocumentContainer > m_xContent;
+ bool m_bCountFinal;
+
+ explicit DataSupplier_Impl(const rtl::Reference< ODocumentContainer >& rContent)
+ : m_xContent(rContent)
+ , m_bCountFinal(false)
+ {
+ }
+};
+
+}
+
+// DataSupplier Implementation.
+
+DataSupplier::DataSupplier( const rtl::Reference< ODocumentContainer >& rContent )
+: m_pImpl( new DataSupplier_Impl( rContent ) )
+{
+
+}
+
+DataSupplier::~DataSupplier()
+{
+
+}
+
+OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ OUString aId = m_pImpl->m_aResults[ nIndex ]->aId;
+ if ( !aId.isEmpty() )
+ {
+ // Already cached.
+ return aId;
+ }
+ }
+
+ if ( getResult( nIndex ) )
+ {
+ OUString aId = m_pImpl->m_xContent->getIdentifier()->getContentIdentifier();
+
+ if ( !aId.isEmpty() )
+ aId += "/";
+
+ aId += m_pImpl->m_aResults[ nIndex ]->rData.aTitle;
+
+ m_pImpl->m_aResults[ nIndex ]->aId = aId;
+ return aId;
+ }
+ return OUString();
+}
+
+Reference< XContentIdentifier >
+DataSupplier::queryContentIdentifier( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ Reference< XContentIdentifier > xId = m_pImpl->m_aResults[ nIndex ]->xId;
+ if ( xId.is() )
+ {
+ // Already cached.
+ return xId;
+ }
+ }
+
+ OUString aId = queryContentIdentifierString( nIndex );
+ if ( !aId.isEmpty() )
+ {
+ Reference< XContentIdentifier > xId = new ::ucbhelper::ContentIdentifier( aId );
+ m_pImpl->m_aResults[ nIndex ]->xId = xId;
+ return xId;
+ }
+ return Reference< XContentIdentifier >();
+}
+
+Reference< XContent >
+DataSupplier::queryContent( sal_uInt32 _nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(_nIndex) < m_pImpl->m_aResults.size() )
+ {
+ Reference< XContent > xContent = m_pImpl->m_aResults[ _nIndex ]->xContent;
+ if ( xContent.is() )
+ {
+ // Already cached.
+ return xContent;
+ }
+ }
+
+ Reference< XContentIdentifier > xId = queryContentIdentifier( _nIndex );
+ if ( xId.is() )
+ {
+ try
+ {
+ Reference< XContent > xContent;
+ OUString sName = xId->getContentIdentifier();
+ sName = sName.copy(sName.lastIndexOf('/')+1);
+
+ m_pImpl->m_aResults[ _nIndex ]->xContent = m_pImpl->m_xContent->getContent(sName);
+
+ xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get();
+ return xContent;
+
+ }
+ catch ( IllegalIdentifierException& )
+ {
+ }
+ }
+ return Reference< XContent >();
+}
+
+bool DataSupplier::getResult( sal_uInt32 nIndex )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ // Result already present.
+ return true;
+ }
+
+ // Result not (yet) present.
+
+ if ( m_pImpl->m_bCountFinal )
+ return false;
+
+ // Try to obtain result...
+
+ sal_uInt32 nOldCount = m_pImpl->m_aResults.size();
+ bool bFound = false;
+ sal_uInt32 nPos = nOldCount;
+
+ // @@@ Obtain data and put it into result list...
+ Sequence< OUString> aSeq = m_pImpl->m_xContent->getElementNames();
+ if ( nIndex < sal::static_int_cast< sal_uInt32 >( aSeq.getLength() ) )
+ {
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(pIter = pIter + nPos;pIter != pEnd;++pIter,++nPos)
+ {
+ m_pImpl->m_aResults.emplace_back(
+ new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );
+
+ if ( nPos == nIndex )
+ {
+ // Result obtained.
+ bFound = true;
+ break;
+ }
+ }
+ }
+
+ if ( !bFound )
+ m_pImpl->m_bCountFinal = true;
+
+ rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet();
+ if ( xResultSet.is() )
+ {
+ // Callbacks follow!
+ aGuard.clear();
+
+ if ( static_cast<size_t>(nOldCount) < m_pImpl->m_aResults.size() )
+ xResultSet->rowCountChanged(
+ nOldCount, m_pImpl->m_aResults.size() );
+
+ if ( m_pImpl->m_bCountFinal )
+ xResultSet->rowCountFinal();
+ }
+
+ return bFound;
+}
+
+sal_uInt32 DataSupplier::totalCount()
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( m_pImpl->m_bCountFinal )
+ return m_pImpl->m_aResults.size();
+
+ sal_uInt32 nOldCount = m_pImpl->m_aResults.size();
+
+ // @@@ Obtain data and put it into result list...
+ Sequence< OUString> aSeq = m_pImpl->m_xContent->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ m_pImpl->m_aResults.emplace_back(
+ new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );
+
+ m_pImpl->m_bCountFinal = true;
+
+ rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet();
+ if ( xResultSet.is() )
+ {
+ // Callbacks follow!
+ aGuard.clear();
+
+ if ( static_cast<size_t>(nOldCount) < m_pImpl->m_aResults.size() )
+ xResultSet->rowCountChanged(
+ nOldCount, m_pImpl->m_aResults.size() );
+
+ xResultSet->rowCountFinal();
+ }
+
+ return m_pImpl->m_aResults.size();
+}
+
+sal_uInt32 DataSupplier::currentCount()
+{
+ return m_pImpl->m_aResults.size();
+}
+
+bool DataSupplier::isCountFinal()
+{
+ return m_pImpl->m_bCountFinal;
+}
+
+Reference< XRow >
+DataSupplier::queryPropertyValues( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow;
+ if ( xRow.is() )
+ {
+ // Already cached.
+ return xRow;
+ }
+ }
+
+ if ( getResult( nIndex ) )
+ {
+ if ( !m_pImpl->m_aResults[ nIndex ]->xContent.is() )
+ queryContent(nIndex);
+
+ Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xContent->getPropertyValues(getResultSet()->getProperties());
+ m_pImpl->m_aResults[ nIndex ]->xRow = xRow;
+ return xRow;
+ }
+
+ return Reference< XRow >();
+}
+
+void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ m_pImpl->m_aResults[ nIndex ]->xRow.clear();
+}
+
+void DataSupplier::close()
+{
+}
+
+void DataSupplier::validate()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx
new file mode 100644
index 000000000..8083f5ef5
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <ucbhelper/resultset.hxx>
+#include "documentcontainer.hxx"
+#include <memory>
+
+namespace dbaccess
+{
+struct DataSupplier_Impl;
+
+class DataSupplier : public ucbhelper::ResultSetDataSupplier
+{
+ std::unique_ptr<DataSupplier_Impl> m_pImpl;
+
+public:
+ explicit DataSupplier(const rtl::Reference<ODocumentContainer>& rxContent);
+ virtual ~DataSupplier() override;
+
+ virtual OUString queryContentIdentifierString(sal_uInt32 nIndex) override;
+ virtual css::uno::Reference<css::ucb::XContentIdentifier>
+ queryContentIdentifier(sal_uInt32 nIndex) override;
+ virtual css::uno::Reference<css::ucb::XContent> queryContent(sal_uInt32 nIndex) override;
+
+ virtual bool getResult(sal_uInt32 nIndex) override;
+
+ virtual sal_uInt32 totalCount() override;
+ virtual sal_uInt32 currentCount() override;
+ virtual bool isCountFinal() override;
+
+ virtual css::uno::Reference<css::sdbc::XRow> queryPropertyValues(sal_uInt32 nIndex) override;
+ virtual void releasePropertyValues(sal_uInt32 nIndex) override;
+
+ virtual void close() override;
+
+ virtual void validate() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.cxx b/dbaccess/source/core/dataaccess/myucp_resultset.cxx
new file mode 100644
index 000000000..67c1ad7c8
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_resultset.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ - This implementation is not a dynamic result set!!! It only implements
+ the necessary interfaces, but never recognizes/notifies changes!!!
+
+ *************************************************************************/
+
+#include "myucp_datasupplier.hxx"
+#include "myucp_resultset.hxx"
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::container;
+
+using namespace dbaccess;
+
+// DynamicResultSet Implementation.
+DynamicResultSet::DynamicResultSet(
+ const Reference< XComponentContext >& rxContext,
+ const rtl::Reference< ODocumentContainer >& rxContent,
+ const OpenCommandArgument2& rCommand,
+ const Reference< XCommandEnvironment >& rxEnv )
+ :ResultSetImplHelper( rxContext, rCommand )
+ ,m_xContent(rxContent)
+ ,m_xEnv( rxEnv )
+{
+}
+
+// Non-interface methods.
+void DynamicResultSet::initStatic()
+{
+ m_xResultSet1
+ = new ::ucbhelper::ResultSet( m_xContext,
+ m_aCommand.Properties,
+ new DataSupplier( m_xContent ),
+ m_xEnv );
+}
+
+void DynamicResultSet::initDynamic()
+{
+ m_xResultSet1
+ = new ::ucbhelper::ResultSet( m_xContext,
+ m_aCommand.Properties,
+ new DataSupplier( m_xContent ),
+ m_xEnv );
+ m_xResultSet2 = m_xResultSet1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.hxx b/dbaccess/source/core/dataaccess/myucp_resultset.hxx
new file mode 100644
index 000000000..ae269ffb8
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_resultset.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <ucbhelper/resultsethelper.hxx>
+#include "documentcontainer.hxx"
+
+
+// @@@ Adjust namespace name.
+namespace dbaccess {
+
+class DynamicResultSet : public ::ucbhelper::ResultSetImplHelper
+{
+ rtl::Reference< ODocumentContainer > m_xContent;
+ css::uno::Reference< css::ucb::XCommandEnvironment > m_xEnv;
+
+private:
+ virtual void initStatic() override;
+ virtual void initDynamic() override;
+
+public:
+ DynamicResultSet(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const rtl::Reference< ODocumentContainer >& rxContent,
+ const css::ucb::OpenCommandArgument2& rCommand,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& rxEnv );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/ContainerMediator.hxx b/dbaccess/source/core/inc/ContainerMediator.hxx
new file mode 100644
index 000000000..37bfc0eba
--- /dev/null
+++ b/dbaccess/source/core/inc/ContainerMediator.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <map>
+
+namespace dbaccess
+{
+
+ class OPropertyForward;
+
+ class OContainerMediator : public ::cppu::BaseMutex
+ ,public ::cppu::WeakImplHelper< css::container::XContainerListener >
+ {
+ private:
+ typedef std::map< OUString, ::rtl::Reference< OPropertyForward > > PropertyForwardList;
+ PropertyForwardList m_aForwardList;
+ css::uno::Reference< css::container::XNameAccess > m_xSettings; // can not be weak
+ css::uno::Reference< css::container::XContainer > m_xContainer; // can not be weak
+
+ protected:
+ virtual ~OContainerMediator() override;
+
+ public:
+ OContainerMediator(
+ const css::uno::Reference< css::container::XContainer >& _xContainer,
+ const css::uno::Reference< css::container::XNameAccess >& _xSettings
+ );
+
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ void notifyElementCreated(const OUString& _sElementName
+ ,const css::uno::Reference< css::beans::XPropertySet>& _xElement);
+
+ private:
+ /** cleans up the instance, by deregistering as listener at the containers,
+ and resetting them to <NULL/>
+ */
+ void impl_cleanup_nothrow();
+
+ /** initializes the properties of the given object from its counterpart in our settings container
+ */
+ void impl_initSettings_nothrow(
+ const OUString& _rName,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxDestination
+ );
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/ContentHelper.hxx b/dbaccess/source/core/inc/ContentHelper.hxx
new file mode 100644
index 000000000..004b785ef
--- /dev/null
+++ b/dbaccess/source/core/inc/ContentHelper.hxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/multiinterfacecontainer3.hxx>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <connectivity/sqlerror.hxx>
+#include <memory>
+
+namespace com::sun::star::beans { struct PropertyValue; }
+
+namespace dbaccess
+{
+ class ODatabaseModelImpl;
+ struct ContentProperties
+ {
+ OUString aTitle; // Title
+ ::std::optional< OUString >
+ aContentType; // ContentType (aka MediaType aka MimeType)
+ bool bIsDocument; // IsDocument
+ bool bIsFolder; // IsFolder
+ bool bAsTemplate; // AsTemplate
+ OUString sPersistentName;// persistent name of the document
+
+ ContentProperties()
+ :bIsDocument( true )
+ ,bIsFolder( false )
+ ,bAsTemplate( false )
+ {
+ }
+ };
+
+ class OContentHelper_Impl
+ {
+ public:
+ OContentHelper_Impl();
+ virtual ~OContentHelper_Impl();
+
+ ContentProperties m_aProps;
+ ODatabaseModelImpl* m_pDataSource; // this will stay alive as long as the content exists
+ };
+
+ typedef std::shared_ptr<OContentHelper_Impl> TContentPtr;
+
+ typedef comphelper::OMultiTypeInterfaceContainerHelperVar3<css::beans::XPropertiesChangeListener, OUString>
+ PropertyChangeListenerContainer;
+ typedef ::cppu::WeakComponentImplHelper< css::ucb::XContent
+ , css::ucb::XCommandProcessor
+ , css::lang::XServiceInfo
+ , css::beans::XPropertiesChangeNotifier
+ , css::beans::XPropertyContainer
+ , css::lang::XInitialization
+ , css::lang::XUnoTunnel
+ , css::container::XChild
+ , css::sdbcx::XRename
+ > OContentHelper_COMPBASE;
+
+ class OContentHelper : public ::cppu::BaseMutex
+ ,public OContentHelper_COMPBASE
+ {
+ css::uno::Sequence< css::uno::Any >
+ setPropertyValues( const css::uno::Sequence< css::beans::PropertyValue >& rValues );
+
+ void impl_rename_throw(const OUString& _sNewName,bool _bNotify = true);
+
+ protected:
+ ::comphelper::OInterfaceContainerHelper3<css::ucb::XContentEventListener> m_aContentListeners;
+ PropertyChangeListenerContainer m_aPropertyChangeListeners;
+ css::uno::Reference< css::uno::XInterface >
+ m_xParentContainer;
+ const css::uno::Reference< css::uno::XComponentContext >
+ m_aContext;
+ const ::connectivity::SQLError m_aErrorHelper;
+ TContentPtr m_pImpl;
+ sal_uInt32 m_nCommandId;
+
+ // helper
+ virtual void SAL_CALL disposing() override;
+
+ void notifyDataSourceModified();
+
+ /**
+ * This method can be used to propagate changes of property values.
+ *
+ * @param evt is a sequence of property change events.
+ */
+ void notifyPropertiesChange( const css::uno::Sequence< css::beans::PropertyChangeEvent >& evt ) const;
+
+ OUString impl_getHierarchicalName( bool _includingRootContainer ) const;
+
+ public:
+
+ OContentHelper( const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ ,const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // css::lang::XServiceInfo
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // XContent
+ virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL getIdentifier( ) override ;
+ virtual OUString SAL_CALL getContentType( ) override ;
+ virtual void SAL_CALL addContentEventListener( const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override ;
+ virtual void SAL_CALL removeContentEventListener( const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override ;
+
+ // XCommandProcessor
+ virtual sal_Int32 SAL_CALL createCommandIdentifier( ) override ;
+ virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override ;
+ virtual void SAL_CALL abort( sal_Int32 CommandId ) override ;
+
+ // XPropertiesChangeNotifier
+ virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override ;
+ virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override ;
+
+ // XPropertyContainer
+ virtual void SAL_CALL addProperty( const OUString& Name, sal_Int16 Attributes, const css::uno::Any& DefaultValue ) override ;
+ virtual void SAL_CALL removeProperty( const OUString& Name ) override ;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ const ContentProperties& getContentProperties() const { return m_pImpl->m_aProps; }
+ css::uno::Reference< css::sdbc::XRow >
+ getPropertyValues( const css::uno::Sequence< css::beans::Property >& rProperties );
+
+ const css::uno::Reference< css::uno::XComponentContext >& getContext() const { return m_aContext; }
+
+ const TContentPtr& getImpl() const { return m_pImpl; }
+
+ protected:
+ virtual OUString determineContentType() const = 0;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/DatabaseDataProvider.hxx b/dbaccess/source/core/inc/DatabaseDataProvider.hxx
new file mode 100644
index 000000000..8c2029634
--- /dev/null
+++ b/dbaccess/source/core/inc/DatabaseDataProvider.hxx
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
+#include <com/sun/star/chart2/XInternalDataProvider.hpp>
+#include <com/sun/star/chart/XComplexDescriptionAccess.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/propertysetmixin.hxx>
+
+#include <connectivity/parameters.hxx>
+#include <connectivity/filtermanager.hxx>
+
+
+namespace dbaccess
+{
+
+typedef ::cppu::WeakComponentImplHelper< css::chart2::data::XDatabaseDataProvider
+ , css::container::XChild
+ , css::chart::XComplexDescriptionAccess
+ , css::lang::XServiceInfo > TDatabaseDataProvider;
+
+class DatabaseDataProvider: private ::cppu::BaseMutex,
+ public TDatabaseDataProvider,
+ public ::cppu::PropertySetMixin< css::chart2::data::XDatabaseDataProvider >
+{
+public:
+ explicit DatabaseDataProvider(css::uno::Reference< css::uno::XComponentContext > const & context);
+
+private:
+ // css::uno::XInterface:
+ virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) override;
+ virtual void SAL_CALL acquire() noexcept override
+ { TDatabaseDataProvider::acquire(); }
+ virtual void SAL_CALL release() noexcept override
+ { TDatabaseDataProvider::release(); }
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::chart2::data::XDataProvider:
+ virtual sal_Bool SAL_CALL createDataSourcePossible(const css::uno::Sequence< css::beans::PropertyValue > & aArguments) override;
+ virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource(const css::uno::Sequence< css::beans::PropertyValue > & aArguments) override;
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments(const css::uno::Reference< css::chart2::data::XDataSource > & xDataSource) override;
+ virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible(const OUString & aRangeRepresentation) override;
+ virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation(const OUString & aRangeRepresentation) override;
+
+ virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
+ createDataSequenceByValueArray(
+ const OUString& aRole, const OUString & aRangeRepresentation, const OUString& aRoleQualifier) override;
+
+ virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override;
+
+ // css::chart2::data::XRangeXMLConversion:
+ virtual OUString SAL_CALL convertRangeToXML(const OUString & aRangeRepresentation) override;
+ virtual OUString SAL_CALL convertRangeFromXML(const OUString & aXMLRange) override;
+
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override;
+
+ // css::beans::XPropertySet:
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue(const OUString & aPropertyName, const css::uno::Any & aValue) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue(const OUString & PropertyName) override;
+ virtual void SAL_CALL addPropertyChangeListener(const OUString & aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > & xListener) override;
+ virtual void SAL_CALL removePropertyChangeListener(const OUString & aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > & aListener) override;
+ virtual void SAL_CALL addVetoableChangeListener(const OUString & PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > & aListener) override;
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString & PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > & aListener) override;
+
+ // css::chart2::data::XDatabaseDataProvider:
+ virtual css::uno::Sequence< OUString > SAL_CALL getMasterFields() override;
+ virtual void SAL_CALL setMasterFields(const css::uno::Sequence< OUString > & the_value) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getDetailFields() override;
+ virtual void SAL_CALL setDetailFields(const css::uno::Sequence< OUString > & the_value) override;
+ virtual OUString SAL_CALL getCommand() override;
+ virtual void SAL_CALL setCommand(const OUString & the_value) override;
+ virtual ::sal_Int32 SAL_CALL getCommandType() override;
+ virtual void SAL_CALL setCommandType(::sal_Int32 the_value) override;
+ virtual OUString SAL_CALL getFilter() override;
+ virtual void SAL_CALL setFilter(const OUString & the_value) override;
+ virtual sal_Bool SAL_CALL getApplyFilter() override;
+ virtual void SAL_CALL setApplyFilter( sal_Bool _applyfilter ) override;
+ virtual OUString SAL_CALL getHavingClause() override;
+ virtual void SAL_CALL setHavingClause( const OUString& _havingclause ) override;
+ virtual OUString SAL_CALL getGroupBy() override;
+ virtual void SAL_CALL setGroupBy( const OUString& _groupby ) override;
+ virtual OUString SAL_CALL getOrder() override;
+ virtual void SAL_CALL setOrder( const OUString& _order ) override;
+ virtual sal_Bool SAL_CALL getEscapeProcessing() override;
+ virtual void SAL_CALL setEscapeProcessing(sal_Bool the_value) override;
+ virtual ::sal_Int32 SAL_CALL getRowLimit() override;
+ virtual void SAL_CALL setRowLimit( ::sal_Int32 _rowlimit ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getActiveConnection() override;
+ virtual void SAL_CALL setActiveConnection(const css::uno::Reference< css::sdbc::XConnection > & the_value) override;
+ virtual OUString SAL_CALL getDataSourceName() override;
+ virtual void SAL_CALL setDataSourceName( const OUString& _datasourcename ) override;
+
+ // css::sdbc::XParameters
+ virtual void SAL_CALL setNull(sal_Int32 parameterIndex, sal_Int32 sqlType) override;
+ virtual void SAL_CALL setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName) override;
+ virtual void SAL_CALL setBoolean(sal_Int32 parameterIndex, sal_Bool x) override;
+ virtual void SAL_CALL setByte(sal_Int32 parameterIndex, sal_Int8 x) override;
+ virtual void SAL_CALL setShort(sal_Int32 parameterIndex, sal_Int16 x) override;
+ virtual void SAL_CALL setInt(sal_Int32 parameterIndex, sal_Int32 x) override;
+ virtual void SAL_CALL setLong(sal_Int32 parameterIndex, sal_Int64 x) override;
+ virtual void SAL_CALL setFloat(sal_Int32 parameterIndex, float x) override;
+ virtual void SAL_CALL setDouble(sal_Int32 parameterIndex, double x) override;
+ virtual void SAL_CALL setString(sal_Int32 parameterIndex, const OUString& x) override;
+ virtual void SAL_CALL setBytes(sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x) override;
+ virtual void SAL_CALL setDate(sal_Int32 parameterIndex, const css::util::Date& x) override;
+ virtual void SAL_CALL setTime(sal_Int32 parameterIndex, const css::util::Time& x) override;
+ virtual void SAL_CALL setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x) override;
+ virtual void SAL_CALL setBinaryStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length) override;
+ virtual void SAL_CALL setCharacterStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length) override;
+ virtual void SAL_CALL setObject(sal_Int32 parameterIndex, const css::uno::Any& x) override;
+ virtual void SAL_CALL setObjectWithInfo(sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale) override;
+ virtual void SAL_CALL setRef(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef>& x) override;
+ virtual void SAL_CALL setBlob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob>& x) override;
+ virtual void SAL_CALL setClob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob>& x) override;
+ virtual void SAL_CALL setArray(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray>& x) override;
+ virtual void SAL_CALL clearParameters() override;
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute() override;
+ virtual void SAL_CALL addRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener>& _rxListener) override;
+ virtual void SAL_CALL removeRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener>& _rxListener) override;
+
+ // css::sdbc::XResultSet
+ virtual sal_Bool SAL_CALL next() override;
+ virtual sal_Bool SAL_CALL isBeforeFirst() override;
+ virtual sal_Bool SAL_CALL isAfterLast() override;
+ virtual sal_Bool SAL_CALL isFirst() override;
+ virtual sal_Bool SAL_CALL isLast() override;
+ virtual void SAL_CALL beforeFirst() override;
+ virtual void SAL_CALL afterLast() override;
+ virtual sal_Bool SAL_CALL first() override;
+ virtual sal_Bool SAL_CALL last() override;
+ virtual sal_Int32 SAL_CALL getRow() override;
+ virtual sal_Bool SAL_CALL absolute(sal_Int32 row) override;
+ virtual sal_Bool SAL_CALL relative(sal_Int32 rows) override;
+ virtual sal_Bool SAL_CALL previous() override;
+ virtual void SAL_CALL refreshRow() override;
+ virtual sal_Bool SAL_CALL rowUpdated() override;
+ virtual sal_Bool SAL_CALL rowInserted() override;
+ virtual sal_Bool SAL_CALL rowDeleted() override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement() override;
+
+ // container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ // ____ XComplexDescriptionAccess ____
+ virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL getComplexRowDescriptions() override;
+ virtual void SAL_CALL setComplexRowDescriptions( const css::uno::Sequence< css::uno::Sequence< OUString > >& aRowDescriptions ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL getComplexColumnDescriptions() override;
+ virtual void SAL_CALL setComplexColumnDescriptions( const css::uno::Sequence< css::uno::Sequence< OUString > >& aColumnDescriptions ) override;
+
+ // ____ XChartDataArray (base of XComplexDescriptionAccess) ____
+ virtual css::uno::Sequence< css::uno::Sequence< double > > SAL_CALL getData() override;
+ virtual void SAL_CALL setData( const css::uno::Sequence< css::uno::Sequence< double > >& aData ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getRowDescriptions() override;
+ virtual void SAL_CALL setRowDescriptions( const css::uno::Sequence< OUString >& aRowDescriptions ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getColumnDescriptions() override;
+ virtual void SAL_CALL setColumnDescriptions( const css::uno::Sequence< OUString >& aColumnDescriptions ) override;
+
+ // ____ XChartData (base of XChartDataArray) ____
+ virtual void SAL_CALL addChartDataChangeEventListener(const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override;
+ virtual void SAL_CALL removeChartDataChangeEventListener(const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override;
+ virtual double SAL_CALL getNotANumber() override;
+ virtual sal_Bool SAL_CALL isNotANumber(double nNumber ) override;
+private:
+ DatabaseDataProvider(DatabaseDataProvider const &) = delete;
+ DatabaseDataProvider& operator =(DatabaseDataProvider const &) = delete;
+
+ virtual ~DatabaseDataProvider() override {}
+
+ // This function is called upon disposing the component,
+ // if your component needs special work when it becomes
+ // disposed, do it here.
+ virtual void SAL_CALL disposing() override;
+
+ void impl_fillRowSet_throw();
+ bool impl_fillParameters_nothrow( ::osl::ResettableMutexGuard& _rClearForNotifies);
+ void impl_fillInternalDataProvider_throw(bool _bHasCategories,const css::uno::Sequence< OUString >& i_aColumnNames);
+ void impl_invalidateParameter_nothrow();
+ css::uno::Any impl_getNumberFormatKey_nothrow(const OUString & _sRangeRepresentation) const;
+
+ template <typename T> void set( const OUString& _sProperty
+ ,const T& Value
+ ,T& _member)
+ {
+ BoundListeners l;
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( _member != Value )
+ {
+ prepareSet(_sProperty, css::uno::Any(_member), css::uno::Any(Value), &l);
+ _member = Value;
+ }
+ }
+ l.notify();
+ }
+
+ ::dbtools::ParameterManager m_aParameterManager;
+ ::dbtools::FilterManager m_aFilterManager;
+ std::map< OUString, css::uno::Any> m_aNumberFormats;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection;
+ css::uno::Reference< css::sdbc::XRowSet > m_xRowSet;
+ css::uno::Reference< css::chart2::XInternalDataProvider > m_xInternal;
+ css::uno::Reference< css::chart::XComplexDescriptionAccess > m_xComplexDescriptionAccess;
+ css::uno::Reference< css::chart2::data::XRangeXMLConversion> m_xRangeConversion;
+ css::uno::Reference< css::task::XInteractionHandler> m_xHandler;
+ // the object doin' most of the work - an SDB-rowset
+ css::uno::Reference< css::uno::XAggregation> m_xAggregate;
+ css::uno::Reference< css::beans::XPropertySet> m_xAggregateSet;
+ css::uno::Reference< css::uno::XInterface> m_xParent;
+ css::uno::Sequence< OUString > m_MasterFields;
+ css::uno::Sequence< OUString > m_DetailFields;
+
+ OUString m_Command;
+ OUString m_DataSourceName;
+ sal_Int32 m_CommandType;
+ sal_Int32 m_RowLimit;
+ OUString m_Filter;
+ OUString m_HavingClause;
+ OUString m_Order;
+ OUString m_GroupBy;
+ bool m_EscapeProcessing;
+ bool m_ApplyFilter;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/FilteredContainer.hxx b/dbaccess/source/core/inc/FilteredContainer.hxx
new file mode 100644
index 000000000..968f3a1d6
--- /dev/null
+++ b/dbaccess/source/core/inc/FilteredContainer.hxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <connectivity/sdbcx/VCollection.hxx>
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+ class IRefreshListener;
+
+ class OFilteredContainer : public ::connectivity::sdbcx::OCollection
+ {
+ private:
+ mutable bool m_bConstructed; // late ctor called
+
+ protected:
+ IRefreshListener* m_pRefreshListener;
+ std::atomic<std::size_t>& m_nInAppend;
+
+ // holds the original container which where set in construct but they can be null
+ css::uno::Reference< css::container::XNameAccess > m_xMasterContainer;
+ css::uno::WeakReference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ /** returns a string denoting the only type of tables allowed in this container, or an empty string
+ if there is no such restriction
+ */
+ virtual OUString getTableTypeRestriction() const = 0;
+
+ virtual void addMasterContainerListener(){}
+ virtual void removeMasterContainerListener(){}
+
+ // ::connectivity::sdbcx::OCollection
+ virtual void impl_refresh() override;
+
+ virtual OUString getNameForObject(const ::connectivity::sdbcx::ObjectType& _xObject) override;
+
+ /** tell the container to free all elements and all additional resources.<BR>
+ After using this method the object may be reconstructed by calling one of the <code>construct</code> methods.
+ */
+ virtual void disposing() override;
+
+ class EnsureReset
+ {
+ public:
+ EnsureReset( std::atomic<std::size_t>& _rValueLocation)
+ :m_rValue( _rValueLocation )
+ {
+ ++m_rValue;
+ }
+
+ ~EnsureReset()
+ {
+ --m_rValue;
+ }
+
+ private:
+ std::atomic<std::size_t>& m_rValue;
+ };
+
+ /** retrieve a table type filter to pass to <member scope="css::sdbc">XDatabaseMetaData::getTables</member>,
+ according to the current data source settings
+ */
+ void getAllTableTypeFilter( css::uno::Sequence< OUString >& /* [out] */ _rFilter ) const;
+
+ public:
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+ @param _rParent the object which acts as parent for the container.
+ all refcounting is rerouted to this object
+ @param _rMutex the access safety object of the parent
+ @param _rTableFilter restricts the visible tables by name
+ @param _rTableTypeFilter restricts the visible tables by type
+ @see construct
+ */
+ OFilteredContainer( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xCon,
+ bool _bCase,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend
+ );
+
+ void dispose() { disposing(); }
+
+ /** late ctor. The container will fill itself with the data got by the connection meta data, considering the
+ filters given (the connection is the parent object you passed in the ctor).
+ */
+ void construct(
+ const css::uno::Sequence< OUString >& _rTableFilter,
+ const css::uno::Sequence< OUString >& _rTableTypeFilter
+ );
+
+ /** late ctor. The container will fill itself with wrapper objects for the tables returned by the given
+ name container.
+ */
+ void construct(
+ const css::uno::Reference< css::container::XNameAccess >& _rxMasterContainer,
+ const css::uno::Sequence< OUString >& _rTableFilter,
+ const css::uno::Sequence< OUString >& _rTableTypeFilter
+ );
+
+ bool isInitialized() const { return m_bConstructed; }
+ };
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/ModelImpl.hxx b/dbaccess/source/core/inc/ModelImpl.hxx
new file mode 100644
index 000000000..b6e2fe729
--- /dev/null
+++ b/dbaccess/source/core/inc/ModelImpl.hxx
@@ -0,0 +1,542 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ContentHelper.hxx"
+#include "documentevents.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertyBag.hpp>
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/docmacromode.hxx>
+#include <sfx2/docstoragemodifylistener.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <rtl/ref.hxx>
+
+namespace comphelper
+{
+ class NamedValueCollection;
+}
+
+namespace dbaccess
+{
+
+typedef std::vector< css::uno::WeakReference< css::sdbc::XConnection > > OWeakConnectionArray;
+
+struct AsciiPropertyValue
+{
+ // note: the canonic member order would be AsciiName / DefaultValue, but
+ // this crashes on unxlngi6.pro, since there's a bug which somehow results in
+ // getDefaultDataSourceSettings returning corrupted Any instances then.
+ css::uno::Any DefaultValue;
+ const char* AsciiName;
+ const css::uno::Type& ValueType;
+
+ AsciiPropertyValue()
+ :DefaultValue( )
+ ,AsciiName( nullptr )
+ ,ValueType( ::cppu::UnoType<void>::get() )
+ {
+ }
+
+ AsciiPropertyValue( const char* _pAsciiName, const css::uno::Any& _rDefaultValue )
+ :DefaultValue( _rDefaultValue )
+ ,AsciiName( _pAsciiName )
+ ,ValueType( _rDefaultValue.getValueType() )
+ {
+ OSL_ENSURE( ValueType.getTypeClass() != css::uno::TypeClass_VOID,
+ "AsciiPropertyValue::AsciiPropertyValue: NULL values not allowed here, use the other CTOR for this!" );
+ }
+ AsciiPropertyValue( const char* _pAsciiName, const css::uno::Type& _rValeType )
+ :DefaultValue()
+ ,AsciiName( _pAsciiName )
+ ,ValueType( _rValeType )
+ {
+ OSL_ENSURE( ValueType.getTypeClass() != css::uno::TypeClass_VOID,
+ "AsciiPropertyValue::AsciiPropertyValue: VOID property values not supported!" );
+ }
+};
+
+class ODatabaseContext;
+class OSharedConnectionManager;
+
+// ODatabaseModelImpl
+typedef ::utl::SharedUNOComponent< css::embed::XStorage > SharedStorage;
+
+class ODatabaseContext;
+class DocumentStorageAccess;
+class OSharedConnectionManager;
+class ODatabaseModelImpl :public ::sfx2::IMacroDocumentAccess
+ ,public ::sfx2::IModifiableDocument
+{
+public:
+ enum ObjectType
+ {
+ E_FORM = 0,
+ E_REPORT = 1,
+ E_QUERY = 2,
+ E_TABLE = 3
+ };
+
+ enum EmbeddedMacros
+ {
+ // the database document (storage) itself contains macros
+ eDocumentWideMacros,
+ // there are sub document( storage)s containing macros
+ eSubDocumentMacros,
+ // there are no known macro( storage)s
+ eNoMacros
+ };
+
+private:
+ css::uno::WeakReference< css::frame::XModel > m_xModel;
+ css::uno::WeakReference< css::sdbc::XDataSource > m_xDataSource;
+
+ rtl::Reference<DocumentStorageAccess> m_pStorageAccess;
+ std::vector< TContentPtr > m_aContainer; // one for each ObjectType
+ ::sfx2::DocumentMacroMode m_aMacroMode;
+ sal_Int16 m_nImposedMacroExecMode;
+
+ css::uno::Reference< css::script::XStorageBasedLibraryContainer > m_xBasicLibraries;
+ css::uno::Reference< css::script::XStorageBasedLibraryContainer > m_xDialogLibraries;
+
+ SharedStorage m_xDocumentStorage;
+ ::rtl::Reference< ::sfx2::DocumentStorageModifyListener > m_pStorageModifyListener;
+ ODatabaseContext& m_rDBContext;
+ DocumentEventsData m_aDocumentEvents;
+
+ ::comphelper::NamedValueCollection m_aMediaDescriptor;
+ /// the URL the document was loaded from
+ OUString m_sDocFileLocation;
+
+ oslInterlockedCount m_refCount;
+
+ /// do we have any object (forms/reports) which contains macros?
+ ::std::optional< EmbeddedMacros > m_aEmbeddedMacros;
+
+ /// true if setting the Modified flag of the document is currently locked
+ bool m_bModificationLock;
+
+ /// true if and only if a database document existed previously (though meanwhile disposed), and was already initialized
+ bool m_bDocumentInitialized;
+
+ /** the URL which the document should report as its URL
+
+ This might differ from ->m_sDocFileLocation in case the document was loaded
+ as part of a crash recovery process. In this case, ->m_sDocFileLocation points to
+ the temporary file where the DB had been saved to, after a crash.
+ ->m_sDocumentURL then is the URL of the document which actually had
+ been recovered.
+ */
+ OUString m_sDocumentURL;
+
+ SignatureState m_nScriptingSignatureState;
+
+public:
+ OWeakConnectionArray m_aConnections;
+ const css::uno::Reference< css::uno::XComponentContext > m_aContext;
+
+public:
+ css::uno::WeakReference< css::container::XNameAccess > m_xCommandDefinitions;
+ css::uno::WeakReference< css::container::XNameAccess > m_xTableDefinitions;
+
+ css::uno::Reference< css::util::XNumberFormatsSupplier >
+ m_xNumberFormatsSupplier;
+ OUString m_sConnectURL;
+ OUString m_sName; // transient, our creator has to tell us the title
+ OUString m_sUser;
+ OUString m_aPassword; // transient !
+ OUString m_sFailedPassword;
+ css::uno::Sequence< css::beans::PropertyValue>
+ m_aLayoutInformation;
+ sal_Int32 m_nLoginTimeout;
+ bool m_bReadOnly : 1;
+ bool m_bPasswordRequired : 1;
+ bool m_bSuppressVersionColumns : 1;
+ bool m_bModified : 1;
+ bool m_bDocumentReadOnly : 1;
+ bool m_bMacroCallsSeenWhileLoading : 1;
+ css::uno::Reference< css::beans::XPropertyBag >
+ m_xSettings;
+ css::uno::Sequence< OUString > m_aTableFilter;
+ css::uno::Sequence< OUString > m_aTableTypeFilter;
+ OSharedConnectionManager* m_pSharedConnectionManager;
+ css::uno::Reference< css::lang::XEventListener >
+ m_xSharedConnectionManager;
+ css::uno::Reference<css::awt::XWindow>
+ m_xDialogParent;
+ sal_uInt16 m_nControllerLockCount;
+
+ void reset();
+
+ /** determines whether the database document has an embedded data storage
+ */
+ bool isEmbeddedDatabase() const { return m_sConnectURL.startsWith("sdbc:embedded:"); }
+
+ /** stores the embedded storage ("database")
+
+ @param _bPreventRootCommits
+ Normally, committing the embedded storage results in also committing the root storage
+ - this is an automatism for data safety reasons.
+ If you pass <TRUE/> here, committing the root storage is prevented for this particular
+ call.
+ @return <TRUE/> if the storage could be committed, otherwise <FALSE/>
+ */
+ bool commitEmbeddedStorage( bool _bPreventRootCommits = false );
+
+ /// commits all sub storages
+ void commitStorages();
+
+ ODatabaseModelImpl(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ ODatabaseContext& _pDBContext
+ );
+ virtual ~ODatabaseModelImpl();
+
+ ODatabaseModelImpl(
+ const OUString& _rRegistrationName,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ ODatabaseContext& _rDBContext
+ );
+
+ // XEventListener
+ /// @throws css::uno::RuntimeException
+ void disposing( const css::lang::EventObject& Source );
+
+ void setModified( bool bModified );
+
+ void dispose();
+
+ const OUString& getURL() const { return m_sDocumentURL; }
+ const OUString& getDocFileLocation() const { return m_sDocFileLocation; }
+
+ css::uno::Reference< css::embed::XStorage >
+ getStorage( const ObjectType _eType );
+
+// helper
+ const css::uno::Reference< css::util::XNumberFormatsSupplier >&
+ getNumberFormatsSupplier();
+
+ DocumentEventsData&
+ getDocumentEvents() { return m_aDocumentEvents; }
+
+ const ::comphelper::NamedValueCollection&
+ getMediaDescriptor() const { return m_aMediaDescriptor; }
+
+ void setResource(
+ const OUString& _rURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rArgs
+ );
+ void setDocFileLocation(
+ const OUString& i_rLoadedFrom
+ );
+
+ static ::comphelper::NamedValueCollection
+ stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments );
+
+// other stuff
+
+ // disposes all elements in m_aStorages, and clears it
+ void disposeStorages();
+
+ /// creates a ->css::embed::StorageFactory
+ css::uno::Reference< css::lang::XSingleServiceFactory >
+ createStorageFactory() const;
+
+ /// commits our storage
+ void commitRootStorage();
+
+ /// commits a given storage if it's not readonly, ignoring (but asserting) all errors
+ bool commitStorageIfWriteable_ignoreErrors(
+ const css::uno::Reference< css::embed::XStorage >& _rxStorage
+ );
+
+ void clearConnections();
+
+ css::uno::Reference< css::embed::XStorage > const & getOrCreateRootStorage();
+ css::uno::Reference< css::embed::XStorage > const & getRootStorage() const { return m_xDocumentStorage.getTyped(); }
+ void resetRootStorage() { impl_switchToStorage_throw( nullptr ); }
+
+ /** returns the data source. If it doesn't exist it will be created
+ */
+ css::uno::Reference< css::sdbc::XDataSource> getOrCreateDataSource();
+
+ /** returns the model, if there already exists one
+ */
+ css::uno::Reference< css::frame::XModel > getModel_noCreate() const;
+
+ /** returns a new ->ODatabaseDocument
+
+ @precond
+ No ->ODatabaseDocument exists so far
+
+ @seealso
+ getModel_noCreate
+ */
+ css::uno::Reference< css::frame::XModel > createNewModel_deliverOwnership();
+
+ struct ResetModelAccess { friend class ODatabaseDocument; private: ResetModelAccess() { } };
+
+ /** resets the model to NULL
+
+ Only to be called when the model is being disposed
+ */
+ void modelIsDisposing( const bool _wasInitialized, ResetModelAccess );
+
+ bool hadInitializedDocument() const { return m_bDocumentInitialized; }
+
+ DocumentStorageAccess*
+ getDocumentStorageAccess();
+
+ css::uno::Reference< css::document::XDocumentSubStorageSupplier >
+ getDocumentSubStorageSupplier();
+
+ void acquire();
+
+ void release();
+
+ /// returns all known data source settings, including their default values
+ static const AsciiPropertyValue* getDefaultDataSourceSettings();
+
+ /** retrieves the requested container of objects (forms/reports/tables/queries)
+ */
+ TContentPtr& getObjectContainer( const ObjectType _eType );
+
+ /** returns the name of the storage which is used to stored objects of the given type, if applicable
+ */
+ static OUString
+ getObjectContainerStorageName( const ObjectType _eType );
+
+ /** determines whether a given object storage contains macros
+ */
+ static bool objectHasMacros(
+ const css::uno::Reference< css::embed::XStorage >& _rxContainerStorage,
+ const OUString& _rPersistentName
+ );
+
+ /** determines which kind of embedded macros are present in the document
+ */
+ EmbeddedMacros determineEmbeddedMacros();
+
+ /** checks our document's macro execution mode, using the interaction handler as supplied with our
+ load arguments
+ */
+ bool checkMacrosOnLoading();
+
+ /** adjusts our document's macro execution mode, without using any UI, assuming the user
+ would reject execution of macros, if she would have been asked.
+
+ If checkMacrosOnLoading has been called before (and thus the macro execution mode
+ is already adjusted), then the current execution mode is simply returned.
+
+ @return
+ whether or not macro execution is allowed
+ */
+ bool adjustMacroMode_AutoReject();
+
+ /** resets our macro execute mode, so next time the checkMacrosOnLoading is called, it will
+ behave as if it has never been called before
+ */
+ void resetMacroExecutionMode();
+
+ /** ensures that ->m_xBasicLibraries resp. m_xDialogLibraries exists
+
+ @return
+ the requested library container. Is never <NULL/>.
+
+ @throws RuntimeException
+ if something does wrong, which indicates a server error in the installation
+ */
+ css::uno::Reference< css::script::XStorageBasedLibraryContainer >
+ getLibraryContainer( bool _bScript );
+
+ /** lets our library containers store themself into the given root storage
+ */
+ void storeLibraryContainersTo( const css::uno::Reference< css::embed::XStorage >& _rxToRootStorage );
+
+ /** rebases the document to the given storage
+
+ No actual committing, copying, saving, whatsoever happens. The storage is just remembered as the documents
+ new storage, nothing more.
+
+ @throws css::lang::IllegalArgumentException
+ if the given storage is <NULL/>
+ @throws css::lang::RuntimeException
+ if any of the invoked operations does so
+ */
+ css::uno::Reference< css::embed::XStorage >
+ switchToStorage(
+ const css::uno::Reference< css::embed::XStorage >& _rxNewRootStorage
+ );
+
+ /** returns the macro mode imposed by an external instance, which passed it to attachResource
+ */
+ sal_Int16 getImposedMacroExecMode() const
+ {
+ return m_nImposedMacroExecMode;
+ }
+ void setImposedMacroExecMode( const sal_Int16 _nMacroMode )
+ {
+ m_nImposedMacroExecMode = _nMacroMode;
+ }
+
+public:
+ // IMacroDocumentAccess overridables
+ virtual sal_Int16 getCurrentMacroExecMode() const override;
+ virtual void setCurrentMacroExecMode( sal_uInt16 ) override;
+ virtual OUString getDocumentLocation() const override;
+ virtual bool documentStorageHasMacros() const override;
+ virtual bool macroCallsSeenWhileLoading() const override;
+ virtual css::uno::Reference< css::document::XEmbeddedScripts > getEmbeddedDocumentScripts() const override;
+ virtual SignatureState getScriptingSignatureState() override;
+ virtual bool hasTrustedScriptingSignature( bool bAllowUIToAddAuthor ) override;
+
+ // IModifiableDocument
+ virtual void storageIsModified() override;
+
+ // don't use directly, use the ModifyLock class instead
+ void lockModify() { m_bModificationLock = true; }
+ void unlockModify() { m_bModificationLock = false; }
+ bool isModifyLocked() const { return m_bModificationLock; }
+
+ weld::Window* GetFrameWeld();
+
+private:
+ void impl_construct_nothrow();
+ css::uno::Reference< css::embed::XStorage > const &
+ impl_switchToStorage_throw( const css::uno::Reference< css::embed::XStorage >& _rxNewRootStorage );
+
+ /** switches to the given document URL, which denotes the logical URL of the document, not necessarily the
+ URL where the doc was loaded/recovered from
+ */
+ void impl_switchToLogicalURL(
+ const OUString& i_rDocumentURL
+ );
+
+};
+
+/** a small base class for UNO components whose functionality depends on an ODatabaseModelImpl
+*/
+class ModelDependentComponent
+{
+protected:
+ ::rtl::Reference< ODatabaseModelImpl > m_pImpl;
+ ::osl::Mutex m_aMutex; // only use this to init WeakComponentImplHelper
+
+protected:
+ explicit ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model );
+ virtual ~ModelDependentComponent();
+
+ /** returns the component itself
+ */
+ virtual css::uno::Reference< css::uno::XInterface > getThis() const = 0;
+
+ ::osl::Mutex& getMutex()
+ {
+ return m_aMutex;
+ }
+
+public:
+ /// checks whether the component is already disposed, throws a DisposedException if so
+ void checkDisposed() const
+ {
+ if ( !m_pImpl.is() )
+ throw css::lang::DisposedException( "Component is already disposed.", getThis() );
+ }
+
+ void lockModify()
+ {
+ m_pImpl->lockModify();
+ }
+
+ void unlockModify()
+ {
+ m_pImpl->unlockModify();
+ }
+};
+
+class ModifyLock
+{
+public:
+ explicit ModifyLock( ModelDependentComponent& _component )
+ :m_rComponent( _component )
+ {
+ m_rComponent.lockModify();
+ }
+
+ ~ModifyLock()
+ {
+ m_rComponent.unlockModify();
+ }
+
+private:
+ ModelDependentComponent& m_rComponent;
+};
+
+/** a guard for public methods of objects dependent on an ODatabaseModelImpl instance
+
+ Just put this guard onto the stack at the beginning of your method. Don't bother yourself
+ with a MutexGuard, checks for being disposed, and the like.
+*/
+class ModelMethodGuard
+{
+private:
+ // to avoid deadlocks, lock SolarMutex
+ SolarMutexResettableGuard m_SolarGuard;
+
+public:
+ /** constructs the guard
+
+ @param _component
+ the component whose functionality depends on an ODatabaseModelImpl instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+ */
+ explicit ModelMethodGuard( const ModelDependentComponent& _component )
+ {
+ _component.checkDisposed();
+ }
+
+ void clear()
+ {
+ // note: this only releases *once* so may still be locked
+ m_SolarGuard.clear();
+ }
+
+ void reset()
+ {
+ m_SolarGuard.reset();
+ }
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/PropertyForward.hxx b/dbaccess/source/core/inc/PropertyForward.hxx
new file mode 100644
index 000000000..b8e602fc0
--- /dev/null
+++ b/dbaccess/source/core/inc/PropertyForward.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <vector>
+
+namespace dbaccess
+{
+
+ // OPropertyForward
+ typedef ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener
+ > OPropertyForward_Base;
+ class OPropertyForward :public ::cppu::BaseMutex
+ ,public OPropertyForward_Base
+ {
+ css::uno::Reference< css::beans::XPropertySet > m_xSource;
+ css::uno::Reference< css::beans::XPropertySet > m_xDest;
+ css::uno::Reference< css::beans::XPropertySetInfo > m_xDestInfo;
+ css::uno::Reference< css::container::XNameAccess > m_xDestContainer;
+ OUString m_sName;
+ bool m_bInInsert;
+
+ protected:
+ virtual ~OPropertyForward() override;
+
+ public:
+ OPropertyForward( const css::uno::Reference< css::beans::XPropertySet>& _xSource,
+ const css::uno::Reference< css::container::XNameAccess>& _xDestContainer,
+ const OUString& _sName,
+ const std::vector< OUString >& _aPropertyList
+ );
+
+ // css::beans::XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& _rSource ) override;
+
+ void setName( const OUString& _sName ) { m_sName = _sName; }
+ void setDefinition( const css::uno::Reference< css::beans::XPropertySet >& _xDest);
+ const css::uno::Reference< css::beans::XPropertySet >& getDefinition() const { return m_xDest; }
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/RefreshListener.hxx b/dbaccess/source/core/inc/RefreshListener.hxx
new file mode 100644
index 000000000..03836c308
--- /dev/null
+++ b/dbaccess/source/core/inc/RefreshListener.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.h>
+
+namespace com::sun::star::container { class XNameAccess; }
+
+
+namespace dbaccess
+{
+
+ // IRefreshListener
+ class SAL_NO_VTABLE IRefreshListener
+ {
+ public:
+ virtual void refresh(const css::uno::Reference< css::container::XNameAccess >& _rToBeRefreshed) = 0;
+
+ protected:
+ ~IRefreshListener() {}
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx b/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx
new file mode 100644
index 000000000..a0edfd195
--- /dev/null
+++ b/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <cppuhelper/implbase5.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <apitools.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <svx/ParseContext.hxx>
+
+namespace com::sun::star::util {
+ class XNumberFormatsSupplier;
+ class XNumberFormatter;
+}
+
+namespace dbaccess
+{
+ typedef ::cppu::ImplHelper5< css::sdb::XSingleSelectQueryComposer,
+ css::sdb::XParametersSupplier,
+ css::sdbcx::XColumnsSupplier,
+ css::sdbcx::XTablesSupplier,
+ css::lang::XServiceInfo > OSingleSelectQueryComposer_BASE;
+
+ class OPrivateColumns;
+ class OPrivateTables;
+
+ class OSingleSelectQueryComposer : public ::comphelper::OMutexAndBroadcastHelper
+ ,public OSubComponent
+ ,public ::comphelper::OPropertyContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper < OSingleSelectQueryComposer >
+ ,public OSingleSelectQueryComposer_BASE
+ {
+ enum SQLPart
+ {
+ Where = 0, // the 0 is important, as it will be used as index into arrays
+ Group,
+ Having,
+ Order,
+
+ SQLPartCount
+ };
+ static void incSQLPart( SQLPart& e ) { e = static_cast<SQLPart>(1 + static_cast<size_t>(e)); }
+ enum EColumnType
+ {
+ SelectColumns = 0,
+ GroupByColumns = 1,
+ OrderColumns = 2,
+ ParameterColumns = 3
+ };
+ typedef std::function<const ::connectivity::OSQLParseNode*(::connectivity::OSQLParseTreeIterator *)>
+ TGetParseNode;
+ ::svxform::OSystemParseContext m_aParseContext;
+ ::connectivity::OSQLParser m_aSqlParser;
+ ::connectivity::OSQLParseTreeIterator m_aSqlIterator; // the iterator for the complete statement
+ ::connectivity::OSQLParseTreeIterator m_aAdditiveIterator; // the iterator for the "additive statement" (means without the clauses of the elementary statement)
+ std::vector<std::unique_ptr<OPrivateColumns>>
+ m_aColumnsCollection; // used for columns and parameters of old queries
+ std::vector<std::unique_ptr<OPrivateTables>>
+ m_aTablesCollection;
+
+ std::vector< OUString > m_aElementaryParts; // the filter/groupby/having/order of the elementary statement
+
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xMetaData;
+ css::uno::Reference< css::container::XNameAccess> m_xConnectionTables;
+ css::uno::Reference< css::container::XNameAccess> m_xConnectionQueries;
+ css::uno::Reference< css::util::XNumberFormatsSupplier > m_xNumberFormatsSupplier;
+ css::uno::Reference< css::uno::XComponentContext> m_aContext;
+ css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter;
+
+ std::vector<std::unique_ptr<OPrivateColumns>> m_aCurrentColumns;
+ std::unique_ptr<OPrivateTables> m_pTables; // currently used tables
+
+ OUString m_aPureSelectSQL; // the pure select statement, without filter/order/groupby/having
+ OUString m_sDecimalSep;
+ OUString m_sCommand;
+ css::lang::Locale m_aLocale;
+ sal_Int32 m_nBoolCompareMode; // how to compare bool values
+ sal_Int32 m_nCommandType;
+
+ // <properties>
+ OUString m_sOriginal;
+ // </properties>
+
+
+ bool setORCriteria(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator& _rIterator,
+ std::vector< std::vector < css::beans::PropertyValue > >& rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+ bool setANDCriteria(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator& _rIterator,
+ std::vector < css::beans::PropertyValue > & rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+ bool setLikePredicate(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator const & _rIterator,
+ std::vector < css::beans::PropertyValue > & rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+ bool setComparisonPredicate(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator const & _rIterator,
+ std::vector < css::beans::PropertyValue > & rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+
+ static OUString getColumnName(::connectivity::OSQLParseNode const * pColumnRef, ::connectivity::OSQLParseTreeIterator const & _rIterator);
+ OUString getTableAlias(const css::uno::Reference< css::beans::XPropertySet >& column ) const;
+ static sal_Int32 getPredicateType(::connectivity::OSQLParseNode const * _pPredicate);
+ // clears all Columns,Parameters and tables and insert it to their vectors
+ void clearCurrentCollections();
+ // clears the columns collection given by EColumnType
+ void clearColumns( const EColumnType _eType );
+
+ /** retrieves a particular part of a statement
+ @param _rIterator
+ the iterator to use.
+ */
+ OUString getStatementPart( TGetParseNode const & _aGetFunctor, ::connectivity::OSQLParseTreeIterator& _rIterator );
+ void setQuery_Impl( const OUString& command );
+
+ void setConditionByColumn( const css::uno::Reference< css::beans::XPropertySet >& column
+ , bool andCriteria
+ , std::function<bool(OSingleSelectQueryComposer *, const OUString&)> const & _aSetFunctor
+ ,sal_Int32 filterOperator);
+
+ /** getStructuredCondition returns the structured condition for the where or having clause
+ @param _aGetFunctor
+ A member function to get the correct parse node.
+
+ @return
+ The structured filter
+ */
+ css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >
+ getStructuredCondition( TGetParseNode const & _aGetFunctor );
+
+ css::uno::Reference< css::container::XIndexAccess >
+ setCurrentColumns( EColumnType _eType, const ::rtl::Reference< ::connectivity::OSQLColumns >& _rCols );
+
+ //helper methods for mem_fun_t
+ bool implSetFilter(const OUString& _sFilter) { setFilter(_sFilter); return true;}
+ bool implSetHavingClause(const OUString& _sFilter) { setHavingClause(_sFilter); return true;}
+
+ /** returns the part of the select statement
+ @param _ePart
+ Which part should be returned.
+ @param _bWithKeyword
+ If <TRUE/> the keyword will be added too. Otherwise not.
+ @param _rIterator
+ The iterator to use.
+
+ @return
+ The part of the select statement.
+ */
+ OUString getSQLPart( SQLPart _ePart, ::connectivity::OSQLParseTreeIterator& _rIterator, bool _bWithKeyword );
+
+ /** retrieves the keyword for the given SQLPart
+ */
+ static OUString getKeyword( SQLPart _ePart );
+
+ /** sets a single "additive" clause, means a filter/groupby/having/order clause
+ */
+ void setSingleAdditiveClause( SQLPart _ePart, const OUString& _rClause );
+
+ /** composes a statement from m_aPureSelectSQL and the 4 usual clauses
+ */
+ OUString composeStatementFromParts( const std::vector< OUString >& _rParts );
+
+ /** return the name of the column in the *source* *table*.
+
+ That is, for (SELECT a AS b FROM t), it returns A or "t"."A", as appropriate.
+
+ Use e.g. for WHERE, GROUP BY and HAVING clauses.
+
+ @param bGroupBy: for GROUP BY clause? In that case, throw exception if trying to use an unrelated column and the database does not support that.
+ */
+ OUString impl_getColumnRealName_throw(const css::uno::Reference< css::beans::XPropertySet >& column, bool bGroupBy);
+
+ /** return the name of the column in the *query* for ORDER BY clause.
+
+ That is, for (SELECT a AS b FROM t), it returns "b"
+
+ Throws exception if trying to use an unrelated column and the database does not support that.
+ */
+ OUString impl_getColumnNameOrderBy_throw(const css::uno::Reference< css::beans::XPropertySet >& column);
+
+ protected:
+ virtual ~OSingleSelectQueryComposer() override;
+ public:
+
+ OSingleSelectQueryComposer( const css::uno::Reference< css::container::XNameAccess>& _xTableSupplier,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const css::uno::Reference< css::uno::XComponentContext>& _rContext);
+
+
+ void SAL_CALL disposing() override;
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+
+ // css::sdb::XSingleSelectQueryComposer
+ virtual OUString SAL_CALL getElementaryQuery() override;
+ virtual void SAL_CALL setElementaryQuery( const OUString& _rElementary ) override;
+ virtual void SAL_CALL setFilter( const OUString& filter ) override;
+ virtual void SAL_CALL setStructuredFilter( const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& filter ) override;
+ virtual void SAL_CALL appendFilterByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator ) override;
+ virtual void SAL_CALL appendGroupByColumn( const css::uno::Reference< css::beans::XPropertySet >& column ) override;
+ virtual void SAL_CALL setGroup( const OUString& group ) override;
+ virtual void SAL_CALL setHavingClause( const OUString& filter ) override;
+ virtual void SAL_CALL setStructuredHavingClause( const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& filter ) override;
+ virtual void SAL_CALL appendHavingClauseByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator ) override;
+ virtual void SAL_CALL appendOrderByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool ascending ) override;
+ virtual void SAL_CALL setOrder( const OUString& order ) override;
+
+ // XSingleSelectQueryAnalyzer
+ virtual OUString SAL_CALL getQuery( ) override;
+ virtual void SAL_CALL setQuery( const OUString& command ) override;
+ virtual void SAL_CALL setCommand( const OUString& command,sal_Int32 CommandType ) override;
+ virtual OUString SAL_CALL getFilter( ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getStructuredFilter( ) override;
+ virtual OUString SAL_CALL getGroup( ) override;
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getGroupColumns( ) override;
+ virtual OUString SAL_CALL getHavingClause( ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getStructuredHavingClause( ) override;
+ virtual OUString SAL_CALL getOrder( ) override;
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getOrderColumns( ) override;
+ virtual OUString SAL_CALL getQueryWithSubstitution( ) override;
+
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+ // XParametersSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getParameters( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/TableDeco.hxx b/dbaccess/source/core/inc/TableDeco.hxx
new file mode 100644
index 000000000..e40fac802
--- /dev/null
+++ b/dbaccess/source/core/inc/TableDeco.hxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdbcx/XAlterTable.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <cppuhelper/compbase.hxx>
+#include "datasettings.hxx"
+#include "column.hxx"
+
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace dbaccess
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbcx::XColumnsSupplier,
+ css::sdbcx::XKeysSupplier,
+ css::container::XNamed,
+ css::lang::XServiceInfo,
+ css::sdbcx::XDataDescriptorFactory,
+ css::sdbcx::XIndexesSupplier,
+ css::sdbcx::XRename,
+ css::lang::XUnoTunnel,
+ css::sdbcx::XAlterTable> OTableDescriptor_BASE;
+ // OTables
+ class ODBTableDecorator;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< ODBTableDecorator > ODBTableDecorator_PROP;
+
+ class ODBTableDecorator :public cppu::BaseMutex
+ ,public OTableDescriptor_BASE
+ ,public ODataSettings //ODataSettings_Base
+ ,public IColumnFactory
+ ,public ::connectivity::sdbcx::IRefreshableColumns
+ ,public ODBTableDecorator_PROP
+ {
+ void fillPrivileges() const;
+ protected:
+ css::uno::Reference< css::container::XContainerListener > m_xColumnMediator;
+ css::uno::Reference< css::sdbcx::XColumnsSupplier > m_xTable;
+ css::uno::Reference< css::container::XNameAccess > m_xColumnDefinitions;
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ css::uno::Reference< css::util::XNumberFormatsSupplier > m_xNumberFormats;
+
+ // <properties>
+ mutable sal_Int32 m_nPrivileges;
+ // </properties>
+ // note: this thing uses the ref-count of "this", see OCollection::acquire()!
+ std::unique_ptr<::connectivity::sdbcx::OCollection> m_pColumns;
+
+ // IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+
+ virtual void refreshColumns() override;
+
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ // OPropertySetHelper
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ virtual ~ODBTableDecorator() override;
+ public:
+ /** constructs a wrapper supporting the com.sun.star.sdb.Table service.
+
+ @param _rxConn
+ the connection the table belongs to. Must not be <NULL/>
+ @param _rxTable
+ the table from the driver can be <NULL/>
+ @throws css::sdbc::SQLException
+ */
+ ODBTableDecorator(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::sdbcx::XColumnsSupplier >& _rxTable,
+ const css::uno::Reference< css::util::XNumberFormatsSupplier >& _rxNumberFormats,
+ const css::uno::Reference< css::container::XNameAccess >& _rxColumnDefinitions
+ );
+
+ // ODescriptor
+ void construct();
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // css::sdbcx::XRename,
+ virtual void SAL_CALL rename( const OUString& _rNewName ) override;
+
+ // css::sdbcx::XAlterTable,
+ virtual void SAL_CALL alterColumnByName( const OUString& _rName, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor ) override;
+ virtual void SAL_CALL alterColumnByIndex( sal_Int32 _nIndex, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+ // XKeysSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getKeys( ) override;
+ // XIndexesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getIndexes( ) override;
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+ protected:
+ using ODataSettings::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/View.hxx b/dbaccess/source/core/inc/View.hxx
new file mode 100644
index 000000000..d3889ff56
--- /dev/null
+++ b/dbaccess/source/core/inc/View.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdb/tools/XViewAccess.hpp>
+
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+
+ // View
+ typedef ::connectivity::sdbcx::OView View_Base;
+ typedef ::cppu::ImplHelper1< css::sdbcx::XAlterView > View_IBASE;
+ class View :public View_Base
+ ,public View_IBASE
+ {
+ public:
+ View(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ bool _bCaseSensitive,
+ const OUString& _rCatalogName,
+ const OUString& _rSchemaName,
+ const OUString& _rName
+ );
+
+ // UNO
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XAlterView
+ virtual void SAL_CALL alterCommand( const OUString& NewCommand ) override;
+
+ protected:
+ virtual ~View() override;
+
+ protected:
+ // OPropertyContainer
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ private:
+ css::uno::Reference< css::sdb::tools::XViewAccess> m_xViewAccess;
+ sal_Int32 m_nCommandHandle;
+ private:
+ using View_Base::getFastPropertyValue;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/bookmarkcontainer.hxx b/dbaccess/source/core/inc/bookmarkcontainer.hxx
new file mode 100644
index 000000000..464192542
--- /dev/null
+++ b/dbaccess/source/core/inc/bookmarkcontainer.hxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace dbaccess
+{
+
+// OBookmarkContainer - base class of collections of database definition
+// documents
+typedef ::cppu::WeakImplHelper<
+ css::container::XIndexAccess
+ , css::container::XNameContainer
+ , css::container::XEnumerationAccess
+ , css::container::XContainer
+ , css::lang::XServiceInfo
+ , css::container::XChild
+ > OBookmarkContainer_Base;
+
+class OBookmarkContainer final
+ :public OBookmarkContainer_Base
+{
+ typedef std::map<OUString, OUString> MapString2String;
+ typedef std::vector<MapString2String::iterator> MapIteratorVector;
+
+ MapString2String m_aBookmarks; // the bookmarks itself
+ MapIteratorVector m_aBookmarksIndexed; // for index access to the
+
+ ::cppu::OWeakObject& m_rParent; // for the ref counting
+ ::comphelper::OInterfaceContainerHelper3<css::container::XContainerListener>
+ m_aContainerListeners;
+ ::osl::Mutex& m_rMutex;
+
+public:
+ /** constructs the container.<BR>
+ after the construction of the object the creator has to call <code>initialize</code>.
+ @param _rParent the parent object which is used for ref counting
+ @param _rMutex the parent's mutex object for access safety
+ */
+ OBookmarkContainer(
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex
+ );
+
+ /** looks like the dtor ...
+ */
+ virtual ~OBookmarkContainer() override;
+
+// css::uno::XInterface
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// css::container::XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+// css::container::XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+// css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 _nIndex ) override;
+
+// css::container::XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& _rName ) override;
+
+// css::container::XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+
+// css::container::XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+// css::container::XContainer
+ virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+ virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+
+// css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+private:
+ /** quickly checks if there already is an element with a given name. No access to the configuration occurs, i.e.
+ if there is such an object which is not already loaded, it won't be loaded now.
+ @param _rName the object name to check
+ @return sal_True if there already exists such an object
+ */
+ inline bool checkExistence(const OUString& _rName);
+
+ void implAppend(
+ const OUString& _rName,
+ const OUString& _rDocumentLocation
+ );
+
+ void implRemove(const OUString& _rName);
+
+ void implReplace(
+ const OUString& _rName,
+ const OUString& _rNewLink);
+
+};
+
+inline bool OBookmarkContainer::checkExistence(const OUString& _rName)
+{
+ return m_aBookmarks.find(_rName) != m_aBookmarks.end();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/callablestatement.hxx b/dbaccess/source/core/inc/callablestatement.hxx
new file mode 100644
index 000000000..58e21189a
--- /dev/null
+++ b/dbaccess/source/core/inc/callablestatement.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XOutParameters.hpp>
+#include "preparedstatement.hxx"
+
+namespace dbaccess
+{
+
+ // OCallableStatement
+
+ class OCallableStatement : public OPreparedStatement,
+ public css::sdbc::XRow,
+ public css::sdbc::XOutParameters
+ {
+ public:
+ OCallableStatement(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement)
+ :OPreparedStatement(_xConn, _xStatement){}
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::sdbc::XOutParameters
+ virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/column.hxx b/dbaccess/source/core/inc/column.hxx
new file mode 100644
index 000000000..aebc376b1
--- /dev/null
+++ b/dbaccess/source/core/inc/column.hxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "columnsettings.hxx"
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/propertycontainer.hxx>
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+
+
+ // OColumn
+
+ typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo,
+ css::container::XNamed
+ > OColumnBase;
+
+ class OColumn :public cppu::BaseMutex
+ ,public OColumnBase
+ ,public ::comphelper::OPropertyContainer
+ ,public IPropertyContainer // convenience for the derived class which also derive from OColumnSettings
+ {
+ friend class OColumns;
+
+ protected:
+ // <properties>
+ OUString m_sName;
+ // </properties>
+
+ protected:
+ OColumn( const bool _bNameIsReadOnly );
+
+ public:
+ virtual ~OColumn() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override = 0;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& _rName ) override;
+
+ protected:
+ // IPropertyContainer
+ virtual void registerProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, void* _pPointerToMember, const css::uno::Type& _rMemberType ) override;
+ virtual void registerMayBeVoidProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, css::uno::Any* _pPointerToMember, const css::uno::Type& _rExpectedType ) override;
+ };
+
+ // IColumnFactory - used by OColumns for creating new columns
+ class SAL_NO_VTABLE IColumnFactory
+ {
+ public:
+ /** creates an OColumn object which should represent the column with a given name
+ */
+ virtual rtl::Reference<OColumn>
+ createColumn( const OUString& _rName ) const = 0;
+
+ /** creates a column descriptor object.
+
+ A column descriptor object is used to append new columns to the collection. If such an append
+ actually happened, columnAppended is called afterwards.
+ */
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() = 0;
+
+ /** notifies that a column, created from a column descriptor, has been appended
+ */
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) = 0;
+
+ /** notifies that a column with a given name has been dropped
+ */
+ virtual void columnDropped( const OUString& _sName ) = 0;
+
+ protected:
+ ~IColumnFactory() {}
+ };
+
+ class OContainerMediator;
+ typedef ::cppu::ImplHelper1< css::container::XChild > TXChild;
+ typedef connectivity::OColumnsHelper OColumns_BASE;
+
+ class OColumns : public OColumns_BASE
+ ,public TXChild
+ {
+ OContainerMediator* m_pMediator;
+
+ protected:
+ // comes from the driver can be null
+ css::uno::Reference< css::container::XNameAccess > m_xDrvColumns;
+ css::uno::WeakReference< css::uno::XInterface > m_xParent;
+ IColumnFactory* m_pColFactoryImpl;
+ ::connectivity::sdbcx::IRefreshableColumns* m_pRefreshColumns;
+
+ bool m_bInitialized : 1;
+ bool m_bAddColumn : 1;
+ bool m_bDropColumn : 1;
+
+ virtual void impl_refresh() override;
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ public:
+ connectivity::sdbcx::ObjectType createBaseObject(const OUString& _rName)
+ {
+ return OColumns_BASE::createObject(_rName);
+ }
+ /** flag which determines whether the container is filled or not
+ */
+ bool isInitialized() const { return m_bInitialized; }
+ void setInitialized() {m_bInitialized = true;}
+ void setMediator(OContainerMediator* _pMediator) { m_pMediator = _pMediator; }
+
+ public:
+ /** constructs an empty container without configuration location.
+ @param rParent the parent object. This instance will be used for refcounting, so the parent
+ cannot die before the container does.
+ @param _rMutex the mutex of the parent.
+ @param _bCaseSensitive the initial case sensitivity flag
+ @see setCaseSensitive
+ */
+ OColumns(
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ bool _bCaseSensitive,
+ const std::vector< OUString>& _rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn = false,
+ bool _bDropColumn = false,
+ bool _bUseHardRef = true);
+
+ OColumns(
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::container::XNameAccess >& _rxDrvColumns,
+ bool _bCaseSensitive,
+ const std::vector< OUString> &_rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn = false,
+ bool _bDropColumn = false,
+ bool _bUseHardRef = true);
+ virtual ~OColumns() override;
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override { OColumns_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OColumns_BASE::release(); }
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ void append(const OUString& rName, OColumn*);
+ void clearColumns();
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ private:
+ using OColumns_BASE::setParent;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/columnsettings.hxx b/dbaccess/source/core/inc/columnsettings.hxx
new file mode 100644
index 000000000..6b6c5d4c1
--- /dev/null
+++ b/dbaccess/source/core/inc/columnsettings.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+namespace dbaccess
+{
+
+ // TODO: move the following to comphelper/propertycontainerhelper.hxx
+ class IPropertyContainer
+ {
+ public:
+ virtual void registerProperty(
+ const OUString& _rName,
+ sal_Int32 _nHandle,
+ sal_Int32 _nAttributes,
+ void* _pPointerToMember,
+ const css::uno::Type& _rMemberType
+ ) = 0;
+
+ virtual void registerMayBeVoidProperty(
+ const OUString& _rName,
+ sal_Int32 _nHandle,
+ sal_Int32 _nAttributes,
+ css::uno::Any* _pPointerToMember,
+ const css::uno::Type& _rExpectedType
+ ) = 0;
+
+ protected:
+ ~IPropertyContainer() {}
+ };
+
+ // OColumnSettings
+ class OColumnSettings
+ {
+ // <properties>
+ css::uno::Any m_aWidth; // sal_Int32 or void
+ css::uno::Any m_aFormatKey; // sal_Int32 or void
+ css::uno::Any m_aRelativePosition; // sal_Int32 or void
+ css::uno::Any m_aAlignment; // sal_Int32 (css::awt::TextAlign) or void
+ css::uno::Any m_aHelpText; // the description of the column which is visible in the helptext of the column
+ css::uno::Any m_aControlDefault; // the default value which should be displayed as by a control when moving to a new row
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xControlModel;
+ bool m_bHidden;
+ // </properties>
+
+ protected:
+ virtual ~OColumnSettings();
+
+ public:
+ OColumnSettings();
+
+ protected:
+ void registerProperties( IPropertyContainer& _rPropertyContainer );
+
+ /** determines whether the property with the given handle is handled by the class
+ */
+ static bool isColumnSettingProperty( const sal_Int32 _nPropertyHandle );
+ static bool isDefaulted( const sal_Int32 _nPropertyHandle, const css::uno::Any& _rPropertyValue );
+
+ public:
+ /** check if the persistent settings have their default value
+ */
+ static bool hasDefaultSettings( const css::uno::Reference< css::beans::XPropertySet >& _rxColumn );
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/commandbase.hxx b/dbaccess/source/core/inc/commandbase.hxx
new file mode 100644
index 000000000..1a0bd91d8
--- /dev/null
+++ b/dbaccess/source/core/inc/commandbase.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace dbaccess
+{
+
+// OCommandBase - a base class (in fact just a container for some members)
+// for classes implementing the sdb.CommandDefinition service
+class OCommandBase
+{
+public: // need public access
+// <properties>
+ css::uno::Sequence< css::beans::PropertyValue>
+ m_aLayoutInformation;
+ OUString m_sCommand;
+ bool m_bEscapeProcessing; // no BitField! So it can be used with an OPropertyStateContainer
+ OUString m_sUpdateTableName;
+ OUString m_sUpdateSchemaName;
+ OUString m_sUpdateCatalogName;
+// </properties>
+
+protected:
+ OCommandBase() : m_bEscapeProcessing(true) { }
+
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/composertools.hxx b/dbaccess/source/core/inc/composertools.hxx
new file mode 100644
index 000000000..337064757
--- /dev/null
+++ b/dbaccess/source/core/inc/composertools.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+
+namespace dbaccess
+{
+
+ // TokenComposer
+ struct TokenComposer
+ {
+ private:
+ #ifdef DBG_UTIL
+ bool m_bUsed;
+ #endif
+
+ protected:
+ OUStringBuffer m_aBuffer;
+
+ public:
+ OUString getComposedAndClear()
+ {
+ #ifdef DBG_UTIL
+ m_bUsed = true;
+ #endif
+ return m_aBuffer.makeStringAndClear();
+ }
+
+ void clear()
+ {
+ #ifdef DBG_UTIL
+ m_bUsed = false;
+ #endif
+ m_aBuffer.setLength(0);
+ }
+
+ public:
+ TokenComposer()
+ #ifdef DBG_UTIL
+ :m_bUsed( false )
+ #endif
+ {
+ }
+
+ virtual ~TokenComposer()
+ {
+ }
+
+ TokenComposer(TokenComposer const &) = default;
+ TokenComposer(TokenComposer &&) = default;
+ TokenComposer & operator =(TokenComposer const &) = default;
+ TokenComposer & operator =(TokenComposer &&) = default;
+
+ void operator() (const OUString& lhs)
+ {
+ append(lhs);
+ }
+
+ void append( const OUString& lhs )
+ {
+ #ifdef DBG_UTIL
+ OSL_ENSURE( !m_bUsed, "FilterCreator::append: already used up!" );
+ #endif
+ if ( !lhs.isEmpty() )
+ {
+ if ( !m_aBuffer.isEmpty() )
+ appendNonEmptyToNonEmpty( lhs );
+ else
+ m_aBuffer.append( lhs );
+ }
+ }
+
+ /// append the given part. Only to be called when both the part and our buffer so far are not empty
+ virtual void appendNonEmptyToNonEmpty( const OUString& lhs ) = 0;
+ };
+
+ // FilterCreator
+ struct FilterCreator : public TokenComposer
+ {
+ virtual void appendNonEmptyToNonEmpty( const OUString& lhs ) override
+ {
+ m_aBuffer.insert( 0, ' ' );
+ m_aBuffer.insert( 0, '(' );
+ m_aBuffer.append( " ) AND ( " );
+ m_aBuffer.append( lhs );
+ m_aBuffer.append( " )" );
+ }
+ };
+
+ // FilterCreator
+ struct OrderCreator : public TokenComposer
+ {
+ virtual void appendNonEmptyToNonEmpty( const OUString& lhs ) override
+ {
+ m_aBuffer.append( ", " );
+ m_aBuffer.append( lhs );
+ }
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/containerapprove.hxx b/dbaccess/source/core/inc/containerapprove.hxx
new file mode 100644
index 000000000..f780e224a
--- /dev/null
+++ b/dbaccess/source/core/inc/containerapprove.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+#include <memory>
+
+namespace dbaccess
+{
+
+ // IContainerApprove
+ /** interface for approving elements to be inserted into a container
+
+ On the long run, one could imagine that this interface completely encapsulates
+ container/element approvals in all our various container classes herein (document
+ containers, definition containers, table containers, query containers,
+ command definition containers, bookmark containers). This would decrease coupling
+ of the respective classes.
+ */
+ class SAL_NO_VTABLE IContainerApprove
+ {
+ public:
+ virtual ~IContainerApprove() {}
+
+ /** approves a given element for insertion into the container
+ @param _rName
+ specifies the name under which the element is going to be inserted
+ @throws Exception
+ if the name or the object are invalid, or not eligible for insertion
+ into the container
+ */
+ virtual void approveElement( const OUString& _rName ) = 0;
+ };
+
+ typedef std::shared_ptr< IContainerApprove > PContainerApprove;
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/databasecontext.hxx b/dbaccess/source/core/inc/databasecontext.hxx
new file mode 100644
index 000000000..e15585c81
--- /dev/null
+++ b/dbaccess/source/core/inc/databasecontext.hxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <config_features.h>
+
+#include <map>
+
+#include "ModelImpl.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdb/XDatabaseContext.hpp>
+#include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
+#include <com/sun/star/uno/XAggregation.hpp>
+
+#if HAVE_FEATURE_SCRIPTING
+#include <basic/basrdll.hxx>
+#endif
+
+#include <basic/basicmanagerrepository.hxx>
+#include <cppuhelper/compbase.hxx>
+
+// needed for registration
+namespace com::sun::star {
+ namespace lang
+ {
+ class XMultiServiceFactory;
+ class IllegalArgumentException;
+ }
+}
+
+namespace dbaccess
+{
+class DatabaseDocumentLoader;
+
+typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo
+ , css::sdb::XDatabaseContext
+ , css::lang::XUnoTunnel
+ > DatabaseAccessContext_Base;
+
+class ODatabaseContext :public DatabaseAccessContext_Base
+ ,public ::basic::BasicManagerCreationListener
+{
+private:
+ /** loads the given object from the given URL
+ @throws WrappedTargetException
+ if an error occurs accessing the URL via the UCB
+ */
+ css::uno::Reference< css::uno::XInterface > loadObjectFromURL(const OUString& _rName,const OUString& _sURL);
+ css::uno::Reference< css::uno::XInterface > getObject( const OUString& _rURL );
+
+ /** sets all properties which were transient at the data source. e.g. password
+ @param _sURL The file URL of the data source
+ @param _xObject The data source itself.
+ */
+ void setTransientProperties(const OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel );
+
+ /** creates a new data source
+ */
+ css::uno::Reference< css::uno::XInterface >
+ impl_createNewDataSource();
+
+#if HAVE_FEATURE_SCRIPTING
+ BasicDLL m_aBasicDLL;
+#endif
+
+protected:
+ ::osl::Mutex m_aMutex;
+ css::uno::Reference< css::uno::XComponentContext >
+ m_aContext;
+
+ css::uno::Reference< css::uno::XAggregation >
+ m_xDBRegistrationAggregate;
+ css::uno::Reference< css::sdb::XDatabaseRegistrations >
+ m_xDatabaseRegistrations;
+
+ typedef std::map<OUString, ODatabaseModelImpl*> ObjectCache;
+ ObjectCache m_aDatabaseObjects;
+
+ typedef std::map< OUString, css::uno::Sequence< css::beans::PropertyValue > > PropertyCache;
+ PropertyCache m_aDatasourceProperties;
+ // as we hold our data sources weak, we have to cache all properties on the data sources which are
+ // transient but stored as long as the session lasts. The database context is the session (as it lives
+ // as long as the session does), but the data sources may die before the session does, and then be
+ // recreated afterwards. So it's our (the context's) responsibility to store the session-persistent
+ // properties.
+
+ ::comphelper::OInterfaceContainerHelper3<css::container::XContainerListener> m_aContainerListeners;
+ rtl::Reference<DatabaseDocumentLoader> m_xDatabaseDocumentLoader;
+
+public:
+ explicit ODatabaseContext( const css::uno::Reference< css::uno::XComponentContext >& );
+ virtual ~ODatabaseContext() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XSingleServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const css::uno::Sequence< css::uno::Any >& _rArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XNamingService
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override;
+ virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override;
+ virtual void SAL_CALL revokeObject( const OUString& Name ) override;
+
+ // XDatabaseRegistrations
+ virtual sal_Bool SAL_CALL hasRegisteredDatabase( const OUString& Name ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getRegistrationNames() override;
+ virtual OUString SAL_CALL getDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL registerDatabaseLocation( const OUString& Name, const OUString& Location ) override;
+ virtual void SAL_CALL revokeDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL changeDatabaseLocation( const OUString& Name, const OUString& NewLocation ) override;
+ virtual sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const OUString& Name ) override;
+ virtual void SAL_CALL addDatabaseRegistrationsListener( const css::uno::Reference< css::sdb::XDatabaseRegistrationsListener >& Listener ) override;
+ virtual void SAL_CALL removeDatabaseRegistrationsListener( const css::uno::Reference< css::sdb::XDatabaseRegistrationsListener >& Listener ) override;
+
+ // XContainer
+ virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+ virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ void registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl);
+ void revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl);
+ void databaseDocumentURLChange(const OUString& _sOldName, const OUString& _sNewName);
+ void storeTransientProperties( ODatabaseModelImpl& _rModelImpl);
+ void appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel);
+ void removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel);
+
+private:
+ // BasicManagerCreationListener
+ virtual void onBasicManagerCreated(
+ const css::uno::Reference< css::frame::XModel >& _rxForDocument,
+ BasicManager& _rBasicManager
+ ) override;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/datasettings.hxx b/dbaccess/source/core/inc/datasettings.hxx
new file mode 100644
index 000000000..8e24ebb71
--- /dev/null
+++ b/dbaccess/source/core/inc/datasettings.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <rtl/ustring.hxx>
+#include <comphelper/propertystatecontainer.hxx>
+
+namespace dbaccess
+{
+
+// ODataSettings_Base - a base class which implements the property member
+// for an object implementing the sdb::DataSettings
+// service
+// the properties have to be registered when used
+class ODataSettings_Base
+{
+public:
+// <properties>
+ OUString m_sFilter;
+ OUString m_sHavingClause;
+ OUString m_sGroupBy;
+ OUString m_sOrder;
+ bool m_bApplyFilter; // no BitField ! the base class needs a pointer to this member !
+ bool m_bAutoGrow;
+ css::awt::FontDescriptor m_aFont;
+ css::uno::Any m_aRowHeight;
+ css::uno::Any m_aTextColor;
+ css::uno::Any m_aTextLineColor;
+ sal_Int16 m_nFontEmphasis;
+ sal_Int16 m_nFontRelief;
+// </properties>
+
+protected:
+ ODataSettings_Base();
+ ODataSettings_Base(const ODataSettings_Base& _rSource) = delete;
+ ~ODataSettings_Base();
+};
+// ODataSettings - a base class which implements the property handling
+// for an object implementing the sdb::DataSettings
+// service
+
+class ODataSettings : public ::comphelper::OPropertyStateContainer
+ , public ODataSettings_Base
+{
+ bool m_bQuery;
+protected:
+ ODataSettings(::cppu::OBroadcastHelper& _rBHelper,bool _bQuery = false);
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ /** register the properties from the param given. The parameter instance must be alive as long as its object lives.
+ @param _pItem
+ The database settings, can be <br>this</br>
+ */
+ void registerPropertiesFor(ODataSettings_Base* _pItem);
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/definitioncolumn.hxx b/dbaccess/source/core/inc/definitioncolumn.hxx
new file mode 100644
index 000000000..4d7ff3e17
--- /dev/null
+++ b/dbaccess/source/core/inc/definitioncolumn.hxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "column.hxx"
+#include "columnsettings.hxx"
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <comphelper/IdPropArrayHelper.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+
+ typedef ::cppu::ImplHelper1< css::container::XChild > TXChild;
+ // OTableColumnDescriptor
+ /**
+ * provides the properties for description. A descriptor could be used to create a new table column.
+ */
+ class OTableColumnDescriptor : public OColumn
+ ,public OColumnSettings
+ ,public ::comphelper::OPropertyArrayUsageHelper < OTableColumnDescriptor >
+ ,public TXChild
+ {
+ css::uno::Reference< css::uno::XInterface > m_xParent;
+ const bool m_bActAsDescriptor;
+
+ protected:
+ // <properties>
+ OUString m_aTypeName;
+ OUString m_aDescription;
+ OUString m_aDefaultValue;
+ OUString m_aAutoIncrementValue;
+ sal_Int32 m_nType;
+ sal_Int32 m_nPrecision;
+ sal_Int32 m_nScale;
+ sal_Int32 m_nIsNullable;
+ bool m_bAutoIncrement;
+ bool m_bRowVersion;
+ bool m_bCurrency;
+ // </properties>
+
+ public:
+ OTableColumnDescriptor( const bool _bActAsDescriptor )
+ :OColumn( !_bActAsDescriptor )
+ ,m_bActAsDescriptor( _bActAsDescriptor )
+ ,m_nType( css::sdbc::DataType::SQLNULL )
+ ,m_nPrecision( 0 )
+ ,m_nScale( 0 )
+ ,m_nIsNullable( css::sdbc::ColumnValue::NULLABLE_UNKNOWN )
+ ,m_bAutoIncrement( false )
+ ,m_bRowVersion( false )
+ ,m_bCurrency( false )
+ {
+ impl_registerProperties();
+ }
+
+ DECLARE_XINTERFACE( )
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ // ::comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+ // ::cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+
+ private:
+ void impl_registerProperties();
+ };
+
+ // OTableColumn
+ class OTableColumn;
+ typedef ::comphelper::OPropertyArrayUsageHelper < OTableColumn > OTableColumn_PBase;
+ /** describes a column of a table
+ */
+ class OTableColumn :public OTableColumnDescriptor
+ ,public OTableColumn_PBase
+ {
+ protected:
+ virtual ~OTableColumn() override;
+
+ public:
+ OTableColumn(const OUString& _rName);
+
+ // XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ };
+
+ // OQueryColumn
+ class OQueryColumn;
+ typedef ::comphelper::OPropertyArrayUsageHelper< OQueryColumn > OQueryColumn_PBase;
+ /** a column of a Query, with additional information obtained from parsing the query statement
+ */
+ class OQueryColumn :public OTableColumnDescriptor
+ ,public OQueryColumn_PBase
+ {
+ // <properties>
+ OUString m_sCatalogName;
+ OUString m_sSchemaName;
+ OUString m_sTableName;
+ OUString m_sRealName;
+ OUString m_sLabel;
+ // </properties>
+
+ css::uno::Reference< css::beans::XPropertySet > m_xOriginalTableColumn;
+
+ protected:
+ virtual ~OQueryColumn() override;
+
+ public:
+ OQueryColumn(
+ const css::uno::Reference< css::beans::XPropertySet>& _rxParserColumn,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const OUString &i_sLabel
+ );
+
+ // XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // *Property*
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ private:
+ css::uno::Reference< css::beans::XPropertySet >
+ impl_determineOriginalTableColumn(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+
+ // OColumnWrapper
+ /**
+ * describes all properties for a columns of a table. Only the view parts are provided
+ * directly, all the other parts are derived from a driver implementation
+ */
+ class OColumnWrapper :public OColumn
+ {
+ protected:
+ // definition which is provided by a driver!
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xAggregate;
+
+ sal_Int32 m_nColTypeID;
+
+ protected:
+ OColumnWrapper( const css::uno::Reference< css::beans::XPropertySet >& _rCol, const bool _bNameIsReadOnly );
+ virtual ~OColumnWrapper() override;
+
+ public:
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ protected:
+ OUString impl_getPropertyNameFromHandle( const sal_Int32 _nHandle ) const;
+
+ protected:
+ using OColumn::getFastPropertyValue;
+ };
+
+ // OTableColumnDescriptorWrapper
+ /**
+ * provides the properties for description. A descriptor could be used to create a new table column.
+ */
+ class OTableColumnDescriptorWrapper :public OColumnWrapper
+ ,public OColumnSettings
+ ,public ::comphelper::OIdPropertyArrayUsageHelper < OTableColumnDescriptorWrapper >
+ {
+ const bool m_bPureWrap;
+ const bool m_bIsDescriptor;
+
+ public:
+ OTableColumnDescriptorWrapper(const css::uno::Reference< css::beans::XPropertySet >& rCol,
+ const bool _bPureWrap, const bool _bIsDescriptor );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OIdPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ protected:
+ using OColumnWrapper::getFastPropertyValue;
+ };
+
+ // OTableColumnWrapper
+ /**
+ * describes all properties for a columns of a table. Only the view parts are provided
+ * directly, all the other parts are derived from a driver implementation
+ */
+ class OTableColumnWrapper :public OTableColumnDescriptorWrapper
+ ,public ::comphelper::OIdPropertyArrayUsageHelper < OTableColumnWrapper >
+ {
+ protected:
+ virtual ~OTableColumnWrapper() override;
+
+ public:
+ OTableColumnWrapper( const css::uno::Reference< css::beans::XPropertySet >& rCol,
+ const css::uno::Reference< css::beans::XPropertySet >& rColDefinition,
+ const bool _bPureWrap );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OIdPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/definitioncontainer.hxx b/dbaccess/source/core/inc/definitioncontainer.hxx
new file mode 100644
index 000000000..9c871601a
--- /dev/null
+++ b/dbaccess/source/core/inc/definitioncontainer.hxx
@@ -0,0 +1,323 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <cppuhelper/implbase7.hxx>
+#include <osl/mutex.hxx>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/XVetoableChangeListener.hpp>
+#include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
+#include "ContentHelper.hxx"
+#include "containerapprove.hxx"
+#include <comphelper/uno3.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+
+namespace dbaccess
+{
+
+class ODefinitionContainer_Impl : public OContentHelper_Impl
+{
+public:
+ typedef std::map< OUString, TContentPtr > NamedDefinitions;
+ typedef NamedDefinitions::iterator iterator;
+ typedef NamedDefinitions::const_iterator const_iterator;
+
+private:
+ NamedDefinitions m_aDefinitions;
+
+public:
+ size_t size() const { return m_aDefinitions.size(); }
+
+ const_iterator begin() const { return m_aDefinitions.begin(); }
+ const_iterator end() const { return m_aDefinitions.end(); }
+
+ const_iterator find( const OUString& _rName ) const { return m_aDefinitions.find( _rName ); }
+ const_iterator find( const TContentPtr& _pDefinition ) const;
+
+ void erase( const OUString& _rName ) { m_aDefinitions.erase( _rName ); }
+ void erase( const TContentPtr& _pDefinition );
+
+ void insert( const OUString& _rName, TContentPtr _pDefinition )
+ {
+ m_aDefinitions.emplace( _rName, _pDefinition );
+ }
+
+private:
+ iterator find( const TContentPtr& _pDefinition );
+ // (for the moment, this is private. Make it public if needed. If really needed.)
+};
+
+// ODefinitionContainer - base class of collections of database definition
+// documents
+typedef ::cppu::ImplHelper7 < css::container::XIndexAccess
+ , css::container::XNameContainer
+ , css::container::XEnumerationAccess
+ , css::container::XContainer
+ , css::container::XContainerApproveBroadcaster
+ , css::beans::XPropertyChangeListener
+ , css::beans::XVetoableChangeListener
+ > ODefinitionContainer_Base;
+
+class ODefinitionContainer
+ :public OContentHelper
+ ,public ODefinitionContainer_Base
+{
+protected:
+ typedef std::map< OUString, css::uno::WeakReference< css::ucb::XContent > > Documents;
+
+ enum ContainerOperation
+ {
+ E_REPLACED,
+ E_REMOVED,
+ E_INSERTED
+ };
+
+ enum ListenerType
+ {
+ ApproveListeners,
+ ContainerListemers
+ };
+
+private:
+ PContainerApprove m_pElementApproval;
+
+protected:
+ // we can't just hold a vector of XContentRefs, as after initialization they're all empty
+ // cause we load them only on access
+ std::vector<Documents::iterator>
+ m_aDocuments; // for an efficient index access
+ Documents m_aDocumentMap; // for an efficient name access
+
+ ::comphelper::OInterfaceContainerHelper2
+ m_aApproveListeners;
+ ::comphelper::OInterfaceContainerHelper2
+ m_aContainerListeners;
+
+ bool m_bInPropertyChange;
+ bool m_bCheckSlash;
+
+protected:
+ /** Additionally to our own approvals which new elements must pass, derived classes
+ can specify an additional approval instance here.
+
+ Every time a new element is inserted into the container (or an element is replaced
+ with a new one), this new element must pass our own internal approval, plus the approval
+ given here.
+ */
+ void setElementApproval( PContainerApprove _pElementApproval ) { m_pElementApproval = _pElementApproval; }
+ const PContainerApprove& getElementApproval() const { return m_pElementApproval; }
+
+protected:
+ virtual ~ODefinitionContainer() override;
+
+ const ODefinitionContainer_Impl& getDefinitions() const
+ {
+ return dynamic_cast< const ODefinitionContainer_Impl& >( *m_pImpl );
+ }
+
+ ODefinitionContainer_Impl& getDefinitions()
+ {
+ return dynamic_cast< ODefinitionContainer_Impl& >( *m_pImpl );
+ }
+public:
+ /** constructs the container.
+ */
+ ODefinitionContainer(
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ , const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ , const TContentPtr& _pImpl
+ , bool _bCheckSlash = true
+ );
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// css::container::XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+// css::container::XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+// css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 _nIndex ) override;
+
+// css::container::XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& _rName ) override;
+
+// css::container::XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+
+// css::container::XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+// css::container::XContainer
+ virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+ virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+
+ // XContainerApproveBroadcaster
+ virtual void SAL_CALL addContainerApproveListener( const css::uno::Reference< css::container::XContainerApproveListener >& Listener ) override;
+ virtual void SAL_CALL removeContainerApproveListener( const css::uno::Reference< css::container::XContainerApproveListener >& Listener ) override;
+
+// css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+ // XVetoableChangeListener
+ virtual void SAL_CALL vetoableChange( const css::beans::PropertyChangeEvent& aEvent ) override;
+
+protected:
+ // helper
+ virtual void SAL_CALL disposing() override;
+
+ /** create an object from its persistent data within the configuration. To be overwritten by derived classes.
+ @param _rName the name the object has within the container
+ @return the newly created object or an empty reference if something went wrong
+ */
+ virtual css::uno::Reference< css::ucb::XContent > createObject(
+ const OUString& _rName) = 0;
+
+ /** get the object specified by the given name. If desired, the object will be read if not already done so.<BR>
+ @param _rName the object name
+ @param _bReadIfNecessary if sal_True, the object will be created if necessary
+ @return the property set interface of the object. Usually the return value is not NULL, but
+ if so, then the object could not be read from the configuration
+ @throws NoSuchElementException if there is no object with the given name.
+ @see createObject
+ */
+ css::uno::Reference< css::ucb::XContent >
+ implGetByName(const OUString& _rName, bool _bCreateIfNecessary);
+
+ /** quickly checks if there already is an element with a given name. No access to the configuration occurs, i.e.
+ if there is such an object which is not already loaded, it won't be loaded now.
+ @param _rName the object name to check
+ @return sal_True if there already exists such an object
+ */
+ virtual bool checkExistence(const OUString& _rName);
+
+ /** append a new object to the container. No plausibility checks are done, e.g. if the object is non-NULL or
+ if the name is already used by another object or anything like this. This method is for derived classes
+ which may support different methods to create and/or append objects, and don't want to deal with the
+ internal structures of this class.<BR>
+ The old component will not be disposed, this is the callers responsibility, too.
+ @param _rName the name of the new object
+ @param _rxNewObject the new object (not surprising, is it ?)
+ @see createConfigKey
+ @see implReplace
+ @see implRemove
+ */
+ void implAppend(
+ const OUString& _rName,
+ const css::uno::Reference< css::ucb::XContent >& _rxNewObject
+ );
+
+ /** remove all references to an object from the container. No plausibility checks are done, e.g. whether
+ or not there exists an object with the given name. This is the responsibility of the caller.<BR>
+ Additionally the node for the given object will be removed from the registry (including all sub nodes).<BR>
+ The old component will not be disposed, this is the callers responsibility, too.
+ @param _rName the objects name
+ @see implReplace
+ @see implAppend
+ */
+ void implRemove(const OUString& _rName);
+
+ /** remove an object in the container. No plausibility checks are done, e.g. whether
+ or not there exists an object with the given name or the object is non-NULL. This is the responsibility of the caller.<BR>
+ Additionally all object-related information within the registry will be deleted. The new object config node,
+ where the caller may want to store the new objects information, is returned.<BR>
+ The old component will not be disposed, this is the callers responsibility, too.
+ @param _rName the objects name
+ @param _rxNewObject the new object
+ @param _rNewObjectNode the configuration node where the new object may be stored
+ @see implAppend
+ @see implRemove
+ */
+ void implReplace(
+ const OUString& _rName,
+ const css::uno::Reference< css::ucb::XContent >& _rxNewObject
+ );
+
+ /** notifies our container/approve listeners
+ */
+ void notifyByName(
+ ::osl::ResettableMutexGuard& _rGuard,
+ const OUString& _rName,
+ const css::uno::Reference< css::ucb::XContent >& _xNewElement,
+ const css::uno::Reference< css::ucb::XContent >& xOldElement,
+ ContainerOperation _eOperation,
+ ListenerType _eType
+ );
+
+ operator css::uno::Reference< css::uno::XInterface > () const
+ {
+ return const_cast< XContainer* >( static_cast< const XContainer* >( this ) );
+ }
+
+private:
+ void addObjectListener(const css::uno::Reference< css::ucb::XContent >& _xNewObject);
+ void removeObjectListener(const css::uno::Reference< css::ucb::XContent >& _xNewObject);
+
+ /** approve that the object given may be inserted into the container.
+ Should be overridden by derived classes,
+ the default implementation just checks the object to be non-void.
+
+ @throws IllegalArgumentException
+ if the name or the object are invalid
+ @throws ElementExistException
+ if the object already exists in the container, or another object with the same name
+ already exists
+ @throws WrappedTargetException
+ if another error occurs which prevents insertion of the object into the container
+ */
+ void approveNewObject(
+ const OUString& _sName,
+ const css::uno::Reference< css::ucb::XContent >& _rxObject
+ ) const;
+
+ bool impl_haveAnyListeners_nothrow() const
+ {
+ return ( m_aContainerListeners.getLength() > 0 ) || ( m_aApproveListeners.getLength() > 0 );
+ }
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/documentevents.hxx b/dbaccess/source/core/inc/documentevents.hxx
new file mode 100644
index 000000000..e7f7ef9ff
--- /dev/null
+++ b/dbaccess/source/core/inc/documentevents.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+#include <map>
+
+namespace dbaccess
+{
+
+ typedef std::map< OUString, css::uno::Sequence< css::beans::PropertyValue > >
+ DocumentEventsData;
+
+ // DocumentEvents
+ struct DocumentEvents_Data;
+
+ typedef ::cppu::WeakImplHelper< css::container::XNameReplace
+ > DocumentEvents_Base;
+
+ class DocumentEvents :public DocumentEvents_Base
+ {
+ public:
+ DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData );
+ virtual ~DocumentEvents() override;
+
+ DocumentEvents(const DocumentEvents&) = delete;
+ const DocumentEvents& operator=(const DocumentEvents&) = delete;
+
+ static bool needsSynchronousNotification( std::u16string_view _rEventName );
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ private:
+ std::unique_ptr< DocumentEvents_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/migrwarndlg.hxx b/dbaccess/source/core/inc/migrwarndlg.hxx
new file mode 100644
index 000000000..24bacf300
--- /dev/null
+++ b/dbaccess/source/core/inc/migrwarndlg.hxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace dbaccess
+{
+class MigrationWarnDialog : public weld::MessageDialogController
+{
+ std::unique_ptr<weld::Button> m_xLater;
+
+public:
+ MigrationWarnDialog(weld::Window* pParent);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/object.hxx b/dbaccess/source/core/inc/object.hxx
new file mode 100644
index 000000000..a947f9c57
--- /dev/null
+++ b/dbaccess/source/core/inc/object.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+enum ObjectType
+{
+ dbaTable,
+ dbaQuery,
+ dbaForm,
+ dbaReport
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/objectnameapproval.hxx b/dbaccess/source/core/inc/objectnameapproval.hxx
new file mode 100644
index 000000000..ddd538c79
--- /dev/null
+++ b/dbaccess/source/core/inc/objectnameapproval.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "containerapprove.hxx"
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace dbaccess
+{
+
+ // ObjectNameApproval
+ struct ObjectNameApproval_Impl;
+ /** implementation of the IContainerApprove interface which approves
+ elements for insertion into a query or tables container.
+
+ The only check done by this instance is whether the query name is
+ not already used, taking into account that in some databases, queries
+ and tables share the same namespace.
+
+ The class is not thread-safe.
+ */
+ class ObjectNameApproval : public IContainerApprove
+ {
+ std::unique_ptr< ObjectNameApproval_Impl > m_pImpl;
+
+ public:
+ enum ObjectType
+ {
+ TypeQuery,
+ TypeTable
+ };
+
+ public:
+ /** constructs the instance
+
+ @param _rxConnection
+ the connection relative to which the names should be checked. This connection
+ will be held weak. In case it is closed, subsequent calls to this instance's
+ methods throw a DisposedException.
+ @param _eType
+ specifies which type of objects is to be approved with this instance
+ */
+ ObjectNameApproval(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ ObjectType _eType
+ );
+ virtual ~ObjectNameApproval() override;
+
+ // IContainerApprove
+ virtual void approveElement( const OUString& _rName ) override;
+
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/preparedstatement.hxx b/dbaccess/source/core/inc/preparedstatement.hxx
new file mode 100644
index 000000000..cea06d79a
--- /dev/null
+++ b/dbaccess/source/core/inc/preparedstatement.hxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include "statement.hxx"
+#include "column.hxx"
+
+namespace dbaccess
+{
+
+ // OPreparedStatement
+
+ class OPreparedStatement : public OStatementBase,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XParameters,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::sdbcx::XColumnsSupplier,
+ public css::lang::XServiceInfo
+ {
+ std::unique_ptr<OColumns> m_pColumns;
+ css::uno::Reference< css::sdbc::XParameters > m_xAggregateAsParameters;
+
+ public:
+ OPreparedStatement(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement);
+ virtual ~OPreparedStatement() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdbc::XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // css::sdbc::XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/querycomposer.hxx b/dbaccess/source/core/inc/querycomposer.hxx
new file mode 100644
index 000000000..c5d764d98
--- /dev/null
+++ b/dbaccess/source/core/inc/querycomposer.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdb/XSQLQueryComposer.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase5.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <apitools.hxx>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+
+
+namespace dbaccess
+{
+ typedef ::cppu::ImplHelper5< css::sdb::XSQLQueryComposer,
+ css::sdb::XParametersSupplier,
+ css::sdbcx::XTablesSupplier,
+ css::sdbcx::XColumnsSupplier,
+ css::lang::XServiceInfo > OQueryComposer_BASE;
+
+ class OQueryComposer : public ::cppu::BaseMutex,
+ public OSubComponent,
+ public OQueryComposer_BASE
+ {
+ std::vector< OUString> m_aFilters;
+ std::vector< OUString> m_aOrders;
+ OUString m_sOrgFilter;
+ OUString m_sOrgOrder;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xComposer;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xComposerHelper;
+
+ protected:
+ virtual void SAL_CALL disposing() override;
+ virtual ~OQueryComposer() override;
+ public:
+
+ OQueryComposer( const css::uno::Reference< css::sdbc::XConnection>& _xConnection );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ // XSQLQueryComposer
+ virtual OUString SAL_CALL getQuery( ) override;
+ virtual void SAL_CALL setQuery( const OUString& command ) override;
+ virtual OUString SAL_CALL getComposedQuery( ) override;
+ virtual OUString SAL_CALL getFilter( ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getStructuredFilter( ) override;
+ virtual OUString SAL_CALL getOrder( ) override;
+ virtual void SAL_CALL appendFilterByColumn( const css::uno::Reference< css::beans::XPropertySet >& column ) override;
+ virtual void SAL_CALL appendOrderByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool ascending ) override;
+ virtual void SAL_CALL setFilter( const OUString& filter ) override;
+ virtual void SAL_CALL setOrder( const OUString& order ) override;
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+ // XParametersSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getParameters( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/querycontainer.hxx b/dbaccess/source/core/inc/querycontainer.hxx
new file mode 100644
index 000000000..a04a1ddf3
--- /dev/null
+++ b/dbaccess/source/core/inc/querycontainer.hxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase5.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/container/XContainerApproveListener.hpp>
+
+#include "definitioncontainer.hxx"
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+
+ typedef ::cppu::ImplHelper5 < css::container::XContainerListener
+ , css::container::XContainerApproveListener
+ , css::sdbcx::XDataDescriptorFactory
+ , css::sdbcx::XAppend
+ , css::sdbcx::XDrop
+ > OQueryContainer_Base;
+
+ // OQueryContainer
+ class OQueryContainer : public ODefinitionContainer
+ , public OQueryContainer_Base
+ {
+ private:
+ ::dbtools::WarningsContainer* m_pWarnings;
+ css::uno::Reference< css::container::XNameContainer >
+ m_xCommandDefinitions;
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xConnection;
+ // possible actions on our "aggregate"
+ enum class AggregateAction { NONE, Inserting };
+ AggregateAction m_eDoingCurrently;
+
+ /** a class which automatically resets m_eDoingCurrently in its destructor
+ */
+ class OAutoActionReset; // just for the following friend declaration
+ friend class OAutoActionReset;
+ class OAutoActionReset
+ {
+ OQueryContainer& m_rActor;
+ public:
+ OAutoActionReset(OQueryContainer& _rActor) : m_rActor(_rActor) { }
+ ~OAutoActionReset() { m_rActor.m_eDoingCurrently = AggregateAction::NONE; }
+ };
+
+ // ODefinitionContainer
+ virtual css::uno::Reference< css::ucb::XContent > createObject( const OUString& _rName) override;
+ virtual bool checkExistence(const OUString& _rName) override;
+
+ // helper
+ virtual void SAL_CALL disposing() override;
+ virtual ~OQueryContainer() override;
+
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+
+ @param _pWarnings
+ specifies a warnings container (May be <NULL/>)
+
+ Any errors which occur during the lifetime of the query container,
+ which cannot be reported as exceptions (for instance in methods where throwing an SQLException is
+ not allowed) will be appended to this container.</p>
+ <p>The caller is responsible for ensuring the lifetime of the object pointed to by this parameter.
+ */
+ OQueryContainer(
+ const css::uno::Reference< css::container::XNameContainer >& _rxCommandDefinitions,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings
+ );
+
+ void init();
+
+ public:
+ static rtl::Reference<OQueryContainer> create(
+ const css::uno::Reference< css::container::XNameContainer >& _rxCommandDefinitions,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings
+ );
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+ DECLARE_SERVICE_INFO();
+
+ // css::container::XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ // XContainerApproveListener
+ virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveInsertElement( const css::container::ContainerEvent& Event ) override;
+ virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveReplaceElement( const css::container::ContainerEvent& Event ) override;
+ virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveRemoveElement( const css::container::ContainerEvent& Event ) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // css::sdbcx::XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+ // css::sdbcx::XAppend
+ virtual void SAL_CALL appendByDescriptor( const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ // css::sdbcx::XDrop
+ virtual void SAL_CALL dropByName( const OUString& elementName ) override;
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+ // css::container::XElementAccess
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+ // css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ // css::container::XNameAccess
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+
+ private:
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+ // helper
+ /** create a query object wrapping a CommandDefinition given by name. To retrieve the object, the CommandDescription
+ container will be asked for the given name.<BR>
+ The returned object is acquired once.
+ */
+ css::uno::Reference< css::ucb::XContent > implCreateWrapper(const OUString& _rName);
+ /// create a query object wrapping a CommandDefinition. The returned object is acquired once.
+ css::uno::Reference< css::ucb::XContent > implCreateWrapper(const css::uno::Reference< css::ucb::XContent >& _rxCommandDesc);
+
+ };
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx b/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx
new file mode 100644
index 000000000..e5f924650
--- /dev/null
+++ b/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <vector>
+#include <memory>
+
+namespace dbaccess
+{
+
+ // DatabaseDocumentRecovery
+ struct DatabaseDocumentRecovery_Data;
+ class DatabaseDocumentRecovery
+ {
+ public:
+ DatabaseDocumentRecovery(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext
+ );
+ ~DatabaseDocumentRecovery();
+
+ /** saves the modified sub components of the given controller(s) to the "recovery" sub storage of the document
+ storage.
+
+ @throws css::uno::Exception
+ in case of an error.
+ */
+ void saveModifiedSubComponents(
+ const css::uno::Reference< css::embed::XStorage >& i_rTargetStorage,
+ const std::vector< css::uno::Reference< css::frame::XController > >& i_rControllers
+ );
+
+ /** recovery sub components from the given document storage, if applicable
+
+ If the given document storage does not contain a recovery folder, the method silently returns.
+
+ @throws css::uno::Exception
+ in case of an error.
+ */
+ void recoverSubDocuments(
+ const css::uno::Reference< css::embed::XStorage >& i_rDocumentStorage,
+ const css::uno::Reference< css::frame::XController >& i_rTargetController
+ );
+
+ private:
+ const std::unique_ptr< DatabaseDocumentRecovery_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/sdbcoretools.hxx b/dbaccess/source/core/inc/sdbcoretools.hxx
new file mode 100644
index 000000000..5b100dcf1
--- /dev/null
+++ b/dbaccess/source/core/inc/sdbcoretools.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaccess
+{
+
+ void notifyDataSourceModified(const css::uno::Reference< css::uno::XInterface >& _rxObject);
+
+ css::uno::Reference< css::uno::XInterface >
+ getDataSource( const css::uno::Reference< css::uno::XInterface >& _rxDependentObject );
+
+ /** retrieves a to-be-displayed string for a given caught exception;
+ */
+ OUString extractExceptionMessage( const css::uno::Reference< css::uno::XComponentContext >& _rContext, const css::uno::Any& _rError );
+
+ namespace tools
+ {
+ namespace stor
+ {
+ bool storageIsWritable_nothrow(
+ const css::uno::Reference< css::embed::XStorage >& _rxStorage
+ );
+
+ /// commits a given storage if it's not readonly
+ bool commitStorageIfWriteable(
+ const css::uno::Reference< css::embed::XStorage >& _rxStorage
+ );
+ }
+
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/statement.hxx b/dbaccess/source/core/inc/statement.hxx
new file mode 100644
index 000000000..f43704068
--- /dev/null
+++ b/dbaccess/source/core/inc/statement.hxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <cppuhelper/propshlp.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <apitools.hxx>
+
+
+// OStatementBase
+
+class OStatementBase : public cppu::BaseMutex,
+ public OSubComponent,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper < OStatementBase >,
+ public css::util::XCancellable,
+ public css::sdbc::XWarningsSupplier,
+ public css::sdbc::XPreparedBatchExecution,
+ public css::sdbc::XMultipleResults,
+ public css::sdbc::XCloseable,
+ public css::sdbc::XGeneratedResultSet
+{
+protected:
+ ::osl::Mutex m_aCancelMutex;
+
+ css::uno::WeakReferenceHelper m_aResultSet;
+ css::uno::Reference< css::beans::XPropertySet > m_xAggregateAsSet;
+ css::uno::Reference< css::util::XCancellable > m_xAggregateAsCancellable;
+ bool m_bUseBookmarks;
+ bool m_bEscapeProcessing;
+
+ virtual ~OStatementBase() override;
+
+public:
+ OStatementBase(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement);
+
+
+// css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+// css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+// comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+// cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+// css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+// css::util::XCancellable
+ virtual void SAL_CALL cancel( ) override;
+
+// css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+// css::sdbc::XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+
+// css::sdbc::XPreparedBatchExecution
+ virtual void SAL_CALL addBatch( ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+// css::sdbc::XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override;
+
+// Helper
+ void disposeResultSet();
+
+protected:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+
+// OStatement
+
+typedef ::cppu::ImplHelper3 < css::sdbc::XStatement
+ , css::lang::XServiceInfo
+ , css::sdbc::XBatchExecution
+ > OStatement_IFACE;
+class OStatement :public OStatementBase
+ ,public OStatement_IFACE
+{
+private:
+ css::uno::Reference< css::sdbc::XStatement > m_xAggregateStatement;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xComposer;
+ bool m_bAttemptedComposerCreation;
+
+public:
+ OStatement(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement);
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// css::sdbc::XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+
+ using OStatementBase::addBatch;
+
+private:
+ /** does escape processing for the given SQL command, if the our EscapeProcessing
+ property allows so.
+ */
+ OUString impl_doEscapeProcessing_nothrow( const OUString& _rSQL ) const;
+ bool impl_ensureComposer_nothrow() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/table.hxx b/dbaccess/source/core/inc/table.hxx
new file mode 100644
index 000000000..8c29bff44
--- /dev/null
+++ b/dbaccess/source/core/inc/table.hxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include "datasettings.hxx"
+#include "column.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace dbaccess
+{
+
+ // OTables
+ class ODBTable;
+ class OContainerMediator;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< ODBTable > ODBTable_PROP;
+ typedef ::connectivity::OTableHelper OTable_Base;
+
+ class ODBTable :public ODataSettings_Base
+ ,public ODBTable_PROP
+ ,public OTable_Base
+ ,public IColumnFactory
+ {
+ private:
+ ::rtl::Reference< OContainerMediator > m_pColumnMediator;
+
+ protected:
+ css::uno::Reference< css::container::XNameAccess > m_xColumnDefinitions;
+ css::uno::Reference< css::container::XNameAccess > m_xDriverColumns;
+
+ // <properties>
+ sal_Int32 m_nPrivileges;
+ // </properties>
+
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ // IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+
+ /** creates the column collection for the table
+ @param _rNames
+ The column names.
+ */
+ virtual ::connectivity::sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the key collection for the table
+ @param _rNames
+ The key names.
+ */
+ virtual ::connectivity::sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the index collection for the table
+ @param _rNames
+ The index names.
+ */
+ virtual ::connectivity::sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ public:
+ /** constructs a wrapper supporting the com.sun.star.sdb.Table service.<BR>
+ @param _rxConn the connection the table belongs to
+ @param _rxTable the table from the driver can be null
+ @param _rCatalog the name of the catalog the table belongs to. May be empty.
+ @param _rSchema the name of the schema the table belongs to. May be empty.
+ @param _rName the name of the table
+ @param _rType the type of the table, as supplied by the driver
+ @param _rDesc the description of the table, as supplied by the driver
+ @throws css::sdbc::SQLException
+ */
+ ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const css::uno::Reference< css::sdbc::XConnection >& _rxConn
+ ,const OUString& _rCatalog
+ , const OUString& _rSchema
+ , const OUString& _rName
+ ,const OUString& _rType
+ , const OUString& _rDesc
+ ,const css::uno::Reference< css::container::XNameAccess >& _rxColumnDefinitions);
+
+ /// @throws css::sdbc::SQLException
+ ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const css::uno::Reference< css::sdbc::XConnection >& _rxConn);
+ virtual ~ODBTable() override;
+
+ // ODescriptor
+ virtual void construct() override;
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // css::beans::XPropertySet
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override;
+
+ // css::sdbcx::XRename,
+ virtual void SAL_CALL rename( const OUString& _rNewName ) override;
+
+ // css::sdbcx::XAlterTable,
+ virtual void SAL_CALL alterColumnByName( const OUString& _rName, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+
+ private:
+ using OTable_Base::createArrayHelper;
+ using OTable_Base::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/tablecontainer.hxx b/dbaccess/source/core/inc/tablecontainer.hxx
new file mode 100644
index 000000000..44358e4e2
--- /dev/null
+++ b/dbaccess/source/core/inc/tablecontainer.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <cppuhelper/implbase1.hxx>
+#include <rtl/ref.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include "FilteredContainer.hxx"
+#include "RefreshListener.hxx"
+
+namespace dbaccess
+{
+ // OTableContainer
+ class OContainerMediator;
+
+ class OTableContainer : public OFilteredContainer,
+ public ::cppu::ImplHelper1< css::container::XContainerListener>
+ {
+ css::uno::Reference< css::container::XNameContainer > m_xTableDefinitions;
+ ::rtl::Reference< OContainerMediator > m_pTableMediator;
+
+ // OFilteredContainer
+ virtual void addMasterContainerListener() override;
+ virtual void removeMasterContainerListener() override;
+ virtual OUString getTableTypeRestriction() const override;
+
+ // ::connectivity::sdbcx::OCollection
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ virtual void disposing() override;
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ public:
+ virtual void SAL_CALL acquire() noexcept override { OFilteredContainer::acquire();}
+ virtual void SAL_CALL release() noexcept override { OFilteredContainer::release();}
+
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+ @param _rParent the object which acts as parent for the container.
+ all refcounting is rerouted to this object
+ @param _rMutex the access safety object of the parent
+ @param _rTableFilter restricts the visible tables by name
+ @param _rTableTypeFilter restricts the visible tables by type
+ @see construct
+ */
+ OTableContainer( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xCon,
+ bool _bCase,
+ const css::uno::Reference< css::container::XNameContainer >& _xTableDefinitions,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend
+ );
+
+ virtual ~OTableContainer() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/veto.hxx b/dbaccess/source/core/inc/veto.hxx
new file mode 100644
index 000000000..5608e87d1
--- /dev/null
+++ b/dbaccess/source/core/inc/veto.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/XVeto.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace dbaccess
+{
+
+ // Veto
+ typedef ::cppu::WeakImplHelper< css::util::XVeto
+ > Veto_Base;
+ /** implements css::util::XVeto
+ */
+ class Veto : public Veto_Base
+ {
+ private:
+ const css::uno::Any m_aDetails;
+
+ public:
+ Veto( const css::uno::Any& _rDetails );
+
+ virtual OUString SAL_CALL getReason() override;
+ virtual css::uno::Any SAL_CALL getDetails() override;
+
+ protected:
+ virtual ~Veto() override;
+
+ private:
+ Veto( const Veto& ) = delete;
+ Veto& operator=( const Veto& ) = delete;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/viewcontainer.hxx b/dbaccess/source/core/inc/viewcontainer.hxx
new file mode 100644
index 000000000..2f7f48cec
--- /dev/null
+++ b/dbaccess/source/core/inc/viewcontainer.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <cppuhelper/implbase1.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+
+#include "FilteredContainer.hxx"
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+ // OViewContainer
+ class OViewContainer : public OFilteredContainer,
+ public ::cppu::ImplHelper1< css::container::XContainerListener>
+ {
+ public:
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+ @param _rParent the object which acts as parent for the container.
+ all refcounting is rerouted to this object
+ @param _rMutex the access safety object of the parent
+ @param _rTableFilter restricts the visible tables by name
+ @param _rTableTypeFilter restricts the visible tables by type
+ @see construct
+ */
+ OViewContainer( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xCon,
+ bool _bCase,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend
+ );
+
+ virtual ~OViewContainer() override;
+
+ protected:
+ // OFilteredContainer overridables
+ virtual OUString getTableTypeRestriction() const override;
+
+ private:
+ virtual void SAL_CALL acquire() noexcept override { OFilteredContainer::acquire();}
+ virtual void SAL_CALL release() noexcept override { OFilteredContainer::release();}
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ // ::connectivity::sdbcx::OCollection
+ virtual ::connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ using OFilteredContainer::disposing;
+
+ bool m_bInElementRemoved;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/ContainerMediator.cxx b/dbaccess/source/core/misc/ContainerMediator.cxx
new file mode 100644
index 000000000..338858c87
--- /dev/null
+++ b/dbaccess/source/core/misc/ContainerMediator.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ContainerMediator.hxx>
+#include <PropertyForward.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <comphelper/property.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+
+OContainerMediator::OContainerMediator( const Reference< XContainer >& _xContainer, const Reference< XNameAccess >& _xSettings )
+ : m_xSettings( _xSettings )
+ , m_xContainer( _xContainer )
+{
+
+ if ( _xSettings.is() && _xContainer.is() )
+ {
+ osl_atomic_increment(&m_refCount);
+ try
+ {
+ m_xContainer->addContainerListener(this);
+ Reference< XContainer > xContainer(_xSettings, UNO_QUERY);
+ if ( xContainer.is() )
+ xContainer->addContainerListener(this);
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "OContainerMediator::OContainerMediator");
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+ else
+ {
+ m_xSettings.clear();
+ m_xContainer.clear();
+ }
+}
+
+OContainerMediator::~OContainerMediator()
+{
+ acquire();
+ impl_cleanup_nothrow();
+}
+
+void OContainerMediator::impl_cleanup_nothrow()
+{
+ try
+ {
+ Reference< XContainer > xContainer( m_xSettings, UNO_QUERY );
+ if ( xContainer.is() )
+ xContainer->removeContainerListener( this );
+ m_xSettings.clear();
+
+ xContainer = m_xContainer;
+ if ( xContainer.is() )
+ xContainer->removeContainerListener( this );
+ m_xContainer.clear();
+
+ m_aForwardList.clear();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OContainerMediator::elementInserted( const ContainerEvent& _rEvent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( _rEvent.Source == m_xSettings && m_xSettings.is() )
+ {
+ OUString sElementName;
+ _rEvent.Accessor >>= sElementName;
+ PropertyForwardList::const_iterator aFind = m_aForwardList.find(sElementName);
+ if ( aFind != m_aForwardList.end() )
+ {
+ Reference< XPropertySet> xDest(_rEvent.Element,UNO_QUERY);
+ aFind->second->setDefinition( xDest );
+ }
+ }
+}
+
+void SAL_CALL OContainerMediator::elementRemoved( const ContainerEvent& _rEvent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ Reference< XContainer > xContainer = m_xContainer;
+ if ( !(_rEvent.Source == xContainer && xContainer.is()) )
+ return;
+
+ OUString sElementName;
+ _rEvent.Accessor >>= sElementName;
+ m_aForwardList.erase(sElementName);
+ try
+ {
+ Reference<XNameContainer> xNameContainer( m_xSettings, UNO_QUERY );
+ if ( xNameContainer.is() && m_xSettings->hasByName( sElementName ) )
+ xNameContainer->removeByName( sElementName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OContainerMediator::elementReplaced( const ContainerEvent& _rEvent )
+{
+ Reference< XContainer > xContainer = m_xContainer;
+ if ( !(_rEvent.Source == xContainer && xContainer.is()) )
+ return;
+
+ OUString sElementName;
+ _rEvent.ReplacedElement >>= sElementName;
+
+ PropertyForwardList::const_iterator aFind = m_aForwardList.find(sElementName);
+ if ( aFind == m_aForwardList.end() )
+ return;
+
+ OUString sNewName;
+ _rEvent.Accessor >>= sNewName;
+ try
+ {
+ Reference<XNameContainer> xNameContainer( m_xSettings, UNO_QUERY_THROW );
+ if ( xNameContainer.is() && m_xSettings->hasByName( sElementName ) )
+ {
+ Reference<XRename> xSource(m_xSettings->getByName(sElementName),UNO_QUERY_THROW);
+ xSource->rename(sNewName);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ aFind->second->setName(sNewName);
+}
+
+void SAL_CALL OContainerMediator::disposing( const EventObject& /*Source*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ impl_cleanup_nothrow();
+}
+
+void OContainerMediator::impl_initSettings_nothrow( const OUString& _rName, const Reference< XPropertySet >& _rxDestination )
+{
+ try
+ {
+ if ( m_xSettings.is() && m_xSettings->hasByName( _rName ) )
+ {
+ Reference< XPropertySet > xSettings( m_xSettings->getByName( _rName ), UNO_QUERY_THROW );
+ ::comphelper::copyProperties( xSettings, _rxDestination );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OContainerMediator::notifyElementCreated( const OUString& _sName, const Reference< XPropertySet >& _xDest )
+{
+ if ( !m_xSettings.is() )
+ return;
+
+ PropertyForwardList::const_iterator aFind = m_aForwardList.find( _sName );
+ if ( aFind != m_aForwardList.end()
+ && aFind->second->getDefinition().is()
+ )
+ {
+ OSL_FAIL( "OContainerMediator::notifyElementCreated: is this really a valid case?" );
+ return;
+ }
+
+ std::vector< OUString > aPropertyList;
+ try
+ {
+ // initially copy from the settings object (if existent) to the newly created object
+ impl_initSettings_nothrow( _sName, _xDest );
+
+ // collect the to-be-monitored properties
+ Reference< XPropertySetInfo > xPSI( _xDest->getPropertySetInfo(), UNO_SET_THROW );
+ const Sequence< Property > aProperties( xPSI->getProperties() );
+ for ( auto const & property : aProperties )
+ {
+ if ( ( property.Attributes & PropertyAttribute::READONLY ) != 0 )
+ continue;
+ if ( ( property.Attributes & PropertyAttribute::BOUND ) == 0 )
+ continue;
+
+ aPropertyList.push_back( property.Name );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ ::rtl::Reference pForward( new OPropertyForward( _xDest, m_xSettings, _sName, aPropertyList ) );
+ m_aForwardList[ _sName ] = pForward;
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/DatabaseDataProvider.cxx b/dbaccess/source/core/misc/DatabaseDataProvider.cxx
new file mode 100644
index 000000000..8695d518c
--- /dev/null
+++ b/dbaccess/source/core/misc/DatabaseDataProvider.cxx
@@ -0,0 +1,1066 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DatabaseDataProvider.hxx>
+#include <strings.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <connectivity/FValue.hxx>
+#include <sal/macros.h>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart/XChartDataArray.hpp>
+
+#include <vector>
+
+// TODO: update for new HavingClause-aware FilterManager
+
+namespace dbaccess
+{
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+
+DatabaseDataProvider::DatabaseDataProvider(uno::Reference< uno::XComponentContext > const & context) :
+ TDatabaseDataProvider(m_aMutex),
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >(
+ context, IMPLEMENTS_PROPERTY_SET, uno::Sequence< OUString >()),
+ m_aParameterManager( m_aMutex, context ),
+ m_xContext(context),
+ m_CommandType(sdb::CommandType::COMMAND), // #i94114
+ m_RowLimit(0),
+ m_EscapeProcessing(true),
+ m_ApplyFilter(true)
+{
+ m_xInternal.set( m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.chart.InternalDataProvider",m_xContext ), uno::UNO_QUERY );
+ m_xRangeConversion.set(m_xInternal,uno::UNO_QUERY);
+ m_xComplexDescriptionAccess.set(m_xInternal,uno::UNO_QUERY);
+
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xRowSet.set( m_xContext->getServiceManager()->createInstanceWithContext(SERVICE_SDB_ROWSET,m_xContext ), uno::UNO_QUERY );
+ m_xAggregate.set(m_xRowSet,uno::UNO_QUERY);
+ m_xAggregateSet.set(m_xRowSet,uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xProp(static_cast< ::cppu::OWeakObject* >( this ),uno::UNO_QUERY);
+ m_aFilterManager.initialize( m_xAggregateSet );
+ m_aParameterManager.initialize( xProp, m_xAggregate );
+ m_xAggregateSet->setPropertyValue(PROPERTY_COMMAND_TYPE,uno::Any(m_CommandType));
+ m_xAggregateSet->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,uno::Any(m_EscapeProcessing));
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+void SAL_CALL DatabaseDataProvider::disposing()
+{
+ m_aParameterManager.dispose(); // (to free any references it may have to me)
+ m_aFilterManager.dispose(); // (ditto)
+
+ m_xParent.clear();
+ m_xAggregateSet.clear();
+ m_xAggregate.clear();
+ m_xRangeConversion.clear();
+ ::comphelper::disposeComponent(m_xRowSet);
+ ::comphelper::disposeComponent(m_xInternal);
+ m_xActiveConnection.clear();
+}
+
+uno::Any DatabaseDataProvider::queryInterface(uno::Type const & type)
+{
+ return TDatabaseDataProvider::queryInterface(type);
+}
+
+// XServiceInfo
+OUString SAL_CALL DatabaseDataProvider::getImplementationName( )
+{
+ return "com.sun.star.comp.dbaccess.DatabaseDataProvider";
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getSupportedServiceNames( )
+{
+ return { "com.sun.star.chart2.data.DatabaseDataProvider" };
+}
+
+// lang::XInitialization:
+void SAL_CALL DatabaseDataProvider::initialize(const uno::Sequence< uno::Any > & aArguments)
+{
+ osl::MutexGuard g(m_aMutex);
+ const uno::Any* pIter = aArguments.getConstArray();
+ const uno::Any* pEnd = pIter + aArguments.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( !m_xActiveConnection.is() )
+ (*pIter) >>= m_xActiveConnection;
+ else if ( !m_xHandler.is() )
+ (*pIter) >>= m_xHandler;
+ }
+ m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, uno::Any( m_xActiveConnection ) );
+}
+
+// chart2::data::XDataProvider:
+sal_Bool SAL_CALL DatabaseDataProvider::createDataSourcePossible(const uno::Sequence< beans::PropertyValue > & _aArguments)
+{
+ const beans::PropertyValue* pArgIter = _aArguments.getConstArray();
+ const beans::PropertyValue* pArgEnd = pArgIter + _aArguments.getLength();
+ for(;pArgIter != pArgEnd;++pArgIter)
+ {
+ if ( pArgIter->Name == "DataRowSource" )
+ {
+ css::chart::ChartDataRowSource eRowSource = css::chart::ChartDataRowSource_COLUMNS;
+ pArgIter->Value >>= eRowSource;
+ if ( eRowSource != css::chart::ChartDataRowSource_COLUMNS )
+ return false;
+ }
+ else if ( pArgIter->Name == "CellRangeRepresentation" )
+ {
+ OUString sRange;
+ pArgIter->Value >>= sRange;
+ if ( sRange != "all" )
+ return false;
+ }
+ else if ( pArgIter->Name == "FirstCellAsLabel" )
+ {
+ bool bFirstCellAsLabel = true;
+ pArgIter->Value >>= bFirstCellAsLabel;
+ if ( !bFirstCellAsLabel )
+ return false;
+ }
+ }
+ return true;
+}
+
+uno::Reference< chart2::data::XDataSource > SAL_CALL DatabaseDataProvider::createDataSource(const uno::Sequence< beans::PropertyValue > & _aArguments)
+{
+ osl::ResettableMutexGuard aClearForNotifies(m_aMutex);
+ if ( createDataSourcePossible(_aArguments) )
+ {
+ try
+ {
+ uno::Reference< chart::XChartDataArray> xChartData( m_xInternal, uno::UNO_QUERY_THROW );
+ xChartData->setData( uno::Sequence< uno::Sequence< double > >() );
+ xChartData->setColumnDescriptions( uno::Sequence< OUString >() );
+ if ( m_xInternal->hasDataByRangeRepresentation( OUString::number( 0 ) ) )
+ m_xInternal->deleteSequence(0);
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ ::comphelper::NamedValueCollection aArgs( _aArguments );
+ const bool bHasCategories = aArgs.getOrDefault( "HasCategories", true );
+ uno::Sequence< OUString > aColumnNames =
+ aArgs.getOrDefault( "ColumnDescriptions", uno::Sequence< OUString >() );
+
+ bool bRet = false;
+ if ( !m_Command.isEmpty() && m_xActiveConnection.is() )
+ {
+ try
+ {
+ impl_fillRowSet_throw();
+ if ( impl_fillParameters_nothrow(aClearForNotifies) )
+ m_xRowSet->execute();
+ impl_fillInternalDataProvider_throw(bHasCategories,aColumnNames);
+ bRet = true;
+ }
+ catch(const uno::Exception& /*e*/)
+ {
+ }
+ }
+ if ( !bRet ) // no command set or an error occurred, use Internal data handler
+ {
+ uno::Reference< lang::XInitialization> xIni(m_xInternal,uno::UNO_QUERY);
+ if ( xIni.is() )
+ {
+ beans::NamedValue aParam("CreateDefaultData",uno::Any(true));
+ uno::Sequence< uno::Any > aInitArgs{ uno::Any(aParam) };
+ xIni->initialize(aInitArgs);
+ }
+ }
+
+ }
+ return m_xInternal->createDataSource(_aArguments);
+}
+
+uno::Sequence< beans::PropertyValue > SAL_CALL DatabaseDataProvider::detectArguments(const uno::Reference< chart2::data::XDataSource > & _xDataSource)
+{
+ ::comphelper::NamedValueCollection aArguments;
+ aArguments.put( "CellRangeRepresentation", uno::Any( OUString( "all" ) ) );
+ aArguments.put( "DataRowSource", uno::Any( chart::ChartDataRowSource_COLUMNS ) );
+ // internal data always contains labels
+ aArguments.put( "FirstCellAsLabel", uno::Any( true ) );
+
+ bool bHasCategories = false;
+ if( _xDataSource.is())
+ {
+ uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences(_xDataSource->getDataSequences());
+ const sal_Int32 nCount( aSequences.getLength());
+ for( sal_Int32 nIdx=0; nIdx<nCount; ++nIdx )
+ {
+ if( aSequences[nIdx].is() )
+ {
+ uno::Reference< beans::XPropertySet > xSeqProp( aSequences[nIdx]->getValues(), uno::UNO_QUERY );
+ OUString aRole;
+ if ( xSeqProp.is()
+ && ( xSeqProp->getPropertyValue( "Role" ) >>= aRole )
+ && aRole == "categories"
+ )
+ {
+ bHasCategories = true;
+ break;
+ }
+ }
+ }
+ }
+ aArguments.put( "HasCategories", uno::Any( bHasCategories ) );
+ return aArguments.getPropertyValues();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::createDataSequenceByRangeRepresentationPossible(const OUString & /*aRangeRepresentation*/)
+{
+ return true;
+}
+
+uno::Any DatabaseDataProvider::impl_getNumberFormatKey_nothrow(const OUString & _sRangeRepresentation) const
+{
+ std::map< OUString,css::uno::Any>::const_iterator aFind = m_aNumberFormats.find(_sRangeRepresentation);
+ if ( aFind != m_aNumberFormats.end() )
+ return aFind->second;
+ return uno::Any(sal_Int32(0));
+}
+
+uno::Reference< chart2::data::XDataSequence > SAL_CALL DatabaseDataProvider::createDataSequenceByRangeRepresentation(const OUString & _sRangeRepresentation)
+{
+ osl::MutexGuard g(m_aMutex);
+ uno::Reference< chart2::data::XDataSequence > xData = m_xInternal->createDataSequenceByRangeRepresentation(_sRangeRepresentation);
+ uno::Reference<beans::XPropertySet> xProp(xData,uno::UNO_QUERY);
+ static constexpr OUStringLiteral s_sNumberFormatKey = u"NumberFormatKey";
+ if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(s_sNumberFormatKey) )
+ {
+ xProp->setPropertyValue(s_sNumberFormatKey,impl_getNumberFormatKey_nothrow(_sRangeRepresentation));
+ }
+ return xData;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+SAL_CALL DatabaseDataProvider::createDataSequenceByValueArray(
+ const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/, const OUString& /*aRoleQualifier*/ )
+{
+ return uno::Reference<chart2::data::XDataSequence>();
+}
+
+uno::Sequence< uno::Sequence< OUString > > SAL_CALL DatabaseDataProvider::getComplexRowDescriptions()
+{
+ return m_xComplexDescriptionAccess->getComplexRowDescriptions();
+}
+
+void SAL_CALL DatabaseDataProvider::setComplexRowDescriptions( const uno::Sequence< uno::Sequence< OUString > >& aRowDescriptions )
+{
+ m_xComplexDescriptionAccess->setComplexRowDescriptions(aRowDescriptions);
+}
+
+uno::Sequence< uno::Sequence< OUString > > SAL_CALL DatabaseDataProvider::getComplexColumnDescriptions()
+{
+ return m_xComplexDescriptionAccess->getComplexColumnDescriptions();
+}
+
+void SAL_CALL DatabaseDataProvider::setComplexColumnDescriptions( const uno::Sequence< uno::Sequence< OUString > >& aColumnDescriptions )
+{
+ m_xComplexDescriptionAccess->setComplexColumnDescriptions(aColumnDescriptions);
+}
+
+// ____ XChartDataArray ____
+uno::Sequence< uno::Sequence< double > > SAL_CALL DatabaseDataProvider::getData()
+{
+ return m_xComplexDescriptionAccess->getData();
+}
+
+void SAL_CALL DatabaseDataProvider::setData( const uno::Sequence< uno::Sequence< double > >& rDataInRows )
+{
+ m_xComplexDescriptionAccess->setData(rDataInRows);
+}
+
+void SAL_CALL DatabaseDataProvider::setRowDescriptions( const uno::Sequence< OUString >& aRowDescriptions )
+{
+ m_xComplexDescriptionAccess->setRowDescriptions(aRowDescriptions);
+}
+
+void SAL_CALL DatabaseDataProvider::setColumnDescriptions( const uno::Sequence< OUString >& aColumnDescriptions )
+{
+ m_xComplexDescriptionAccess->setColumnDescriptions(aColumnDescriptions);
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getRowDescriptions()
+{
+ return m_xComplexDescriptionAccess->getRowDescriptions();
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getColumnDescriptions()
+{
+ return m_xComplexDescriptionAccess->getColumnDescriptions();
+}
+
+// ____ XChartData (base of XChartDataArray) ____
+void SAL_CALL DatabaseDataProvider::addChartDataChangeEventListener(const uno::Reference< css::chart::XChartDataChangeEventListener >& x)
+{
+ m_xComplexDescriptionAccess->addChartDataChangeEventListener(x);
+}
+
+void SAL_CALL DatabaseDataProvider::removeChartDataChangeEventListener(const uno::Reference< css::chart::XChartDataChangeEventListener >& x)
+{
+ m_xComplexDescriptionAccess->removeChartDataChangeEventListener(x);
+}
+
+double SAL_CALL DatabaseDataProvider::getNotANumber()
+{
+ return m_xComplexDescriptionAccess->getNotANumber();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isNotANumber( double nNumber )
+{
+ return m_xComplexDescriptionAccess->isNotANumber(nNumber);
+}
+
+uno::Reference< sheet::XRangeSelection > SAL_CALL DatabaseDataProvider::getRangeSelection()
+{
+ // TODO: Exchange the default return implementation for "getRangeSelection" !!!
+ // Exchange the default return implementation.
+ // NOTE: Default initialized polymorphic structs can cause problems because of
+ // missing default initialization of primitive types of some C++ compilers or
+ // different Any initialization in Java and C++ polymorphic structs.
+ return uno::Reference< sheet::XRangeSelection >();
+}
+
+// chart2::data::XRangeXMLConversion:
+OUString SAL_CALL DatabaseDataProvider::convertRangeToXML(const OUString & _sRangeRepresentation)
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_xRangeConversion->convertRangeToXML(_sRangeRepresentation);
+}
+
+OUString SAL_CALL DatabaseDataProvider::convertRangeFromXML(const OUString & _sXMLRange)
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_xRangeConversion->convertRangeFromXML(_sXMLRange);
+}
+
+// com.sun.star.beans.XPropertySet:
+uno::Reference< beans::XPropertySetInfo > SAL_CALL DatabaseDataProvider::getPropertySetInfo()
+{
+ return ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::getPropertySetInfo();
+}
+
+void SAL_CALL DatabaseDataProvider::setPropertyValue(const OUString & aPropertyName, const uno::Any & aValue)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::setPropertyValue(aPropertyName, aValue);
+}
+
+uno::Any SAL_CALL DatabaseDataProvider::getPropertyValue(const OUString & aPropertyName)
+{
+ return ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::getPropertyValue(aPropertyName);
+}
+
+void SAL_CALL DatabaseDataProvider::addPropertyChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XPropertyChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::addPropertyChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL DatabaseDataProvider::removePropertyChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XPropertyChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::removePropertyChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL DatabaseDataProvider::addVetoableChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XVetoableChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::addVetoableChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL DatabaseDataProvider::removeVetoableChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XVetoableChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::removeVetoableChangeListener(aPropertyName, xListener);
+}
+
+// chart2::data::XDatabaseDataProvider:
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getMasterFields()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_MasterFields;
+}
+
+void SAL_CALL DatabaseDataProvider::setMasterFields(const uno::Sequence< OUString > & the_value)
+{
+ impl_invalidateParameter_nothrow();
+ set("MasterFields",the_value,m_MasterFields);
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getDetailFields()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_DetailFields;
+}
+
+void SAL_CALL DatabaseDataProvider::setDetailFields(const uno::Sequence< OUString > & the_value)
+{
+ set("DetailFields",the_value,m_DetailFields);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getCommand()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Command;
+}
+
+void SAL_CALL DatabaseDataProvider::setCommand(const OUString & the_value)
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ impl_invalidateParameter_nothrow();
+ m_xAggregateSet->setPropertyValue( PROPERTY_COMMAND, uno::Any( the_value ) );
+ }
+ set(PROPERTY_COMMAND,the_value,m_Command);
+}
+
+::sal_Int32 SAL_CALL DatabaseDataProvider::getCommandType()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_CommandType;
+}
+
+void SAL_CALL DatabaseDataProvider::setCommandType(::sal_Int32 the_value)
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_COMMAND_TYPE, uno::Any( the_value ) );
+ }
+ set(PROPERTY_COMMAND_TYPE,the_value,m_CommandType);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getFilter()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_aFilterManager.getFilterComponent( dbtools::FilterManager::FilterComponent::PublicFilter );
+}
+
+void SAL_CALL DatabaseDataProvider::setFilter(const OUString & the_value)
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_aFilterManager.setFilterComponent( dbtools::FilterManager::FilterComponent::PublicFilter, the_value );
+ }
+ set(PROPERTY_FILTER,the_value,m_Filter);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::getApplyFilter()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_ApplyFilter;
+}
+
+void SAL_CALL DatabaseDataProvider::setApplyFilter( sal_Bool the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_APPLYFILTER, uno::Any( the_value ) );
+ }
+ set(PROPERTY_APPLYFILTER,static_cast<bool>(the_value),m_ApplyFilter);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getHavingClause()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_HavingClause;
+}
+
+void SAL_CALL DatabaseDataProvider::setHavingClause( const OUString& the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_HAVING_CLAUSE, uno::Any( the_value ) );
+ }
+ set(PROPERTY_HAVING_CLAUSE,the_value,m_HavingClause);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getGroupBy()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_GroupBy;
+}
+
+void SAL_CALL DatabaseDataProvider::setGroupBy( const OUString& the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_GROUP_BY, uno::Any( the_value ) );
+ }
+ set(PROPERTY_GROUP_BY,the_value,m_GroupBy);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getOrder()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Order;
+}
+
+void SAL_CALL DatabaseDataProvider::setOrder( const OUString& the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_ORDER, uno::Any( the_value ) );
+ }
+ set(PROPERTY_ORDER,the_value,m_Order);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::getEscapeProcessing()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_EscapeProcessing;
+}
+
+void SAL_CALL DatabaseDataProvider::setEscapeProcessing(sal_Bool the_value)
+{
+ set(PROPERTY_ESCAPE_PROCESSING,static_cast<bool>(the_value),m_EscapeProcessing);
+}
+
+::sal_Int32 SAL_CALL DatabaseDataProvider::getRowLimit()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_RowLimit;
+}
+
+void SAL_CALL DatabaseDataProvider::setRowLimit(::sal_Int32 the_value)
+{
+ set("RowLimit",the_value,m_RowLimit);
+}
+
+uno::Reference< sdbc::XConnection > SAL_CALL DatabaseDataProvider::getActiveConnection()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_xActiveConnection;
+}
+
+void SAL_CALL DatabaseDataProvider::setActiveConnection(const uno::Reference< sdbc::XConnection > & the_value)
+{
+ if ( !the_value.is() )
+ throw lang::IllegalArgumentException();
+ set(PROPERTY_ACTIVE_CONNECTION,the_value,m_xActiveConnection);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getDataSourceName()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_DataSourceName;
+}
+
+void SAL_CALL DatabaseDataProvider::setDataSourceName(const OUString& the_value)
+{
+ set(PROPERTY_DATASOURCENAME,the_value,m_DataSourceName);
+}
+
+namespace
+{
+ struct ColumnDescription
+ {
+ OUString sName;
+ sal_Int32 nResultSetPosition;
+ sal_Int32 nDataType;
+
+ ColumnDescription()
+ :nResultSetPosition( 0 )
+ ,nDataType( sdbc::DataType::VARCHAR )
+ {
+ }
+ explicit ColumnDescription( const OUString& i_rName )
+ :sName( i_rName )
+ ,nResultSetPosition( 0 )
+ ,nDataType( sdbc::DataType::VARCHAR )
+ {
+ }
+ };
+
+ struct CreateColumnDescription
+ {
+ ColumnDescription operator()( const OUString& i_rName )
+ {
+ return ColumnDescription( i_rName );
+ }
+ };
+
+ struct SelectColumnName
+ {
+ const OUString& operator()( const ColumnDescription& i_rColumn )
+ {
+ return i_rColumn.sName;
+ }
+ };
+}
+
+void DatabaseDataProvider::impl_fillInternalDataProvider_throw(bool _bHasCategories,const uno::Sequence< OUString >& i_aColumnNames)
+{
+ // clear the data before fill the new one
+ uno::Reference< sdbcx::XColumnsSupplier > xColSup(m_xRowSet,uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNameAccess > xColumns( xColSup->getColumns(), uno::UNO_SET_THROW );
+ const uno::Sequence< OUString > aRowSetColumnNames( xColumns->getElementNames() );
+
+ typedef std::vector< ColumnDescription > ColumnDescriptions;
+ ColumnDescriptions aColumns;
+ bool bFirstColumnIsCategory = _bHasCategories;
+ if ( i_aColumnNames.hasElements() )
+ {
+ // some normalizations ...
+ uno::Sequence< OUString > aImposedColumnNames( i_aColumnNames );
+
+ // strangely, there exist documents where the ColumnDescriptions end with a number of empty strings. /me
+ // thinks they're generated when you have a chart based on a result set with n columns, but remove some
+ // of those columns from the chart - it looks like a bug in the report XML export to me.
+ // So, get rid of the "trailing" empty columns
+ sal_Int32 nLastNonEmptyColName = aImposedColumnNames.getLength() - 1;
+ for ( ; nLastNonEmptyColName >= 0; --nLastNonEmptyColName )
+ {
+ if ( !aImposedColumnNames[ nLastNonEmptyColName ].isEmpty() )
+ break;
+ }
+ aImposedColumnNames.realloc( nLastNonEmptyColName + 1 );
+
+ // second, for X-Y-charts the ColumnDescriptions exported by chart miss the name of the first (non-category)
+ // column. This, this results in a ColumnDescriptions array like <"", "col2", "col3">, where you'd expect
+ // <"col1", "col2", "col3">.
+ // Fix this with some heuristics:
+ if ( aImposedColumnNames.hasElements() && ( !aImposedColumnNames[0].isEmpty() ) )
+ {
+ const sal_Int32 nAssumedRowSetColumnIndex = _bHasCategories ? 1 : 0;
+ if ( nAssumedRowSetColumnIndex < aRowSetColumnNames.getLength() )
+ aImposedColumnNames.getArray()[0] = aRowSetColumnNames[ nAssumedRowSetColumnIndex ];
+ }
+
+ const sal_Int32 nCount = aImposedColumnNames.getLength();
+ for ( sal_Int32 i = 0 ; i < nCount; ++i )
+ {
+ const OUString sColumnName( aImposedColumnNames[i] );
+ if ( !xColumns->hasByName( sColumnName ) )
+ continue;
+
+ if ( _bHasCategories && aColumns.empty() )
+ {
+ if ( aRowSetColumnNames.hasElements() )
+ aColumns.emplace_back( aRowSetColumnNames[0] );
+ else
+ aColumns.emplace_back( sColumnName );
+ bFirstColumnIsCategory = true;
+ }
+ aColumns.emplace_back( sColumnName );
+ }
+ }
+ if ( aColumns.empty() )
+ {
+ aColumns.resize( aRowSetColumnNames.getLength() );
+ std::transform(
+ aRowSetColumnNames.begin(),
+ aRowSetColumnNames.end(),
+ aColumns.begin(),
+ CreateColumnDescription()
+ );
+ }
+
+ // fill the data
+ uno::Reference< sdbc::XResultSet> xRes( m_xRowSet, uno::UNO_QUERY_THROW );
+ uno::Reference< sdbc::XRow> xRow( m_xRowSet,uno::UNO_QUERY_THROW );
+ uno::Reference< sdbc::XResultSetMetaDataSupplier > xSuppMeta( m_xRowSet,uno::UNO_QUERY_THROW );
+ uno::Reference< sdbc::XColumnLocate > xColumnLocate( m_xRowSet, uno::UNO_QUERY_THROW );
+
+ sal_Int32 columnIndex = 0;
+ for (auto & column : aColumns)
+ {
+ column.nResultSetPosition = xColumnLocate->findColumn( column.sName );
+
+ const uno::Reference< beans::XPropertySet > xColumn( xColumns->getByName( column.sName ), uno::UNO_QUERY_THROW );
+ const uno::Any aNumberFormat( xColumn->getPropertyValue( PROPERTY_NUMBERFORMAT ) );
+ OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_TYPE ) >>= column.nDataType );
+
+ const OUString sRangeName = OUString::number( columnIndex );
+ m_aNumberFormats.emplace( sRangeName, aNumberFormat );
+ ++columnIndex;
+ }
+
+ std::vector< OUString > aRowLabels;
+ std::vector< std::vector< double > > aDataValues;
+ sal_Int32 nRowCount = 0;
+ ::connectivity::ORowSetValue aValue;
+ while( xRes->next() && (!m_RowLimit || nRowCount < m_RowLimit) )
+ {
+ ++nRowCount;
+
+ aValue.fill( aColumns[0].nResultSetPosition, aColumns[0].nDataType, xRow );
+ aRowLabels.push_back( aValue.getString() );
+
+ std::vector< double > aRow;
+ bool bFirstLoop = true;
+ for (auto const& column : aColumns)
+ {
+ if (bFirstLoop)
+ {
+ bFirstLoop = false;
+ if (bFirstColumnIsCategory)
+ continue;
+ }
+
+ aValue.fill( column.nResultSetPosition, column.nDataType, xRow );
+ if ( aValue.isNull() )
+ aRow.push_back( std::numeric_limits<double>::quiet_NaN() );
+ else
+ aRow.push_back( aValue.getDouble() );
+ }
+
+ aDataValues.push_back( aRow );
+ }
+
+ // insert default data when no rows exist
+ if ( !nRowCount )
+ {
+ nRowCount = 3;
+ static const double fDefaultData[ ] =
+ { 9.10, 3.20, 4.54,
+ 2.40, 8.80, 9.65,
+ 3.10, 1.50, 3.70,
+ 4.30, 9.02, 6.20 };
+ for(sal_Int32 h = 0,k = 0; h < nRowCount; ++h,++k )
+ {
+ aRowLabels.push_back(OUString::number(h+1));
+ std::vector< double > aRow;
+ const sal_Int32 nSize = SAL_N_ELEMENTS(fDefaultData);
+ for (size_t j = 0; j < (aColumns.size()-1); ++j,++k)
+ {
+ if ( k >= nSize )
+ k = 0;
+ aRow.push_back(fDefaultData[k]);
+ }
+ aDataValues.push_back(aRow);
+ }
+ }
+
+ uno::Reference< chart::XChartDataArray> xData(m_xInternal,uno::UNO_QUERY);
+ xData->setRowDescriptions(comphelper::containerToSequence(aRowLabels));
+
+ const size_t nOffset = bFirstColumnIsCategory ? 1 : 0;
+ uno::Sequence< OUString > aColumnDescriptions( aColumns.size() - nOffset );
+ std::transform(
+ aColumns.begin() + nOffset,
+ aColumns.end(),
+ aColumnDescriptions.getArray(),
+ SelectColumnName()
+ );
+ xData->setColumnDescriptions( aColumnDescriptions );
+
+ uno::Sequence< uno::Sequence< double > > aData(aDataValues.size());
+ uno::Sequence< double >* pDataIter = aData.getArray();
+ uno::Sequence< double >* pDataEnd = pDataIter + aData.getLength();
+ for(sal_Int32 i= 0;pDataIter != pDataEnd; ++pDataIter,++i )
+ {
+ if ( !aDataValues[i].empty() )
+ *pDataIter = comphelper::containerToSequence(aDataValues[i]);
+ }
+ xData->setData(aData);
+}
+
+void DatabaseDataProvider::impl_fillRowSet_throw()
+{
+ m_xAggregateSet->setPropertyValue( PROPERTY_FILTER, uno::Any( getFilter() ) );
+ uno::Reference< sdbc::XParameters> xParam(m_xRowSet,uno::UNO_QUERY_THROW);
+ xParam->clearParameters( );
+}
+
+bool DatabaseDataProvider::impl_fillParameters_nothrow( ::osl::ResettableMutexGuard& _rClearForNotifies)
+{
+ // do we have to fill the parameters again?
+ if ( !m_aParameterManager.isUpToDate() )
+ m_aParameterManager.updateParameterInfo( m_aFilterManager );
+
+ if ( m_aParameterManager.isUpToDate() )
+ return m_aParameterManager.fillParameterValues( m_xHandler, _rClearForNotifies );
+
+ return true;
+}
+
+// css::sdbc::XParameters
+void SAL_CALL DatabaseDataProvider::setNull(sal_Int32 parameterIndex, sal_Int32 sqlType)
+{
+ m_aParameterManager.setNull(parameterIndex, sqlType);
+}
+
+void SAL_CALL DatabaseDataProvider::setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName)
+{
+ m_aParameterManager.setObjectNull(parameterIndex, sqlType, typeName);
+}
+
+void SAL_CALL DatabaseDataProvider::setBoolean(sal_Int32 parameterIndex, sal_Bool x)
+{
+ m_aParameterManager.setBoolean(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setByte(sal_Int32 parameterIndex, sal_Int8 x)
+{
+ m_aParameterManager.setByte(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setShort(sal_Int32 parameterIndex, sal_Int16 x)
+{
+ m_aParameterManager.setShort(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setInt(sal_Int32 parameterIndex, sal_Int32 x)
+{
+ m_aParameterManager.setInt(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setLong(sal_Int32 parameterIndex, sal_Int64 x)
+{
+ m_aParameterManager.setLong(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setFloat(sal_Int32 parameterIndex, float x)
+{
+ m_aParameterManager.setFloat(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setDouble(sal_Int32 parameterIndex, double x)
+{
+ m_aParameterManager.setDouble(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setString(sal_Int32 parameterIndex, const OUString& x)
+{
+ m_aParameterManager.setString(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setBytes(sal_Int32 parameterIndex, const uno::Sequence< sal_Int8 >& x)
+{
+ m_aParameterManager.setBytes(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setDate(sal_Int32 parameterIndex, const util::Date& x)
+{
+ m_aParameterManager.setDate(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setTime(sal_Int32 parameterIndex, const util::Time& x)
+{
+ m_aParameterManager.setTime(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setTimestamp(sal_Int32 parameterIndex, const util::DateTime& x)
+{
+ m_aParameterManager.setTimestamp(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setBinaryStream(sal_Int32 parameterIndex, const uno::Reference<io::XInputStream>& x, sal_Int32 length)
+{
+ m_aParameterManager.setBinaryStream(parameterIndex, x, length);
+}
+
+void SAL_CALL DatabaseDataProvider::setCharacterStream(sal_Int32 parameterIndex, const uno::Reference<io::XInputStream>& x, sal_Int32 length)
+{
+ m_aParameterManager.setCharacterStream(parameterIndex, x, length);
+}
+
+void SAL_CALL DatabaseDataProvider::setObjectWithInfo(sal_Int32 parameterIndex, const uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale)
+{
+ m_aParameterManager.setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
+}
+
+void SAL_CALL DatabaseDataProvider::setObject(sal_Int32 parameterIndex, const uno::Any& x)
+{
+ m_aParameterManager.setObject(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setRef(sal_Int32 parameterIndex, const uno::Reference<sdbc::XRef>& x)
+{
+ m_aParameterManager.setRef(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setBlob(sal_Int32 parameterIndex, const uno::Reference<sdbc::XBlob>& x)
+{
+ m_aParameterManager.setBlob(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setClob(sal_Int32 parameterIndex, const uno::Reference<sdbc::XClob>& x)
+{
+ m_aParameterManager.setClob(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setArray(sal_Int32 parameterIndex, const Reference<sdbc::XArray>& x)
+{
+ m_aParameterManager.setArray(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::clearParameters()
+{
+ m_aParameterManager.clearParameters();
+}
+
+// css::sdbc::XRowSet
+void SAL_CALL DatabaseDataProvider::execute()
+{
+ uno::Sequence< beans::PropertyValue > aEmpty;
+ createDataSource(aEmpty);
+}
+
+void SAL_CALL DatabaseDataProvider::addRowSetListener(const uno::Reference<sdbc::XRowSetListener>& _rListener)
+{
+ if (m_xRowSet.is())
+ m_xRowSet->addRowSetListener(_rListener);
+}
+
+void SAL_CALL DatabaseDataProvider::removeRowSetListener(const uno::Reference<sdbc::XRowSetListener>& _rListener)
+{
+ if (m_xRowSet.is())
+ m_xRowSet->removeRowSetListener(_rListener);
+}
+
+// css::sdbc::XResultSet
+sal_Bool SAL_CALL DatabaseDataProvider::next()
+{
+ return m_xRowSet->next();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isBeforeFirst()
+{
+ return m_xRowSet->isBeforeFirst();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isAfterLast()
+{
+ return m_xRowSet->isAfterLast();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isFirst()
+{
+ return m_xRowSet->isFirst();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isLast()
+{
+ return m_xRowSet->isLast();
+}
+
+void SAL_CALL DatabaseDataProvider::beforeFirst()
+{
+ m_xRowSet->beforeFirst();
+}
+
+void SAL_CALL DatabaseDataProvider::afterLast()
+{
+ m_xRowSet->afterLast();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::first()
+{
+ return m_xRowSet->first();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::last()
+{
+ return m_xRowSet->last();
+}
+
+sal_Int32 SAL_CALL DatabaseDataProvider::getRow()
+{
+ return m_xRowSet->getRow();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::absolute(sal_Int32 row)
+{
+ return m_xRowSet->absolute(row);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::relative(sal_Int32 rows)
+{
+ return m_xRowSet->relative(rows);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::previous()
+{
+ return m_xRowSet->previous();
+}
+
+void SAL_CALL DatabaseDataProvider::refreshRow()
+{
+ m_xRowSet->refreshRow();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::rowUpdated()
+{
+ return m_xRowSet->rowUpdated();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::rowInserted()
+{
+ return m_xRowSet->rowInserted();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::rowDeleted()
+{
+ return m_xRowSet->rowDeleted();
+}
+
+uno::Reference< uno::XInterface > SAL_CALL DatabaseDataProvider::getStatement()
+{
+ return m_xRowSet->getStatement();
+}
+
+uno::Reference< uno::XInterface > SAL_CALL DatabaseDataProvider::getParent( )
+{
+ return m_xParent;
+}
+
+void SAL_CALL DatabaseDataProvider::setParent( const uno::Reference< uno::XInterface >& _xParent )
+{
+ osl::MutexGuard g(m_aMutex);
+ m_xParent = _xParent;
+}
+
+void DatabaseDataProvider::impl_invalidateParameter_nothrow()
+{
+ osl::MutexGuard g(m_aMutex);
+ m_aParameterManager.clearAllParameterInformation();
+}
+
+} // namespace dbaccess
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbaccess_DatabaseDataProvider_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new dbaccess::DatabaseDataProvider(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/PropertyForward.cxx b/dbaccess/source/core/misc/PropertyForward.cxx
new file mode 100644
index 000000000..239bd422f
--- /dev/null
+++ b/dbaccess/source/core/misc/PropertyForward.cxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <PropertyForward.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+
+#include <comphelper/property.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+
+
+ OPropertyForward::OPropertyForward( const Reference< XPropertySet>& _xSource, const Reference< XNameAccess>& _xDestContainer,
+ const OUString& _sName, const std::vector< OUString>& _aPropertyList )
+ :m_xSource( _xSource, UNO_SET_THROW )
+ ,m_xDestContainer( _xDestContainer, UNO_SET_THROW )
+ ,m_sName( _sName )
+ ,m_bInInsert( false )
+ {
+
+ osl_atomic_increment(&m_refCount);
+ try
+ {
+ if ( _aPropertyList.empty() )
+ _xSource->addPropertyChangeListener( OUString(), this );
+ else
+ {
+ for (auto const& property : _aPropertyList)
+ _xSource->addPropertyChangeListener(property, this);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ OPropertyForward::~OPropertyForward()
+ {
+ }
+
+ void SAL_CALL OPropertyForward::propertyChange( const PropertyChangeEvent& evt )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_xDestContainer.is() )
+ throw DisposedException( OUString(), *this );
+
+ try
+ {
+ if ( !m_xDest.is() )
+ {
+ if ( m_xDestContainer->hasByName( m_sName ) )
+ {
+ m_xDest.set( m_xDestContainer->getByName( m_sName ), UNO_QUERY_THROW );
+ }
+ else
+ {
+ Reference< XDataDescriptorFactory > xFactory( m_xDestContainer, UNO_QUERY_THROW );
+ m_xDest.set( xFactory->createDataDescriptor(), UNO_SET_THROW );
+
+ ::comphelper::copyProperties( m_xSource, m_xDest );
+
+ m_bInInsert = true;
+ Reference< XAppend > xAppend( m_xDestContainer, UNO_QUERY_THROW );
+ xAppend->appendByDescriptor( m_xDest );
+ m_bInInsert = false;
+ }
+
+ m_xDestInfo.set( m_xDest->getPropertySetInfo(), UNO_SET_THROW );
+ }
+
+ if ( m_xDestInfo->hasPropertyByName( evt.PropertyName ) )
+ {
+ m_xDest->setPropertyValue( evt.PropertyName, evt.NewValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void SAL_CALL OPropertyForward::disposing( const css::lang::EventObject& /*_rSource*/ )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( !m_xSource.is() )
+ throw DisposedException( OUString(), *this );
+
+ m_xSource->removePropertyChangeListener( OUString(), this );
+ m_xSource = nullptr;
+ m_xDestContainer = nullptr;
+ m_xDestInfo = nullptr;
+ m_xDest = nullptr;
+ }
+
+ void OPropertyForward::setDefinition( const css::uno::Reference< css::beans::XPropertySet>& _xDest )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bInInsert )
+ return;
+
+ OSL_ENSURE( !m_xDest.is(), "OPropertyForward::setDefinition: definition object is already set!" );
+ try
+ {
+ m_xDest.set( _xDest, UNO_SET_THROW );
+ m_xDestInfo.set( m_xDest->getPropertySetInfo(), UNO_SET_THROW );
+ ::comphelper::copyProperties( m_xDest, m_xSource );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/apitools.cxx b/dbaccess/source/core/misc/apitools.cxx
new file mode 100644
index 000000000..efec92cf5
--- /dev/null
+++ b/dbaccess/source/core/misc/apitools.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <apitools.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace cppu;
+using namespace osl;
+
+// various helper functions
+// OSubComponent
+OSubComponent::OSubComponent(Mutex& _rMutex, const Reference< XInterface > & xParent)
+ :OComponentHelper(_rMutex)
+ ,m_xParent(xParent)
+{
+
+}
+
+OSubComponent::~OSubComponent()
+{
+ m_xParent = nullptr;
+
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OSubComponent::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XComponent>::get(),
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XWeak>::get());
+
+ return aTypes.getTypes();
+}
+
+// XInterface
+
+void OSubComponent::release() noexcept
+{
+ Reference< XInterface > x( xDelegator );
+ if (! x.is())
+ {
+ if (osl_atomic_decrement( &m_refCount ) == 0 )
+ {
+ if (! rBHelper.bDisposed)
+ {
+ // *before* again incrementing our ref count, ensure that our weak connection point
+ // will not create references to us anymore (via XAdapter::queryAdapted)
+ disposeWeakConnectionPoint();
+
+ Reference< XInterface > xHoldAlive( *this );
+ // remember the parent
+ Reference< XInterface > xParent;
+ {
+ MutexGuard aGuard( rBHelper.rMutex );
+ xParent = m_xParent;
+ m_xParent = nullptr;
+ }
+
+ SAL_WARN_IF( m_refCount != 1, "dbaccess.core", "OSubComponent::release: invalid ref count (before dispose)!" );
+
+ // First dispose
+ dispose();
+
+ // only the alive ref holds the object
+ SAL_WARN_IF( m_refCount != 1, "dbaccess.core", "OSubComponent::release: invalid ref count (after dispose)!" );
+
+ // release the parent in the ~
+ if (xParent.is())
+ {
+ MutexGuard aGuard( rBHelper.rMutex );
+ m_xParent = xParent;
+ }
+
+ // destroy the object if xHoldAlive decrement the refcount to 0
+ return;
+ }
+ }
+ // restore the reference count
+ osl_atomic_increment( &m_refCount );
+ }
+
+ // as we cover the job of the componenthelper we use the ...
+ OWeakAggObject::release();
+}
+
+Any OSubComponent::queryInterface( const Type & rType )
+{
+ Any aReturn;
+ if (!rType.equals(cppu::UnoType<XAggregation>::get()))
+ aReturn = OComponentHelper::queryInterface(rType);
+
+ return aReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/dsntypes.cxx b/dbaccess/source/core/misc/dsntypes.cxx
new file mode 100644
index 000000000..d8ceed402
--- /dev/null
+++ b/dbaccess/source/core/misc/dsntypes.cxx
@@ -0,0 +1,565 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_java.h>
+#include <dsntypes.hxx>
+#include <unotools/confignode.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <tools/wldcrd.hxx>
+#include <osl/file.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/string.hxx>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+
+ namespace
+ {
+ void lcl_extractHostAndPort(std::u16string_view _sUrl, OUString& _sHostname, sal_Int32& _nPortNumber)
+ {
+ if ( comphelper::string::getTokenCount(_sUrl, ':') >= 2 )
+ {
+ sal_Int32 nPos {0};
+ _sHostname = o3tl::getToken(_sUrl, 0, ':', nPos);
+ _nPortNumber = o3tl::toInt32(o3tl::getToken(_sUrl, 0, ':', nPos));
+ }
+ }
+ }
+// ODsnTypeCollection
+ODsnTypeCollection::ODsnTypeCollection(const css::uno::Reference< css::uno::XComponentContext >& _xContext)
+:m_aDriverConfig(_xContext)
+#if OSL_DEBUG_LEVEL > 0
+,m_nLivingIterators(0)
+#endif
+{
+ const uno::Sequence< OUString > aURLs = m_aDriverConfig.getURLs();
+ const OUString* pIter = aURLs.getConstArray();
+ const OUString* pEnd = pIter + aURLs.getLength();
+ for(;pIter != pEnd;++pIter )
+ {
+ m_aDsnPrefixes.push_back(*pIter);
+ m_aDsnTypesDisplayNames.push_back(m_aDriverConfig.getDriverTypeDisplayName(*pIter));
+ }
+
+ OSL_ENSURE(m_aDsnTypesDisplayNames.size() == m_aDsnPrefixes.size(),
+ "ODsnTypeCollection::ODsnTypeCollection : invalid resources !");
+}
+
+ODsnTypeCollection::~ODsnTypeCollection()
+{
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE(0 == m_nLivingIterators, "ODsnTypeCollection::~ODsnTypeCollection : there are still living iterator objects!");
+#endif
+}
+
+OUString ODsnTypeCollection::getTypeDisplayName(std::u16string_view _sURL) const
+{
+ return m_aDriverConfig.getDriverTypeDisplayName(_sURL);
+}
+
+OUString ODsnTypeCollection::cutPrefix(std::u16string_view _sURL) const
+{
+ OUString sRet;
+ OUString sOldPattern;
+
+ // on Windows or with gen rendering, the urls may begin with an ~
+ std::u16string_view sCleanURL = comphelper::string::stripStart(_sURL, '~');
+
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(sCleanURL) )
+ {
+ // This relies on the fact that all patterns are of the form
+ // foo*
+ // that is, the very concept of "prefix" applies.
+ OUString prefix(comphelper::string::stripEnd(dsnPrefix, '*'));
+ OSL_ENSURE(o3tl::make_unsigned(prefix.getLength()) <= sCleanURL.size(), "How can A match B when A shorter than B?");
+ sRet = sCleanURL.substr(prefix.getLength());
+ sOldPattern = dsnPrefix;
+ }
+ }
+
+ return sRet;
+}
+
+OUString ODsnTypeCollection::getPrefix(const OUString& _sURL) const
+{
+ OUString sRet;
+ OUString sOldPattern;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ // This relies on the fact that all patterns are of the form
+ // foo*
+ // that is, the very concept of "prefix" applies.
+ sRet = comphelper::string::stripEnd(dsnPrefix, '*');
+ OSL_ENSURE(sRet.getLength() <= _sURL.getLength(), "How can A match B when A shorter than B?");
+ sOldPattern = dsnPrefix;
+ }
+ }
+
+ return sRet;
+}
+
+bool ODsnTypeCollection::hasDriver( const char* _pAsciiPattern ) const
+{
+ OUString sPrefix( getPrefix( OUString::createFromAscii( _pAsciiPattern ) ) );
+ return !sPrefix.isEmpty();
+}
+
+bool ODsnTypeCollection::isConnectionUrlRequired(std::u16string_view _sURL) const
+{
+ OUString sRet;
+ OUString sOldPattern;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sRet = dsnPrefix;
+ sOldPattern = dsnPrefix;
+ }
+ }
+ return !sRet.isEmpty() && sRet[sRet.getLength()-1] == '*';
+}
+
+OUString ODsnTypeCollection::getMediaType(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("MediaType",OUString());
+}
+
+OUString ODsnTypeCollection::getDatasourcePrefixFromMediaType(std::u16string_view _sMediaType,std::u16string_view _sExtension)
+{
+ OUString sURL, sFallbackURL;
+ const uno::Sequence< OUString > aURLs = m_aDriverConfig.getURLs();
+ const OUString* pIter = aURLs.getConstArray();
+ const OUString* pEnd = pIter + aURLs.getLength();
+ for(;pIter != pEnd;++pIter )
+ {
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(*pIter);
+ if ( aFeatures.getOrDefault("MediaType",OUString()) == _sMediaType )
+ {
+ const OUString sFileExtension = aFeatures.getOrDefault("Extension",OUString());
+ if ( _sExtension == sFileExtension )
+ {
+ sURL = *pIter;
+ break;
+ }
+ if ( sFileExtension.isEmpty() && !_sExtension.empty() )
+ sFallbackURL = *pIter;
+ }
+ }
+
+ if ( sURL.isEmpty() && !sFallbackURL.isEmpty() )
+ sURL = sFallbackURL;
+
+ sURL = comphelper::string::stripEnd(sURL, '*');
+ return sURL;
+}
+
+bool ODsnTypeCollection::isShowPropertiesEnabled( const OUString& _sURL )
+{
+ return !( _sURL.startsWithIgnoreAsciiCase("sdbc:embedded:hsqldb")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:embedded:firebird")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:outlook")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:outlookexp")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:mozilla:")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:kab")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:evolution:local")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:evolution:groupwise")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:evolution:ldap")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:macab") );
+}
+
+void ODsnTypeCollection::extractHostNamePort(const OUString& _rDsn,OUString& _sDatabaseName,OUString& _rsHostname,sal_Int32& _nPortNumber) const
+{
+ OUString sUrl = cutPrefix(_rDsn);
+ if ( _rDsn.startsWithIgnoreAsciiCase("jdbc:oracle:thin:") )
+ {
+ lcl_extractHostAndPort(sUrl,_rsHostname,_nPortNumber);
+ const sal_Int32 nUrlTokens {comphelper::string::getTokenCount(sUrl, ':')};
+ if ( _rsHostname.isEmpty() && nUrlTokens == 2 )
+ {
+ _nPortNumber = -1;
+ _rsHostname = sUrl.getToken(0,':');
+ }
+ if ( !_rsHostname.isEmpty() )
+ _rsHostname = _rsHostname.copy(_rsHostname.lastIndexOf('@')+1);
+ _sDatabaseName = sUrl.copy(sUrl.lastIndexOf(':')+1);
+ }
+ else if ( _rDsn.startsWithIgnoreAsciiCase("sdbc:address:ldap:") )
+ {
+ lcl_extractHostAndPort(sUrl,_sDatabaseName,_nPortNumber);
+ }
+ else if ( _rDsn.startsWithIgnoreAsciiCase("sdbc:mysql:mysqlc:")
+ || _rDsn.startsWithIgnoreAsciiCase("sdbc:mysql:jdbc:") )
+ {
+ lcl_extractHostAndPort(sUrl,_rsHostname,_nPortNumber);
+
+ const sal_Int32 nUrlTokens {comphelper::string::getTokenCount(sUrl, '/')};
+ if ( _nPortNumber == -1 && _rsHostname.isEmpty() && nUrlTokens == 2 )
+ _rsHostname = sUrl.getToken(0,'/');
+ _sDatabaseName = sUrl.copy(sUrl.lastIndexOf('/')+1);
+ }
+ else if ( _rDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:Provider=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=")
+ || _rDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=") )
+ {
+ OUString sNewFileName;
+ if ( ::osl::FileBase::getFileURLFromSystemPath( sUrl, sNewFileName ) == ::osl::FileBase::E_None )
+ {
+ _sDatabaseName = sNewFileName;
+ }
+ }
+}
+
+OUString ODsnTypeCollection::getJavaDriverClass(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getProperties(_sURL);
+ return aFeatures.getOrDefault("JavaDriverClass",OUString());
+}
+
+bool ODsnTypeCollection::isFileSystemBased(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("FileSystemBased",false);
+}
+
+bool ODsnTypeCollection::supportsTableCreation(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsTableCreation",false);
+}
+
+bool ODsnTypeCollection::supportsColumnDescription(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsColumnDescription",false);
+}
+
+bool ODsnTypeCollection::supportsBrowsing(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsBrowsing",false);
+}
+
+bool ODsnTypeCollection::supportsDBCreation(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsDBCreation",false);
+}
+
+Sequence<PropertyValue> ODsnTypeCollection::getDefaultDBSettings( std::u16string_view _sURL ) const
+{
+ const ::comphelper::NamedValueCollection& aProperties = m_aDriverConfig.getProperties(_sURL);
+ return aProperties.getPropertyValues();
+}
+
+bool ODsnTypeCollection::isEmbeddedDatabase( std::u16string_view _sURL )
+{
+ return o3tl::starts_with( _sURL, u"sdbc:embedded:" );
+}
+
+OUString ODsnTypeCollection::getEmbeddedDatabase()
+{
+ if (!HAVE_FEATURE_JAVA || officecfg::Office::Common::Misc::ExperimentalMode::get())
+ return "sdbc:embedded:firebird";
+ else
+ return "sdbc:embedded:hsqldb";
+}
+
+
+DATASOURCE_TYPE ODsnTypeCollection::determineType(std::u16string_view _rDsn) const
+{
+ OUString sDsn(comphelper::string::stripEnd(_rDsn, '*'));
+ sal_Int32 nSeparator = sDsn.indexOf(u':');
+ if (-1 == nSeparator)
+ {
+ if (!sDsn.isEmpty())
+ {
+ // there should be at least one such separator
+ OSL_FAIL("ODsnTypeCollection::implDetermineType : missing the colon !");
+ }
+
+ return DST_UNKNOWN;
+ }
+
+ // find first :
+ if (sDsn.startsWithIgnoreAsciiCase("jdbc:oracle:thin:"))
+ return DST_ORACLE_JDBC;
+
+ if (sDsn.startsWithIgnoreAsciiCase("jdbc:"))
+ return DST_JDBC;
+
+ if (sDsn.equalsIgnoreAsciiCase("sdbc:embedded:hsqldb"))
+ return DST_EMBEDDED_HSQLDB;
+
+ if (sDsn.equalsIgnoreAsciiCase("sdbc:embedded:firebird"))
+ return DST_EMBEDDED_FIREBIRD;
+
+ // find second :
+ nSeparator = sDsn.indexOf(u':', nSeparator + 1);
+ if (-1 == nSeparator)
+ {
+ // at the moment only jdbc is allowed to have just one separator
+ OSL_FAIL("ODsnTypeCollection::implDetermineType : missing the second colon !");
+ return DST_UNKNOWN;
+ }
+
+ if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:"))
+ {
+ if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:"))
+ {
+ if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:Provider=Microsoft.ACE.OLEDB.12.0;"))
+ return DST_MSACCESS_2007;
+ else
+ return DST_MSACCESS;
+ }
+ return DST_ADO;
+ }
+
+ struct KnownPrefix
+ {
+ const OUString sPrefix;
+ const DATASOURCE_TYPE eType;
+ const bool bMatchComplete;
+
+ KnownPrefix( const OUString &_s, const DATASOURCE_TYPE _t, const bool _m )
+ :sPrefix( _s )
+ ,eType ( _t )
+ ,bMatchComplete( _m )
+ {
+ }
+
+ bool match( const OUString &url) const
+ {
+ if(bMatchComplete)
+ {
+ return url.equalsIgnoreAsciiCase(sPrefix);
+ }
+ else
+ {
+ return url.startsWithIgnoreAsciiCase(sPrefix);
+ }
+ }
+ };
+ const KnownPrefix aKnowPrefixes[] =
+ {
+ KnownPrefix( "sdbc:calc:", DST_CALC, false ),
+ KnownPrefix( "sdbc:writer:", DST_WRITER, false ),
+ KnownPrefix( "sdbc:flat:", DST_FLAT, false ),
+ KnownPrefix( "sdbc:odbc:", DST_ODBC, false ),
+ KnownPrefix( "sdbc:dbase:", DST_DBASE, false ),
+ KnownPrefix( "sdbc:firebird:", DST_FIREBIRD, false ),
+ KnownPrefix( "sdbc:mysql:odbc:", DST_MYSQL_ODBC, false ),
+ KnownPrefix( "sdbc:mysql:jdbc:", DST_MYSQL_JDBC, false ),
+ KnownPrefix( "sdbc:mysql:mysqlc:", DST_MYSQL_NATIVE, false ),
+ KnownPrefix( "sdbc:mysqlc:", DST_MYSQL_NATIVE_DIRECT,false ),
+ KnownPrefix( "sdbc:postgresql:", DST_POSTGRES ,false ),
+
+ KnownPrefix( "sdbc:address:mozilla:", DST_MOZILLA, true ),
+ KnownPrefix( "sdbc:address:thunderbird:", DST_THUNDERBIRD, true ),
+ KnownPrefix( "sdbc:address:ldap:", DST_LDAP, true ),
+ KnownPrefix( "sdbc:address:outlook", DST_OUTLOOK, true ),
+ KnownPrefix( "sdbc:address:outlookexp", DST_OUTLOOKEXP, true ),
+ KnownPrefix( "sdbc:address:evolution:ldap", DST_EVOLUTION_LDAP, true ),
+ KnownPrefix( "sdbc:address:evolution:groupwise",DST_EVOLUTION_GROUPWISE,true ),
+ KnownPrefix( "sdbc:address:evolution:local", DST_EVOLUTION, true ),
+ KnownPrefix( "sdbc:address:kab", DST_KAB, true ),
+ KnownPrefix( "sdbc:address:macab", DST_MACAB, true )
+ };
+
+ for (const auto & aKnowPrefixe : aKnowPrefixes)
+ {
+ if( aKnowPrefixe.match(sDsn) )
+ {
+ return aKnowPrefixe.eType;
+ }
+ }
+
+ return DST_UNKNOWN;
+}
+
+void ODsnTypeCollection::fillPageIds(std::u16string_view _sURL,std::vector<sal_Int16>& _rOutPathIds) const
+{
+ DATASOURCE_TYPE eType = determineType(_sURL);
+ switch(eType)
+ {
+ case DST_ADO:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_ADO);
+ break;
+ case DST_DBASE:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_DBASE);
+ break;
+ case DST_FLAT:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_TEXT);
+ break;
+ case DST_CALC:
+ case DST_WRITER:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET);
+ break;
+ case DST_ODBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_ODBC);
+ break;
+ case DST_JDBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_JDBC);
+ break;
+ case DST_MYSQL_ODBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_INTRO);
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_ODBC);
+ break;
+ case DST_MYSQL_JDBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_INTRO);
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_JDBC);
+ break;
+ case DST_MYSQL_NATIVE:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_INTRO);
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_NATIVE);
+ break;
+ case DST_ORACLE_JDBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_ORACLE);
+ break;
+ case DST_LDAP:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_LDAP);
+ break;
+ case DST_MSACCESS:
+ case DST_MSACCESS_2007:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MSACCESS);
+ break;
+ case DST_OUTLOOKEXP:
+ case DST_OUTLOOK:
+ case DST_MOZILLA:
+ case DST_THUNDERBIRD:
+ case DST_EVOLUTION:
+ case DST_EVOLUTION_GROUPWISE:
+ case DST_EVOLUTION_LDAP:
+ case DST_KAB:
+ case DST_MACAB:
+ case DST_EMBEDDED_HSQLDB:
+ case DST_EMBEDDED_FIREBIRD:
+ break;
+ default:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_USERDEFINED);
+ break;
+ }
+}
+
+OUString ODsnTypeCollection::getType(std::u16string_view _sURL) const
+{
+ OUString sOldPattern;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sOldPattern = dsnPrefix;
+ }
+ }
+ return sOldPattern;
+}
+
+sal_Int32 ODsnTypeCollection::getIndexOf(std::u16string_view _sURL) const
+{
+ sal_Int32 nRet = -1;
+ OUString sOldPattern;
+ sal_Int32 i = 0;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ nRet = i;
+ sOldPattern = dsnPrefix;
+ }
+ ++i;
+ }
+
+ return nRet;
+}
+
+sal_Int32 ODsnTypeCollection::size() const
+{
+ return m_aDsnPrefixes.size();
+}
+
+// ODsnTypeCollection::TypeIterator
+ODsnTypeCollection::TypeIterator::TypeIterator(const ODsnTypeCollection* _pContainer, sal_Int32 _nInitialPos)
+ :m_pContainer(_pContainer)
+ ,m_nPosition(_nInitialPos)
+{
+ OSL_ENSURE(m_pContainer, "ODsnTypeCollection::TypeIterator::TypeIterator : invalid container!");
+#if OSL_DEBUG_LEVEL > 0
+ ++const_cast<ODsnTypeCollection*>(m_pContainer)->m_nLivingIterators;
+#endif
+}
+
+ODsnTypeCollection::TypeIterator::TypeIterator(const TypeIterator& _rSource)
+ :m_pContainer(_rSource.m_pContainer)
+ ,m_nPosition(_rSource.m_nPosition)
+{
+#if OSL_DEBUG_LEVEL > 0
+ ++const_cast<ODsnTypeCollection*>(m_pContainer)->m_nLivingIterators;
+#endif
+}
+
+ODsnTypeCollection::TypeIterator::~TypeIterator()
+{
+#if OSL_DEBUG_LEVEL > 0
+ --const_cast<ODsnTypeCollection*>(m_pContainer)->m_nLivingIterators;
+#endif
+}
+
+OUString const & ODsnTypeCollection::TypeIterator::getDisplayName() const
+{
+ OSL_ENSURE(m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnTypesDisplayNames.size()), "ODsnTypeCollection::TypeIterator::getDisplayName : invalid position!");
+ return m_pContainer->m_aDsnTypesDisplayNames[m_nPosition];
+}
+
+OUString const & ODsnTypeCollection::TypeIterator::getURLPrefix() const
+{
+ OSL_ENSURE(m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnPrefixes.size()), "ODsnTypeCollection::TypeIterator::getDisplayName : invalid position!");
+ return m_pContainer->m_aDsnPrefixes[m_nPosition];
+}
+
+const ODsnTypeCollection::TypeIterator& ODsnTypeCollection::TypeIterator::operator++()
+{
+ OSL_ENSURE(m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnTypesDisplayNames.size()), "ODsnTypeCollection::TypeIterator::operator++ : invalid position!");
+ if (m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnTypesDisplayNames.size()))
+ ++m_nPosition;
+ return *this;
+}
+
+bool operator==(const ODsnTypeCollection::TypeIterator& lhs, const ODsnTypeCollection::TypeIterator& rhs)
+{
+ return (lhs.m_pContainer == rhs.m_pContainer) && (lhs.m_nPosition == rhs.m_nPosition);
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/migrwarndlg.cxx b/dbaccess/source/core/misc/migrwarndlg.cxx
new file mode 100644
index 000000000..d1712fba3
--- /dev/null
+++ b/dbaccess/source/core/misc/migrwarndlg.cxx
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <migrwarndlg.hxx>
+
+namespace dbaccess
+{
+MigrationWarnDialog::MigrationWarnDialog(weld::Window* pParent)
+ : MessageDialogController(pParent, "dbaccess/ui/migrwarndlg.ui", "MigrationWarnDialog")
+ , m_xLater(m_xBuilder->weld_button("no"))
+{
+ m_xLater->grab_focus();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/objectnameapproval.cxx b/dbaccess/source/core/misc/objectnameapproval.cxx
new file mode 100644
index 000000000..3ec15caaa
--- /dev/null
+++ b/dbaccess/source/core/misc/objectnameapproval.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <objectnameapproval.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdb/tools/XConnectionTools.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+
+#include <cppuhelper/weakref.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::uno::WeakReference;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::sdb::tools::XConnectionTools;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::sdb::tools::XObjectNames;
+ using ::com::sun::star::uno::XInterface;
+
+ namespace CommandType = com::sun::star::sdb::CommandType;
+
+ // ObjectNameApproval_Impl
+ struct ObjectNameApproval_Impl
+ {
+ WeakReference< XConnection > aConnection;
+ sal_Int32 nCommandType;
+ };
+
+ // ObjectNameApproval
+ ObjectNameApproval::ObjectNameApproval( const Reference< XConnection >& _rxConnection, ObjectType _eType )
+ :m_pImpl( new ObjectNameApproval_Impl )
+ {
+ m_pImpl->aConnection = _rxConnection;
+ m_pImpl->nCommandType = _eType == TypeQuery ? CommandType::QUERY : CommandType::TABLE;
+ }
+
+ ObjectNameApproval::~ObjectNameApproval()
+ {
+ }
+
+ void ObjectNameApproval::approveElement( const OUString& _rName )
+ {
+ Reference< XConnection > xConnection( m_pImpl->aConnection );
+ if ( !xConnection.is() )
+ throw DisposedException();
+
+ Reference< XConnectionTools > xConnectionTools( xConnection, UNO_QUERY_THROW );
+ Reference< XObjectNames > xObjectNames( xConnectionTools->getObjectNames(), css::uno::UNO_SET_THROW );
+ xObjectNames->checkNameForCreate( m_pImpl->nCommandType, _rName );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/sdbcoretools.cxx b/dbaccess/source/core/misc/sdbcoretools.cxx
new file mode 100644
index 000000000..1789aea84
--- /dev/null
+++ b/dbaccess/source/core/misc/sdbcoretools.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/task/InteractionRequestStringResolver.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <comphelper/interaction.hxx>
+#include <rtl/ref.hxx>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::io;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::embed;
+ using namespace ::com::sun::star::container;
+
+ void notifyDataSourceModified(const css::uno::Reference< css::uno::XInterface >& _rxObject)
+ {
+ Reference< XInterface > xDs = getDataSource( _rxObject );
+ Reference<XDocumentDataSource> xDocumentDataSource(xDs,UNO_QUERY);
+ if ( xDocumentDataSource.is() )
+ xDs = xDocumentDataSource->getDatabaseDocument();
+ Reference< XModifiable > xModi( xDs, UNO_QUERY );
+ if ( xModi.is() )
+ xModi->setModified(true);
+ }
+
+ Reference< XInterface > getDataSource( const Reference< XInterface >& _rxDependentObject )
+ {
+ Reference< XInterface > xParent = _rxDependentObject;
+ Reference< XInterface > xReturn;
+ while( xParent.is() )
+ {
+ xReturn = xParent;
+ Reference<XChild> xChild(xParent,UNO_QUERY);
+ xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY);
+ }
+ return xReturn;
+ }
+
+ OUString extractExceptionMessage( const Reference<XComponentContext> & _rContext, const Any& _rError )
+ {
+ OUString sDisplayMessage;
+
+ try
+ {
+ Reference< XInteractionRequestStringResolver > xStringResolver = InteractionRequestStringResolver::create(_rContext);
+
+ ::rtl::Reference pRequest( new ::comphelper::OInteractionRequest( _rError ) );
+ ::rtl::Reference pApprove( new ::comphelper::OInteractionApprove );
+ pRequest->addContinuation( pApprove );
+ Optional< OUString > aMessage = xStringResolver->getStringFromInformationalRequest( pRequest );
+ if ( aMessage.IsPresent )
+ sDisplayMessage = aMessage.Value;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( sDisplayMessage.isEmpty() )
+ {
+ Exception aExcept;
+ _rError >>= aExcept;
+
+ sDisplayMessage = _rError.getValueTypeName() +
+ ":\n" +
+ aExcept.Message;
+ }
+
+ return sDisplayMessage;
+ }
+
+ namespace tools::stor {
+
+ bool storageIsWritable_nothrow( const Reference< XStorage >& _rxStorage )
+ {
+ if ( !_rxStorage.is() )
+ return false;
+
+ sal_Int32 nMode = ElementModes::READ;
+ try
+ {
+ Reference< XPropertySet > xStorageProps( _rxStorage, UNO_QUERY_THROW );
+ xStorageProps->getPropertyValue( "OpenMode" ) >>= nMode;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return ( nMode & ElementModes::WRITE ) != 0;
+ }
+
+ bool commitStorageIfWriteable( const Reference< XStorage >& _rxStorage )
+ {
+ bool bSuccess = false;
+ Reference< XTransactedObject > xTrans( _rxStorage, UNO_QUERY );
+ if ( xTrans.is() )
+ {
+ if ( storageIsWritable_nothrow( _rxStorage ) )
+ xTrans->commit();
+ bSuccess = true;
+ }
+ return bSuccess;
+ }
+
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/veto.cxx b/dbaccess/source/core/misc/veto.cxx
new file mode 100644
index 000000000..d2596d4e1
--- /dev/null
+++ b/dbaccess/source/core/misc/veto.cxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <veto.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Any;
+
+ // Veto
+ Veto::Veto( const Any& _rDetails )
+ :m_aDetails( _rDetails )
+ {
+ }
+
+ Veto::~Veto()
+ {
+ }
+
+ OUString SAL_CALL Veto::getReason()
+ {
+ return OUString();
+ }
+
+ Any SAL_CALL Veto::getDetails()
+ {
+ return m_aDetails;
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/dbdocrecovery.cxx b/dbaccess/source/core/recovery/dbdocrecovery.cxx
new file mode 100644
index 000000000..db7bb53bd
--- /dev/null
+++ b/dbaccess/source/core/recovery/dbdocrecovery.cxx
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <recovery/dbdocrecovery.hxx>
+#include <sdbcoretools.hxx>
+#include "storagetextstream.hxx"
+#include "subcomponentrecovery.hxx"
+#include "subcomponents.hxx"
+
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/TextInputStream.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using css::uno::Reference;
+ using css::uno::UNO_QUERY;
+ using css::uno::UNO_QUERY_THROW;
+ using css::uno::UNO_SET_THROW;
+ using css::uno::Exception;
+ using css::uno::Sequence;
+ using css::uno::XComponentContext;
+ using css::embed::XStorage;
+ using css::frame::XController;
+ using css::sdb::application::XDatabaseDocumentUI;
+ using css::lang::XComponent;
+ using css::io::XStream;
+ using css::io::TextInputStream;
+ using css::io::XTextInputStream2;
+ using css::util::XModifiable;
+
+ namespace ElementModes = css::embed::ElementModes;
+
+ // helpers
+ namespace
+ {
+ void lcl_getPersistentRepresentation( const MapStringToCompDesc::value_type& i_rComponentDesc, OUStringBuffer& o_rBuffer )
+ {
+ o_rBuffer.append( i_rComponentDesc.first );
+ o_rBuffer.append( '=' );
+ o_rBuffer.append( i_rComponentDesc.second.sName );
+ o_rBuffer.append( ',' );
+ o_rBuffer.append( sal_Unicode( i_rComponentDesc.second.bForEditing ? '1' : '0' ) );
+ }
+
+ bool lcl_extractCompDesc( const OUString& i_rIniLine, OUString& o_rStorName, SubComponentDescriptor& o_rCompDesc )
+ {
+ const sal_Int32 nEqualSignPos = i_rIniLine.indexOf( '=' );
+ if ( nEqualSignPos < 1 )
+ {
+ OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of '='" );
+ return false;
+ }
+ o_rStorName = i_rIniLine.copy( 0, nEqualSignPos );
+
+ const sal_Int32 nCommaPos = i_rIniLine.lastIndexOf( ',' );
+ if ( nCommaPos != i_rIniLine.getLength() - 2 )
+ {
+ OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of ','" );
+ return false;
+ }
+ o_rCompDesc.sName = i_rIniLine.copy( nEqualSignPos + 1, nCommaPos - nEqualSignPos - 1 );
+ o_rCompDesc.bForEditing = ( i_rIniLine[ nCommaPos + 1 ] == '1' );
+ return true;
+ }
+
+ constexpr OUStringLiteral sRecoveryDataSubStorageName = u"recovery";
+
+ constexpr OUStringLiteral sObjectMapStreamName = u"storage-component-map.ini";
+
+ void lcl_writeObjectMap_throw( const Reference<XComponentContext> & i_rContext, const Reference< XStorage >& i_rStorage,
+ const MapStringToCompDesc& i_mapStorageToCompDesc )
+ {
+ if ( i_mapStorageToCompDesc.empty() )
+ // nothing to do
+ return;
+
+ StorageTextOutputStream aTextOutput( i_rContext, i_rStorage, sObjectMapStreamName );
+
+ aTextOutput.writeLine( "[storages]" );
+
+ for (auto const& elem : i_mapStorageToCompDesc)
+ {
+ OUStringBuffer aLine;
+ lcl_getPersistentRepresentation(elem, aLine);
+
+ aTextOutput.writeLine( aLine.makeStringAndClear() );
+ }
+
+ aTextOutput.writeLine();
+ }
+
+ bool lcl_isSectionStart( const OUString& i_rIniLine, OUString& o_rSectionName )
+ {
+ const sal_Int32 nLen = i_rIniLine.getLength();
+ if ( i_rIniLine.startsWith("[") && i_rIniLine.endsWith("]") )
+ {
+ o_rSectionName = i_rIniLine.copy( 1, nLen -2 );
+ return true;
+ }
+ return false;
+ }
+
+ void lcl_stripTrailingLineFeed( OUString& io_rLine )
+ {
+ const sal_Int32 nLen = io_rLine.getLength();
+ if ( io_rLine.endsWith("\n") )
+ io_rLine = io_rLine.copy( 0, nLen - 1 );
+ }
+
+ void lcl_readObjectMap_throw( const Reference<XComponentContext> & i_rxContext, const Reference< XStorage >& i_rStorage,
+ MapStringToCompDesc& o_mapStorageToObjectName )
+ {
+ ENSURE_OR_THROW( i_rStorage.is(), "invalid storage" );
+ if ( !i_rStorage->hasByName( sObjectMapStreamName ) )
+ { // nothing to do, though suspicious
+ OSL_FAIL( "lcl_readObjectMap_throw: if there's no map file, then there's expected to be no storage, too!" );
+ return;
+ }
+
+ Reference< XStream > xIniStream( i_rStorage->openStreamElement(
+ sObjectMapStreamName, ElementModes::READ ), UNO_SET_THROW );
+
+ Reference< XTextInputStream2 > xTextInput = TextInputStream::create( i_rxContext );
+ xTextInput->setEncoding( "UTF-8" );
+ xTextInput->setInputStream( xIniStream->getInputStream() );
+
+ OUString sCurrentSection;
+ bool bCurrentSectionIsKnownToBeUnsupported = true;
+ while ( !xTextInput->isEOF() )
+ {
+ OUString sLine = xTextInput->readLine();
+ lcl_stripTrailingLineFeed( sLine );
+
+ if ( sLine.isEmpty() )
+ continue;
+
+ if ( lcl_isSectionStart( sLine, sCurrentSection ) )
+ {
+ bCurrentSectionIsKnownToBeUnsupported = false;
+ continue;
+ }
+
+ if ( bCurrentSectionIsKnownToBeUnsupported )
+ continue;
+
+ // the only section we support so far is "storages"
+ if ( sCurrentSection != "storages" )
+ {
+ bCurrentSectionIsKnownToBeUnsupported = true;
+ continue;
+ }
+
+ OUString sStorageName;
+ SubComponentDescriptor aCompDesc;
+ if ( !lcl_extractCompDesc( sLine, sStorageName, aCompDesc ) )
+ continue;
+ o_mapStorageToObjectName[ sStorageName ] = aCompDesc;
+ }
+ }
+
+ void lcl_markModified( const Reference< XComponent >& i_rSubComponent )
+ {
+ const Reference< XModifiable > xModify( i_rSubComponent, UNO_QUERY );
+ if ( !xModify.is() )
+ {
+ OSL_FAIL( "lcl_markModified: unhandled case!" );
+ return;
+ }
+
+ xModify->setModified( true );
+ }
+ }
+
+ // DatabaseDocumentRecovery_Data
+ struct DatabaseDocumentRecovery_Data
+ {
+ const Reference<XComponentContext> aContext;
+
+ explicit DatabaseDocumentRecovery_Data( const Reference<XComponentContext> & i_rContext )
+ :aContext( i_rContext )
+ {
+ }
+ };
+
+ // DatabaseDocumentRecovery
+ DatabaseDocumentRecovery::DatabaseDocumentRecovery( const Reference<XComponentContext> & i_rContext )
+ :m_pData( new DatabaseDocumentRecovery_Data( i_rContext ) )
+ {
+ }
+
+ DatabaseDocumentRecovery::~DatabaseDocumentRecovery()
+ {
+ }
+
+ void DatabaseDocumentRecovery::saveModifiedSubComponents( const Reference< XStorage >& i_rTargetStorage,
+ const std::vector< Reference< XController > >& i_rControllers )
+ {
+ ENSURE_OR_THROW( i_rTargetStorage.is(), "invalid document storage" );
+
+ // create a sub storage for recovery data
+ if ( i_rTargetStorage->hasByName( sRecoveryDataSubStorageName ) )
+ i_rTargetStorage->removeElement( sRecoveryDataSubStorageName );
+ Reference< XStorage > xRecoveryStorage = i_rTargetStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READWRITE );
+
+ // store recovery data for open sub components of the given controller(s)
+ if ( !i_rControllers.empty() )
+ {
+ ENSURE_OR_THROW( i_rControllers.size() == 1, "can't handle more than one controller" );
+ // At the moment, there can be only one view to a database document. If we ever allow for more than this,
+ // then we need a concept for sub documents opened from different controllers (i.e. two document views,
+ // and the user opens the very same form in both views). And depending on this, we need a concept for
+ // how those are saved to the recovery file.
+
+ MapCompTypeToCompDescs aMapCompDescs;
+
+ for (auto const& controller : i_rControllers)
+ {
+ Reference< XDatabaseDocumentUI > xDatabaseUI(controller, UNO_QUERY_THROW);
+ const Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() );
+
+ for ( auto const & component : aComponents )
+ {
+ SubComponentRecovery aComponentRecovery( m_pData->aContext, xDatabaseUI, component );
+ aComponentRecovery.saveToRecoveryStorage( xRecoveryStorage, aMapCompDescs );
+ }
+ }
+
+ for (auto const& elem : aMapCompDescs)
+ {
+ Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
+ SubComponentRecovery::getComponentsStorageName( elem.first ), ElementModes::WRITE | ElementModes::NOCREATE ) );
+ lcl_writeObjectMap_throw( m_pData->aContext, xComponentsStor, elem.second );
+ tools::stor::commitStorageIfWriteable( xComponentsStor );
+ }
+ }
+
+ // commit the recovery storage
+ tools::stor::commitStorageIfWriteable( xRecoveryStorage );
+ }
+
+ void DatabaseDocumentRecovery::recoverSubDocuments( const Reference< XStorage >& i_rDocumentStorage,
+ const Reference< XController >& i_rTargetController )
+ {
+ ENSURE_OR_THROW( i_rDocumentStorage.is(), "illegal document storage" );
+ Reference< XDatabaseDocumentUI > xDocumentUI( i_rTargetController, UNO_QUERY_THROW );
+
+ if ( !i_rDocumentStorage->hasByName( sRecoveryDataSubStorageName ) )
+ // that's allowed
+ return;
+
+ // the "recovery" sub storage
+ Reference< XStorage > xRecoveryStorage = i_rDocumentStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READ );
+
+ // read the map from sub storages to object names
+ MapCompTypeToCompDescs aMapCompDescs;
+ const SubComponentType aKnownTypes[] = { TABLE, QUERY, FORM, REPORT, RELATION_DESIGN };
+ for (SubComponentType aKnownType : aKnownTypes)
+ {
+ if ( !xRecoveryStorage->hasByName( SubComponentRecovery::getComponentsStorageName( aKnownType ) ) )
+ continue;
+
+ Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
+ SubComponentRecovery::getComponentsStorageName( aKnownType ), ElementModes::READ ) );
+ lcl_readObjectMap_throw( m_pData->aContext, xComponentsStor, aMapCompDescs[ aKnownType ] );
+ xComponentsStor->dispose();
+ }
+
+ // recover all sub components as indicated by the map
+ for (auto const& elemMapCompDescs : aMapCompDescs)
+ {
+ const SubComponentType eComponentType = elemMapCompDescs.first;
+
+ // the storage for all components of the current type
+ Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
+ SubComponentRecovery::getComponentsStorageName( eComponentType ), ElementModes::READ ), UNO_SET_THROW );
+
+ // loop through all components of this type
+ for (auto const& elem : elemMapCompDescs.second)
+ {
+ const OUString sComponentName(elem.second.sName);
+ if ( !xComponentsStor->hasByName(elem.first) )
+ {
+ SAL_WARN( "dbaccess",
+ "DatabaseDocumentRecovery::recoverSubDocuments: inconsistent recovery storage: storage '" <<
+ elem.first <<
+ "' not found in '" <<
+ SubComponentRecovery::getComponentsStorageName( eComponentType ) <<
+ "', but required per map file!" );
+ continue;
+ }
+
+ // the controller needs to have a connection to be able to open sub components
+ if ( !xDocumentUI->isConnected() )
+ xDocumentUI->connect();
+
+ // recover the single component
+ Reference< XStorage > xCompStor( xComponentsStor->openStorageElement( elem.first, ElementModes::READ ) );
+ SubComponentRecovery aComponentRecovery( m_pData->aContext, xDocumentUI, eComponentType );
+ Reference< XComponent > xSubComponent( aComponentRecovery.recoverFromStorage( xCompStor, sComponentName, elem.second.bForEditing ) );
+
+ // at the moment, we only store, during session save, sub components which are modified. So, set this
+ // recovered sub component to "modified", too.
+ lcl_markModified( xSubComponent );
+ }
+
+ xComponentsStor->dispose();
+ }
+
+ xRecoveryStorage->dispose();
+
+ // now that we successfully recovered, removed the "recovery" sub storage
+ try
+ {
+ i_rDocumentStorage->removeElement( sRecoveryDataSubStorageName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/settingsimport.cxx b/dbaccess/source/core/recovery/settingsimport.cxx
new file mode 100644
index 000000000..821dea045
--- /dev/null
+++ b/dbaccess/source/core/recovery/settingsimport.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "settingsimport.hxx"
+
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <sax/tools/converter.hxx>
+#include <xmloff/xmltoken.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::xml::sax::XAttributeList;
+
+ // SettingsImport
+ SettingsImport::SettingsImport()
+ {
+ }
+
+ SettingsImport::~SettingsImport()
+ {
+ }
+
+ void SettingsImport::startElement( const Reference< XAttributeList >& i_rAttributes )
+ {
+ // find the name of the setting
+ if ( i_rAttributes.is() )
+ {
+ m_sItemName = i_rAttributes->getValueByName( "config:name" );
+ m_sItemType = i_rAttributes->getValueByName( "config:type" );
+ }
+ }
+
+ void SettingsImport::endElement()
+ {
+ }
+
+ void SettingsImport::characters( std::u16string_view i_rCharacters )
+ {
+ m_aCharacters.append( i_rCharacters );
+ }
+
+ void SettingsImport::split( const OUString& i_rElementName, OUString& o_rNamespace, OUString& o_rLocalName )
+ {
+ o_rNamespace.clear();
+ o_rLocalName = i_rElementName;
+ const sal_Int32 nSeparatorPos = i_rElementName.indexOf( ':' );
+ if ( nSeparatorPos > -1 )
+ {
+ o_rNamespace = i_rElementName.copy( 0, nSeparatorPos );
+ o_rLocalName = i_rElementName.copy( nSeparatorPos + 1 );
+ }
+
+ OSL_ENSURE( o_rNamespace == "config", "SettingsImport::split: unexpected namespace!" );
+ // our recovery file is kind of hand-made, so there shouldn't be anything else than "config".
+ // If there is, then just ignore it ...
+ }
+
+ // IgnoringSettingsImport
+ ::rtl::Reference< SettingsImport > IgnoringSettingsImport::nextState( const OUString& )
+ {
+ return this;
+ }
+
+ // OfficeSettingsImport
+ OfficeSettingsImport::OfficeSettingsImport( ::comphelper::NamedValueCollection& o_rSettings )
+ :m_rSettings( o_rSettings )
+ {
+ }
+
+ OfficeSettingsImport::~OfficeSettingsImport()
+ {
+ }
+
+ ::rtl::Reference< SettingsImport > OfficeSettingsImport::nextState( const OUString& i_rElementName )
+ {
+ // separate the namespace part from the element name
+ OUString sNamespace;
+ OUString sLocalName;
+ split( i_rElementName, sNamespace, sLocalName );
+
+ if ( sLocalName == "config-item-set" )
+ return new ConfigItemSetImport( m_rSettings );
+
+ SAL_WARN( "dbaccess", "unknown (or unsupported at this place) element name '"
+ << i_rElementName
+ << "', ignoring");
+ return new IgnoringSettingsImport;
+ }
+
+ // ConfigItemImport
+ ConfigItemImport::ConfigItemImport( ::comphelper::NamedValueCollection& o_rSettings )
+ :m_rSettings( o_rSettings )
+ {
+ }
+
+ ConfigItemImport::~ConfigItemImport()
+ {
+ }
+
+ ::rtl::Reference< SettingsImport > ConfigItemImport::nextState( const OUString& )
+ {
+ OSL_FAIL( "ConfigItemImport::nextState: unexpected: this class is responsible for child-less items only!" );
+ return new IgnoringSettingsImport;
+ }
+
+ void ConfigItemImport::endElement()
+ {
+ SettingsImport::endElement();
+
+ const OUString sItemName( getItemName() );
+ ENSURE_OR_RETURN_VOID( !sItemName.isEmpty(), "no item name -> no item value" );
+ Any aValue;
+ getItemValue( aValue );
+ m_rSettings.put( sItemName, aValue );
+ }
+
+ void ConfigItemImport::getItemValue( css::uno::Any& o_rValue ) const
+ {
+ o_rValue.clear();
+
+ // the characters building up th evalue
+ std::u16string_view sValue = getAccumulatedCharacters();
+
+ const OUString& rItemType( getItemType() );
+ ENSURE_OR_RETURN_VOID( !rItemType.isEmpty(), "no item type -> no item value" );
+
+ if ( ::xmloff::token::IsXMLToken( rItemType, ::xmloff::token::XML_INT ) )
+ {
+ sal_Int32 nValue(0);
+ if (::sax::Converter::convertNumber( nValue, sValue ))
+ {
+ o_rValue <<= nValue;
+ }
+ else
+ {
+ OSL_FAIL( "ConfigItemImport::getItemValue: could not convert an int value!" );
+ }
+ }
+ else if ( ::xmloff::token::IsXMLToken( rItemType, ::xmloff::token::XML_BOOLEAN ) )
+ {
+ bool bValue(false);
+ if (::sax::Converter::convertBool( bValue, sValue ))
+ {
+ o_rValue <<= bValue;
+ }
+ else
+ {
+ OSL_FAIL( "ConfigItemImport::getItemValue: could not convert a boolean value!" );
+ }
+ }
+ else if ( ::xmloff::token::IsXMLToken( rItemType, ::xmloff::token::XML_STRING ) )
+ {
+ o_rValue <<= OUString(sValue);
+ }
+ else
+ {
+ SAL_WARN( "dbaccess", "ConfigItemImport::getItemValue: unsupported item type '"
+ << rItemType << "', ignoring");
+ }
+ }
+
+ // ConfigItemSetImport
+ ConfigItemSetImport::ConfigItemSetImport( ::comphelper::NamedValueCollection& o_rSettings )
+ :ConfigItemImport( o_rSettings )
+ {
+ }
+
+ ConfigItemSetImport::~ConfigItemSetImport()
+ {
+ }
+
+ ::rtl::Reference< SettingsImport > ConfigItemSetImport::nextState( const OUString& i_rElementName )
+ {
+ // separate the namespace part from the element name
+ OUString sNamespace;
+ OUString sLocalName;
+ split( i_rElementName, sNamespace, sLocalName );
+
+ if ( sLocalName == "config-item-set" )
+ return new ConfigItemSetImport( m_aChildSettings );
+ if ( sLocalName == "config-item" )
+ return new ConfigItemImport( m_aChildSettings );
+
+ SAL_WARN( "dbaccess", "unknown element name '"
+ << i_rElementName << "', ignoring");
+ return new IgnoringSettingsImport;
+ }
+
+ void ConfigItemSetImport::getItemValue( Any& o_rValue ) const
+ {
+ o_rValue <<= m_aChildSettings.getPropertyValues();
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/settingsimport.hxx b/dbaccess/source/core/recovery/settingsimport.hxx
new file mode 100644
index 000000000..bc29bd727
--- /dev/null
+++ b/dbaccess/source/core/recovery/settingsimport.hxx
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/sax/XAttributeList.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+namespace dbaccess
+{
+
+ // SettingsImport
+ /** a simplified version of xmloff/DocumentSettingsContext
+
+ It would be nice if the DocumentSettingsContext would not be that tightly interwoven with the SvXMLImport
+ class, so we could re-use it here ...
+ */
+ class SettingsImport : public salhelper::SimpleReferenceObject
+ {
+ public:
+ SettingsImport();
+
+ // own overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) = 0;
+ void startElement(
+ const css::uno::Reference< css::xml::sax::XAttributeList >& i_rAttributes
+ );
+ virtual void endElement();
+ void characters( std::u16string_view i_rCharacters );
+
+ protected:
+ virtual ~SettingsImport() override;
+
+ protected:
+ static void split( const OUString& i_rElementName, OUString& o_rNamespace, OUString& o_rLocalName );
+
+ protected:
+ const OUString& getItemName() const { return m_sItemName; }
+ const OUString& getItemType() const { return m_sItemType; }
+ const OUStringBuffer& getAccumulatedCharacters() const { return m_aCharacters; }
+
+ private:
+ // value of the config:name attribute, if any
+ OUString m_sItemName;
+ // value of the config:type attribute, if any
+ OUString m_sItemType;
+ // accumulated characters, if any
+ OUStringBuffer m_aCharacters;
+ };
+
+ // IgnoringSettingsImport
+ class IgnoringSettingsImport : public SettingsImport
+ {
+ public:
+ IgnoringSettingsImport()
+ {
+ }
+
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+
+ private:
+ virtual ~IgnoringSettingsImport() override
+ {
+ }
+ };
+
+ // OfficeSettingsImport
+ class OfficeSettingsImport : public SettingsImport
+ {
+ public:
+ explicit OfficeSettingsImport( ::comphelper::NamedValueCollection& o_rSettings );
+
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+
+ protected:
+ virtual ~OfficeSettingsImport() override;
+
+ private:
+ // the settings collection to which |this| will contribute a single setting
+ ::comphelper::NamedValueCollection& m_rSettings;
+ };
+
+ // ConfigItemSetImport
+ class ConfigItemImport : public SettingsImport
+ {
+ public:
+ explicit ConfigItemImport( ::comphelper::NamedValueCollection& o_rSettings );
+
+ protected:
+ virtual ~ConfigItemImport() override;
+
+ public:
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+ virtual void endElement() override;
+
+ protected:
+ // own overridables
+ /// retrieves the value represented by the element
+ virtual void getItemValue( css::uno::Any& o_rValue ) const;
+
+ private:
+ // the settings collection to which |this| will contribute a single setting
+ ::comphelper::NamedValueCollection& m_rSettings;
+ };
+
+ // ConfigItemSetImport
+ class ConfigItemSetImport : public ConfigItemImport
+ {
+ public:
+ explicit ConfigItemSetImport( ::comphelper::NamedValueCollection& o_rSettings );
+
+ protected:
+ virtual ~ConfigItemSetImport() override;
+
+ public:
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+
+ protected:
+ // ConfigItemImport overridables
+ virtual void getItemValue( css::uno::Any& o_rValue ) const override;
+
+ private:
+ /// the settings represented by our child elements
+ ::comphelper::NamedValueCollection m_aChildSettings;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagestream.cxx b/dbaccess/source/core/recovery/storagestream.cxx
new file mode 100644
index 000000000..2831f406b
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagestream.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "storagestream.hxx"
+
+#include <com/sun/star/embed/ElementModes.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::embed::XStorage;
+ using ::com::sun::star::io::XStream;
+
+ namespace ElementModes = ::com::sun::star::embed::ElementModes;
+
+ // StorageOutputStream
+ StorageOutputStream::StorageOutputStream( const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ )
+ {
+ ENSURE_OR_THROW( i_rParentStorage.is(), "illegal stream" );
+
+ const Reference< XStream > xStream(
+ i_rParentStorage->openStreamElement( i_rStreamName, ElementModes::READWRITE ), UNO_SET_THROW );
+ m_xOutputStream.set( xStream->getOutputStream(), UNO_SET_THROW );
+ }
+
+ StorageOutputStream::~StorageOutputStream()
+ {
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagestream.hxx b/dbaccess/source/core/recovery/storagestream.hxx
new file mode 100644
index 000000000..64c7e369d
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagestream.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+
+namespace dbaccess
+{
+
+ // StorageOutputStream
+ /** convenience wrapper around a stream living in a storage
+ */
+ class StorageOutputStream
+ {
+ public:
+ StorageOutputStream(
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ virtual ~StorageOutputStream();
+
+ protected:
+ const css::uno::Reference< css::io::XOutputStream >&
+ getOutputStream() const { return m_xOutputStream; }
+
+ private:
+ css::uno::Reference< css::io::XOutputStream >
+ m_xOutputStream;
+ };
+
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagetextstream.cxx b/dbaccess/source/core/recovery/storagetextstream.cxx
new file mode 100644
index 000000000..32f68da9a
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagetextstream.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "storagetextstream.hxx"
+
+#include <com/sun/star/io/TextOutputStream.hpp>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::embed::XStorage;
+ using ::com::sun::star::io::TextOutputStream;
+ using ::com::sun::star::io::XTextOutputStream2;
+
+ // StorageTextOutputStream_Data
+ struct StorageTextOutputStream_Data
+ {
+ Reference< XTextOutputStream2 > xTextOutput;
+ };
+
+ constexpr OUStringLiteral sLineFeed = u"\n";
+
+ // StorageTextOutputStream
+ StorageTextOutputStream::StorageTextOutputStream( const Reference<XComponentContext>& i_rContext,
+ const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ )
+ :StorageOutputStream( i_rParentStorage, i_rStreamName )
+ ,m_pData( new StorageTextOutputStream_Data )
+ {
+ m_pData->xTextOutput = TextOutputStream::create( i_rContext );
+ m_pData->xTextOutput->setEncoding( "UTF-8" );
+ m_pData->xTextOutput->setOutputStream( getOutputStream() );
+ }
+
+ StorageTextOutputStream::~StorageTextOutputStream()
+ {
+ }
+
+ void StorageTextOutputStream::writeLine( const OUString& i_rLine )
+ {
+ m_pData->xTextOutput->writeString( i_rLine );
+ m_pData->xTextOutput->writeString( sLineFeed );
+ }
+
+ void StorageTextOutputStream::writeLine()
+ {
+ m_pData->xTextOutput->writeString( sLineFeed );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagetextstream.hxx b/dbaccess/source/core/recovery/storagetextstream.hxx
new file mode 100644
index 000000000..46c3e5b2e
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagetextstream.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "storagestream.hxx"
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <memory>
+
+namespace dbaccess
+{
+
+ // StorageTextStream
+ struct StorageTextOutputStream_Data;
+ class StorageTextOutputStream : public StorageOutputStream
+ {
+ public:
+ StorageTextOutputStream(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ virtual ~StorageTextOutputStream() override;
+
+ void writeLine( const OUString& i_rLine );
+ void writeLine();
+
+ private:
+ std::unique_ptr< StorageTextOutputStream_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagexmlstream.cxx b/dbaccess/source/core/recovery/storagexmlstream.cxx
new file mode 100644
index 000000000..e76dabefe
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagexmlstream.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "storagexmlstream.hxx"
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+
+#include <rtl/ref.hxx>
+#include <tools/diagnose_ex.h>
+#include <xmloff/attrlist.hxx>
+
+#include <stack>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::embed::XStorage;
+ using ::com::sun::star::xml::sax::XDocumentHandler;
+ using ::com::sun::star::xml::sax::XWriter;
+ using ::com::sun::star::xml::sax::Writer;
+ using ::com::sun::star::xml::sax::Parser;
+ using ::com::sun::star::xml::sax::InputSource;
+
+ // StorageXMLOutputStream_Data
+ struct StorageXMLOutputStream_Data
+ {
+ Reference< XDocumentHandler > xHandler;
+ std::stack< OUString > aElements;
+ ::rtl::Reference< SvXMLAttributeList > xAttributes;
+ };
+
+ // StorageXMLOutputStream
+ StorageXMLOutputStream::StorageXMLOutputStream( const Reference<XComponentContext>& i_rContext,
+ const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName )
+ :StorageOutputStream( i_rParentStorage, i_rStreamName )
+ ,m_pData( new StorageXMLOutputStream_Data )
+ {
+ const Reference< XWriter > xSaxWriter = Writer::create( i_rContext );
+ xSaxWriter->setOutputStream( getOutputStream() );
+
+ m_pData->xHandler.set( xSaxWriter, UNO_QUERY_THROW );
+ m_pData->xHandler->startDocument();
+
+ m_pData->xAttributes = new SvXMLAttributeList;
+ }
+
+ StorageXMLOutputStream::~StorageXMLOutputStream()
+ {
+ }
+
+ void StorageXMLOutputStream::close()
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "illegal document handler" );
+ m_pData->xHandler->endDocument();
+ // do not call the base class, it would call closeOutput on the output stream, which is already done by
+ // endDocument
+ }
+
+ void StorageXMLOutputStream::addAttribute( const OUString& i_rName, const OUString& i_rValue ) const
+ {
+ m_pData->xAttributes->AddAttribute( i_rName, i_rValue );
+ }
+
+ void StorageXMLOutputStream::startElement( const OUString& i_rElementName ) const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+
+ m_pData->xHandler->startElement( i_rElementName, m_pData->xAttributes );
+ m_pData->xAttributes = new SvXMLAttributeList;
+ m_pData->aElements.push( i_rElementName );
+ }
+
+ void StorageXMLOutputStream::endElement() const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+ ENSURE_OR_RETURN_VOID( !m_pData->aElements.empty(), "no element on the stack" );
+
+ const OUString sElementName( m_pData->aElements.top() );
+ m_pData->xHandler->endElement( sElementName );
+ m_pData->aElements.pop();
+ }
+
+ void StorageXMLOutputStream::ignorableWhitespace( const OUString& i_rWhitespace ) const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+
+ m_pData->xHandler->ignorableWhitespace( i_rWhitespace );
+ }
+
+ void StorageXMLOutputStream::characters( const OUString& i_rCharacters ) const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+
+ m_pData->xHandler->characters( i_rCharacters );
+ }
+
+ // StorageXMLInputStream
+ StorageXMLInputStream::StorageXMLInputStream( const Reference<XComponentContext>& i_rContext,
+ const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName )
+ {
+ ENSURE_OR_THROW( i_rParentStorage.is(), "illegal stream" );
+
+ const Reference< css::io::XStream > xStream(
+ i_rParentStorage->openStreamElement( i_rStreamName, css::embed::ElementModes::READ ), css::uno::UNO_SET_THROW );
+ m_xInputStream.set( xStream->getInputStream(), css::uno::UNO_SET_THROW );
+
+ m_xParser.set( Parser::create(i_rContext) );
+ }
+
+ void StorageXMLInputStream::import( const Reference< XDocumentHandler >& i_rHandler )
+ {
+ ENSURE_OR_THROW( i_rHandler.is(), "illegal document handler (NULL)" );
+
+ InputSource aInputSource;
+ aInputSource.aInputStream = m_xInputStream;
+
+ m_xParser->setDocumentHandler( i_rHandler );
+ m_xParser->parseStream( aInputSource );
+ }
+
+ StorageXMLInputStream::~StorageXMLInputStream()
+ {
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagexmlstream.hxx b/dbaccess/source/core/recovery/storagexmlstream.hxx
new file mode 100644
index 000000000..fd762ae05
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagexmlstream.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "storagestream.hxx"
+
+#include <com/sun/star/xml/sax/XParser.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <memory>
+
+namespace dbaccess
+{
+
+ // StorageXMLOutputStream
+ struct StorageXMLOutputStream_Data;
+ class StorageXMLOutputStream : public StorageOutputStream
+ {
+ public:
+ StorageXMLOutputStream(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ virtual ~StorageXMLOutputStream() override;
+
+ void close();
+
+ void addAttribute( const OUString& i_rName, const OUString& i_rValue ) const;
+
+ void startElement( const OUString& i_rElementName ) const;
+ void endElement() const;
+
+ void ignorableWhitespace( const OUString& i_rWhitespace ) const;
+ void characters( const OUString& i_rCharacters ) const;
+
+ private:
+ StorageXMLOutputStream( const StorageXMLOutputStream& ) = delete;
+ StorageXMLOutputStream& operator=( const StorageXMLOutputStream& ) = delete;
+
+ private:
+ std::unique_ptr< StorageXMLOutputStream_Data > m_pData;
+ };
+
+ class StorageXMLInputStream
+ {
+ public:
+ StorageXMLInputStream(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ ~StorageXMLInputStream();
+
+ void import(
+ const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_rHandler
+ );
+
+ StorageXMLInputStream( const StorageXMLInputStream& ) = delete;
+ StorageXMLInputStream& operator=( const StorageXMLInputStream& ) = delete;
+
+ private:
+ css::uno::Reference< css::xml::sax::XParser > m_xParser;
+ css::uno::Reference< css::io::XInputStream > m_xInputStream;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentloader.cxx b/dbaccess/source/core/recovery/subcomponentloader.cxx
new file mode 100644
index 000000000..3393c3d13
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentloader.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "subcomponentloader.hxx"
+
+#include <com/sun/star/ucb/Command.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::awt::WindowEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::ucb::Command;
+ using ::com::sun::star::ucb::XCommandProcessor;
+ using ::com::sun::star::frame::XController2;
+ using ::com::sun::star::lang::XComponent;
+
+ // SubComponentLoader
+ SubComponentLoader::SubComponentLoader( const Reference< XController >& i_rApplicationController,
+ const Reference< XCommandProcessor >& i_rSubDocumentDefinition )
+ :mxDocDefCommands( i_rSubDocumentDefinition )
+ {
+ // add as window listener to the controller's container window, so we get notified when it is shown
+ Reference< XController2 > xController( i_rApplicationController, UNO_QUERY_THROW );
+ mxAppComponentWindow.set( xController->getComponentWindow(), UNO_SET_THROW );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ mxAppComponentWindow->addWindowListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ SubComponentLoader::SubComponentLoader( const Reference< XController >& i_rApplicationController,
+ const Reference< XComponent >& i_rNonDocumentComponent )
+ :mxNonDocComponent( i_rNonDocumentComponent )
+ {
+ // add as window listener to the controller's container window, so we get notified when it is shown
+ Reference< XController2 > xController( i_rApplicationController, UNO_QUERY_THROW );
+ mxAppComponentWindow.set( xController->getComponentWindow(), UNO_SET_THROW );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ mxAppComponentWindow->addWindowListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ SubComponentLoader::~SubComponentLoader()
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::windowResized( const WindowEvent& )
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::windowMoved( const WindowEvent& )
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::windowShown( const EventObject& )
+ {
+ try
+ {
+ if ( mxDocDefCommands.is() )
+ {
+ Command aCommandOpen;
+ aCommandOpen.Name = "show";
+
+ const sal_Int32 nCommandIdentifier = mxDocDefCommands->createCommandIdentifier();
+ mxDocDefCommands->execute( aCommandOpen, nCommandIdentifier, nullptr );
+ }
+ else
+ {
+ const Reference< XController > xController( mxNonDocComponent, UNO_QUERY_THROW );
+ const Reference< XFrame > xFrame( xController->getFrame(), UNO_SET_THROW );
+ const Reference< XWindow > xWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
+ xWindow->setVisible( true );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ mxAppComponentWindow->removeWindowListener( this );
+ }
+
+ void SAL_CALL SubComponentLoader::windowHidden( const EventObject& )
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::disposing( const EventObject& )
+ {
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentloader.hxx b/dbaccess/source/core/recovery/subcomponentloader.hxx
new file mode 100644
index 000000000..4ab867880
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentloader.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace dbaccess
+{
+
+ // SubComponentLoader
+ typedef ::cppu::WeakImplHelper< css::awt::XWindowListener
+ > SubComponentLoader_Base;
+ /** is a helper class which loads/opens a given sub component as soon as the main application
+ window becomes visible.
+ */
+ class SubComponentLoader : public SubComponentLoader_Base
+ {
+ public:
+ SubComponentLoader(
+ const css::uno::Reference< css::frame::XController >& i_rApplicationController,
+ const css::uno::Reference< css::ucb::XCommandProcessor >& i_rSubDocumentDefinition
+ );
+
+ SubComponentLoader(
+ const css::uno::Reference< css::frame::XController >& i_rApplicationController,
+ const css::uno::Reference< css::lang::XComponent >& i_rNonDocumentComponent
+ );
+
+ // XWindowListener
+ virtual void SAL_CALL windowResized( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowMoved( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowShown( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowHidden( const css::lang::EventObject& e ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ protected:
+ virtual ~SubComponentLoader() override;
+
+ private:
+ const css::uno::Reference< css::ucb::XCommandProcessor > mxDocDefCommands;
+ const css::uno::Reference< css::lang::XComponent > mxNonDocComponent;
+ css::uno::Reference< css::awt::XWindow > mxAppComponentWindow;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentrecovery.cxx b/dbaccess/source/core/recovery/subcomponentrecovery.cxx
new file mode 100644
index 000000000..e7ffffd61
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentrecovery.cxx
@@ -0,0 +1,628 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "subcomponentrecovery.hxx"
+
+#include <sdbcoretools.hxx>
+#include "storagexmlstream.hxx"
+#include "subcomponentloader.hxx"
+#include "settingsimport.hxx"
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <connectivity/dbtools.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <xmloff/XMLSettingsExportContext.hxx>
+#include <xmloff/SettingsExportHelper.hxx>
+
+#include <stack>
+
+namespace dbaccess
+{
+
+ using css::uno::Reference;
+ using css::uno::XInterface;
+ using css::uno::UNO_QUERY;
+ using css::uno::UNO_QUERY_THROW;
+ using css::uno::UNO_SET_THROW;
+ using css::uno::Exception;
+ using css::uno::RuntimeException;
+ using css::uno::Any;
+ using css::uno::Sequence;
+ using css::uno::XComponentContext;
+ using css::embed::XStorage;
+ using css::sdb::application::XDatabaseDocumentUI;
+ using css::beans::Pair;
+ using css::frame::ModuleManager;
+ using css::frame::XModuleManager2;
+ using css::lang::XComponent;
+ using css::frame::XModel;
+ using css::frame::XController;
+ using css::beans::XPropertySet;
+ using css::beans::PropertyValue;
+ using css::document::XStorageBasedDocument;
+ using css::ucb::XCommandProcessor;
+ using css::container::XHierarchicalNameAccess;
+ using css::sdb::XFormDocumentsSupplier;
+ using css::sdb::XReportDocumentsSupplier;
+ using css::xml::sax::XLocator;
+ using css::xml::sax::XDocumentHandler;
+ using css::xml::sax::XAttributeList;
+
+ namespace ElementModes = css::embed::ElementModes;
+ namespace DatabaseObject = css::sdb::application::DatabaseObject;
+
+ // helper
+ namespace
+ {
+ OUString lcl_getComponentStorageBaseName( const SubComponentType i_eType )
+ {
+ switch ( i_eType )
+ {
+ case FORM:
+ return "form";
+ case REPORT:
+ return "report";
+ case TABLE:
+ return "table";
+ case QUERY:
+ return "query";
+ default:
+ break;
+ }
+
+ OSL_FAIL( "lcl_getComponentStorageBaseName: unimplemented case!" );
+ return OUString();
+ }
+
+ SubComponentType lcl_databaseObjectToSubComponentType( const sal_Int32 i_nObjectType )
+ {
+ switch ( i_nObjectType )
+ {
+ case DatabaseObject::TABLE: return TABLE;
+ case DatabaseObject::QUERY: return QUERY;
+ case DatabaseObject::FORM: return FORM;
+ case DatabaseObject::REPORT:return REPORT;
+ default:
+ break;
+ }
+ return UNKNOWN;
+ }
+
+ bool lcl_determineReadOnly( const Reference< XComponent >& i_rComponent )
+ {
+ Reference< XModel > xDocument( i_rComponent, UNO_QUERY );
+ if ( !xDocument.is() )
+ {
+ Reference< XController > xController( i_rComponent, UNO_QUERY_THROW );
+ xDocument = xController->getModel();
+ }
+
+ if ( !xDocument.is() )
+ return false;
+
+ ::comphelper::NamedValueCollection aDocArgs( xDocument->getArgs() );
+ return aDocArgs.getOrDefault( "ReadOnly", false );
+ }
+
+ Reference< XCommandProcessor > lcl_getSubComponentDef_nothrow( const Reference< XDatabaseDocumentUI >& i_rAppUI,
+ const SubComponentType i_eType, const OUString& i_rName )
+ {
+ Reference< XController > xController( i_rAppUI, UNO_QUERY_THROW );
+ ENSURE_OR_RETURN( ( i_eType == FORM ) || ( i_eType == REPORT ), "lcl_getSubComponentDef_nothrow: illegal controller", nullptr );
+
+ Reference< XCommandProcessor > xCommandProcessor;
+ try
+ {
+ Reference< XHierarchicalNameAccess > xDefinitionContainer;
+ if ( i_eType == FORM )
+ {
+ Reference< XFormDocumentsSupplier > xSuppForms( xController->getModel(), UNO_QUERY_THROW );
+ xDefinitionContainer.set( xSuppForms->getFormDocuments(), UNO_QUERY_THROW );
+ }
+ else
+ {
+ Reference< XReportDocumentsSupplier > xSuppReports( xController->getModel(), UNO_QUERY_THROW );
+ xDefinitionContainer.set( xSuppReports->getReportDocuments(), UNO_QUERY_THROW );
+ }
+ xCommandProcessor.set( xDefinitionContainer->getByHierarchicalName( i_rName ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xCommandProcessor;
+ }
+
+ constexpr OUStringLiteral sSettingsStreamName = u"settings.xml";
+ constexpr OUStringLiteral sCurrentQueryDesignName = u"ooo:current-query-design";
+ }
+
+ namespace {
+
+ // SettingsExportContext
+ class SettingsExportContext : public ::xmloff::XMLSettingsExportContext
+ {
+ public:
+ SettingsExportContext( const Reference<XComponentContext>& i_rContext, const StorageXMLOutputStream& i_rDelegator )
+ :m_rContext( i_rContext )
+ ,m_rDelegator( i_rDelegator )
+ ,m_aNamespace( ::xmloff::token::GetXMLToken( ::xmloff::token::XML_NP_CONFIG ) )
+ {
+ }
+
+ virtual ~SettingsExportContext()
+ {
+ }
+
+ public:
+ virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue ) override;
+ virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue ) override;
+ virtual void StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) override;
+ virtual void EndElement ( const bool i_bIgnoreWhitespace ) override;
+ virtual void Characters( const OUString& i_rCharacters ) override;
+
+ virtual css::uno::Reference< css::uno::XComponentContext >
+ GetComponentContext() const override;
+
+ private:
+ OUString impl_prefix( const ::xmloff::token::XMLTokenEnum i_eToken )
+ {
+ return m_aNamespace + ":" + ::xmloff::token::GetXMLToken( i_eToken );
+ }
+
+ private:
+ const Reference<XComponentContext>& m_rContext;
+ const StorageXMLOutputStream& m_rDelegator;
+ const OUString m_aNamespace;
+ };
+
+ }
+
+ void SettingsExportContext::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue )
+ {
+ m_rDelegator.addAttribute( impl_prefix( i_eName ), i_rValue );
+ }
+
+ void SettingsExportContext::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue )
+ {
+ m_rDelegator.addAttribute( impl_prefix( i_eName ), ::xmloff::token::GetXMLToken( i_eValue ) );
+ }
+
+ void SettingsExportContext::StartElement( enum ::xmloff::token::XMLTokenEnum i_eName )
+ {
+ m_rDelegator.ignorableWhitespace( " " );
+
+ m_rDelegator.startElement( impl_prefix( i_eName ) );
+ }
+
+ void SettingsExportContext::EndElement( const bool i_bIgnoreWhitespace )
+ {
+ if ( i_bIgnoreWhitespace )
+ m_rDelegator.ignorableWhitespace( " " );
+ m_rDelegator.endElement();
+ }
+
+ void SettingsExportContext::Characters( const OUString& i_rCharacters )
+ {
+ m_rDelegator.characters( i_rCharacters );
+ }
+
+ Reference< css::uno::XComponentContext > SettingsExportContext::GetComponentContext() const
+ {
+ return m_rContext;
+ }
+
+ // SettingsDocumentHandler
+ typedef ::cppu::WeakImplHelper< XDocumentHandler
+ > SettingsDocumentHandler_Base;
+
+ namespace {
+
+ class SettingsDocumentHandler : public SettingsDocumentHandler_Base
+ {
+ public:
+ SettingsDocumentHandler()
+ {
+ }
+
+ protected:
+ virtual ~SettingsDocumentHandler() override
+ {
+ }
+
+ public:
+ // XDocumentHandler
+ virtual void SAL_CALL startDocument( ) override;
+ virtual void SAL_CALL endDocument( ) override;
+ virtual void SAL_CALL startElement( const OUString& aName, const Reference< XAttributeList >& xAttribs ) override;
+ virtual void SAL_CALL endElement( const OUString& aName ) override;
+ virtual void SAL_CALL characters( const OUString& aChars ) override;
+ virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override;
+ virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) override;
+ virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& xLocator ) override;
+
+ const ::comphelper::NamedValueCollection& getSettings() const { return m_aSettings; }
+
+ private:
+ std::stack< ::rtl::Reference< SettingsImport > > m_aStates;
+ ::comphelper::NamedValueCollection m_aSettings;
+ };
+
+ }
+
+ void SAL_CALL SettingsDocumentHandler::startDocument( )
+ {
+ }
+
+ void SAL_CALL SettingsDocumentHandler::endDocument( )
+ {
+ }
+
+ void SAL_CALL SettingsDocumentHandler::startElement( const OUString& i_Name, const Reference< XAttributeList >& i_Attribs )
+ {
+ ::rtl::Reference< SettingsImport > pNewState;
+
+ if ( m_aStates.empty() )
+ {
+ if ( i_Name == "office:settings" )
+ {
+ pNewState = new OfficeSettingsImport( m_aSettings );
+ }
+ else
+ {
+ OSL_FAIL( "SettingsDocumentHandler::startElement: invalid settings file!" );
+ // Yes, that's not correct. Somebody could, in theory, give us a document which starts with "foo:settings",
+ // where "foo" is mapped to the proper namespace URL.
+ // However, there's no need to bother with this. The "recovery" sub storage we're recovering from is
+ // not part of ODF, so we can impose any format restrictions on it ...
+ }
+ }
+ else
+ {
+ ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() );
+ pNewState = pCurrentState->nextState( i_Name );
+ }
+
+ ENSURE_OR_THROW( pNewState.is(), "no new state - aborting import" );
+ pNewState->startElement( i_Attribs );
+
+ m_aStates.push( pNewState );
+ }
+
+ void SAL_CALL SettingsDocumentHandler::endElement( const OUString& )
+ {
+ ENSURE_OR_THROW( !m_aStates.empty(), "no active element" );
+
+ ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() );
+ pCurrentState->endElement();
+ m_aStates.pop();
+ }
+
+ void SAL_CALL SettingsDocumentHandler::characters( const OUString& i_Chars )
+ {
+ ENSURE_OR_THROW( !m_aStates.empty(), "no active element" );
+
+ ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() );
+ pCurrentState->characters( i_Chars );
+ }
+
+ void SAL_CALL SettingsDocumentHandler::ignorableWhitespace( const OUString& )
+ {
+ // ignore them - that's why they're called "ignorable"
+ }
+
+ void SAL_CALL SettingsDocumentHandler::processingInstruction( const OUString&, const OUString& )
+ {
+ OSL_FAIL( "SettingsDocumentHandler::processingInstruction: unexpected ..." );
+ }
+
+ void SAL_CALL SettingsDocumentHandler::setDocumentLocator( const Reference< XLocator >& ) {}
+
+ // SubComponentRecovery
+ OUString SubComponentRecovery::getComponentsStorageName( const SubComponentType i_eType )
+ {
+ switch ( i_eType )
+ {
+ case FORM:
+ return "forms";
+ case REPORT:
+ return "reports";
+ case TABLE:
+ return "tables";
+ case QUERY:
+ return "queries";
+ case RELATION_DESIGN:
+ return "relations";
+ default:
+ break;
+ }
+
+ OSL_FAIL( "SubComponentRecovery::getComponentsStorageName: unimplemented case!" );
+ return OUString();
+ }
+
+ void SubComponentRecovery::saveToRecoveryStorage( const Reference< XStorage >& i_rRecoveryStorage,
+ MapCompTypeToCompDescs& io_mapCompDescs )
+ {
+ if ( m_eType == UNKNOWN )
+ // quite fatal, but has already been reported (as assertion) before
+ return;
+
+ // open the sub storage for the given kind of components
+ const OUString& rStorageName( getComponentsStorageName( m_eType ) );
+ const Reference< XStorage > xComponentsStorage( i_rRecoveryStorage->openStorageElement(
+ rStorageName, ElementModes::READWRITE ), UNO_SET_THROW );
+
+ // find a free sub storage name, and create Yet Another Sub Storage
+ const OUString& rBaseName( lcl_getComponentStorageBaseName( m_eType ) );
+ const OUString sStorName = ::dbtools::createUniqueName( xComponentsStorage, rBaseName );
+ const Reference< XStorage > xObjectStor( xComponentsStorage->openStorageElement(
+ sStorName, ElementModes::READWRITE ), UNO_SET_THROW );
+
+ switch ( m_eType )
+ {
+ case FORM:
+ case REPORT:
+ impl_saveSubDocument_throw( xObjectStor );
+ break;
+
+ case QUERY:
+ impl_saveQueryDesign_throw( xObjectStor );
+ break;
+
+ default:
+ // TODO
+ OSL_FAIL( "SubComponentRecoverys::saveToRecoveryStorage: unimplemented case!" );
+ break;
+ }
+
+ // commit the storage(s)
+ tools::stor::commitStorageIfWriteable( xObjectStor );
+ tools::stor::commitStorageIfWriteable( xComponentsStorage );
+
+ // remember the relationship from the component name to the storage name
+ MapStringToCompDesc& rMapCompDescs = io_mapCompDescs[ m_eType ];
+ OSL_ENSURE( rMapCompDescs.find( sStorName ) == rMapCompDescs.end(),
+ "SubComponentRecoverys::saveToRecoveryStorage: object name already used!" );
+ rMapCompDescs[ sStorName ] = m_aCompDesc;
+ }
+
+ void SubComponentRecovery::impl_identifyComponent_throw()
+ {
+ // ask the controller
+ Pair< sal_Int32, OUString > aComponentIdentity = m_xDocumentUI->identifySubComponent( m_xComponent );
+ m_eType = lcl_databaseObjectToSubComponentType( aComponentIdentity.First );
+ m_aCompDesc.sName = aComponentIdentity.Second;
+
+ // what the controller didn't give us is the information whether this is in edit mode or not ...
+ Reference< XModuleManager2 > xModuleManager( ModuleManager::create(m_rContext) );
+ const OUString sModuleIdentifier = xModuleManager->identify( m_xComponent );
+
+ switch ( m_eType )
+ {
+ case TABLE:
+ m_aCompDesc.bForEditing = sModuleIdentifier == "com.sun.star.sdb.TableDesign";
+ break;
+
+ case QUERY:
+ m_aCompDesc.bForEditing = sModuleIdentifier == "com.sun.star.sdb.QueryDesign";
+ break;
+
+ case REPORT:
+ if ( sModuleIdentifier == "com.sun.star.report.ReportDefinition" )
+ {
+ // it's an SRB report designer
+ m_aCompDesc.bForEditing = true;
+ break;
+ }
+ [[fallthrough]];
+
+ case FORM:
+ m_aCompDesc.bForEditing = !lcl_determineReadOnly( m_xComponent );
+ break;
+
+ default:
+ if ( sModuleIdentifier == "com.sun.star.sdb.RelationDesign" )
+ {
+ m_eType = RELATION_DESIGN;
+ m_aCompDesc.bForEditing = true;
+ }
+ else
+ {
+ OSL_FAIL( "SubComponentRecovery::impl_identifyComponent_throw: couldn't classify the given sub component!" );
+ }
+ break;
+ }
+
+ SAL_WARN_IF( m_eType == UNKNOWN, "dbaccess",
+ "SubComponentRecovery::impl_identifyComponent_throw: couldn't classify the component!" );
+ }
+
+ void SubComponentRecovery::impl_saveQueryDesign_throw( const Reference< XStorage >& i_rObjectStorage )
+ {
+ ENSURE_OR_THROW( m_eType == QUERY, "illegal sub component type" );
+ ENSURE_OR_THROW( i_rObjectStorage.is(), "illegal storage" );
+
+ // retrieve the current query design (which might differ from what we can retrieve as ActiveCommand property, since
+ // the latter is updated only upon successful save of the design)
+ Reference< XPropertySet > xDesignerProps( m_xComponent, UNO_QUERY_THROW );
+ Sequence< PropertyValue > aCurrentQueryDesign;
+ OSL_VERIFY( xDesignerProps->getPropertyValue( "CurrentQueryDesign" ) >>= aCurrentQueryDesign );
+
+ // write the query design
+ StorageXMLOutputStream aDesignOutput( m_rContext, i_rObjectStorage, sSettingsStreamName );
+ SettingsExportContext aSettingsExportContext( m_rContext, aDesignOutput );
+
+ static const OUStringLiteral sWhitespace( u" " );
+
+ aDesignOutput.startElement( "office:settings" );
+ aDesignOutput.ignorableWhitespace( sWhitespace );
+
+ XMLSettingsExportHelper aSettingsExporter( aSettingsExportContext );
+ aSettingsExporter.exportAllSettings( aCurrentQueryDesign, sCurrentQueryDesignName );
+
+ aDesignOutput.ignorableWhitespace( sWhitespace );
+ aDesignOutput.endElement();
+ aDesignOutput.close();
+ }
+
+ void SubComponentRecovery::impl_saveSubDocument_throw( const Reference< XStorage >& i_rObjectStorage )
+ {
+ ENSURE_OR_THROW( ( m_eType == FORM ) || ( m_eType == REPORT ), "illegal sub component type" );
+ ENSURE_OR_THROW( i_rObjectStorage.is(), "illegal storage" );
+
+ // store the document into the storage
+ Reference< XStorageBasedDocument > xStorageDocument( m_xComponent, UNO_QUERY_THROW );
+ xStorageDocument->storeToStorage( i_rObjectStorage, Sequence< PropertyValue >() );
+ }
+
+ Reference< XComponent > SubComponentRecovery::impl_recoverSubDocument_throw( const Reference< XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName, const bool i_bForEditing )
+ {
+ Reference< XComponent > xSubComponent;
+ Reference< XCommandProcessor > xDocDefinition;
+
+ ::comphelper::NamedValueCollection aLoadArgs;
+ aLoadArgs.put( "RecoveryStorage", i_rRecoveryStorage );
+
+ // load/create the sub component hidden. We'll show it when the main app window is shown.
+ aLoadArgs.put( "Hidden", true );
+
+ if ( !i_rComponentName.isEmpty() )
+ {
+ xDocDefinition = lcl_getSubComponentDef_nothrow( m_xDocumentUI, m_eType, i_rComponentName );
+ xSubComponent.set( m_xDocumentUI->loadComponentWithArguments(
+ m_eType,
+ i_rComponentName,
+ i_bForEditing,
+ aLoadArgs.getPropertyValues()
+ ),
+ UNO_SET_THROW
+ );
+ }
+ else
+ {
+ Reference< XComponent > xDocDefComponent;
+ xSubComponent.set( m_xDocumentUI->createComponentWithArguments(
+ m_eType,
+ aLoadArgs.getPropertyValues(),
+ xDocDefComponent
+ ),
+ UNO_SET_THROW
+ );
+
+ xDocDefinition.set( xDocDefComponent, UNO_QUERY );
+ OSL_ENSURE( xDocDefinition.is(), "DatabaseDocumentRecovery::recoverSubDocuments: loaded a form/report, but don't have a document definition?!" );
+ }
+
+ if ( xDocDefinition.is() )
+ {
+ Reference< XController > xController( m_xDocumentUI, UNO_QUERY_THROW );
+ rtl::Reference( new SubComponentLoader( xController, xDocDefinition ) );
+ }
+
+ return xSubComponent;
+ }
+
+ Reference< XComponent > SubComponentRecovery::impl_recoverQueryDesign_throw( const Reference< XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName, const bool i_bForEditing )
+ {
+ Reference< XComponent > xSubComponent;
+
+ // first read the settings query design settings from the storage
+ StorageXMLInputStream aDesignInput( m_rContext, i_rRecoveryStorage, sSettingsStreamName );
+
+ ::rtl::Reference< SettingsDocumentHandler > pDocHandler( new SettingsDocumentHandler );
+ aDesignInput.import( pDocHandler );
+
+ const ::comphelper::NamedValueCollection& rSettings( pDocHandler->getSettings() );
+ const Any& aCurrentQueryDesign = rSettings.get( sCurrentQueryDesignName );
+#if OSL_DEBUG_LEVEL > 0
+ Sequence< PropertyValue > aQueryDesignLayout;
+ OSL_VERIFY( aCurrentQueryDesign >>= aQueryDesignLayout );
+#endif
+
+ // then load the query designer
+ ::comphelper::NamedValueCollection aLoadArgs;
+ aLoadArgs.put( "CurrentQueryDesign", aCurrentQueryDesign );
+ aLoadArgs.put( "Hidden", true );
+
+ if ( !i_rComponentName.isEmpty() )
+ {
+ xSubComponent.set( m_xDocumentUI->loadComponentWithArguments(
+ m_eType,
+ i_rComponentName,
+ i_bForEditing,
+ aLoadArgs.getPropertyValues()
+ ),
+ UNO_SET_THROW
+ );
+ }
+ else
+ {
+ Reference< XComponent > xDummy;
+ xSubComponent.set( m_xDocumentUI->createComponentWithArguments(
+ m_eType,
+ aLoadArgs.getPropertyValues(),
+ xDummy
+ ),
+ UNO_SET_THROW
+ );
+ }
+
+ Reference< XController > xController( m_xDocumentUI, UNO_QUERY_THROW );
+ rtl::Reference( new SubComponentLoader( xController, xSubComponent ) );
+
+ return xSubComponent;
+ }
+
+ Reference< XComponent > SubComponentRecovery::recoverFromStorage( const Reference< XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName, const bool i_bForEditing )
+ {
+ Reference< XComponent > xSubComponent;
+ switch ( m_eType )
+ {
+ case FORM:
+ case REPORT:
+ xSubComponent = impl_recoverSubDocument_throw( i_rRecoveryStorage, i_rComponentName, i_bForEditing );
+ break;
+ case QUERY:
+ xSubComponent = impl_recoverQueryDesign_throw( i_rRecoveryStorage, i_rComponentName, i_bForEditing );
+ break;
+ default:
+ OSL_FAIL( "SubComponentRecovery::recoverFromStorage: unimplemented case!" );
+ break;
+ }
+ return xSubComponent;
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentrecovery.hxx b/dbaccess/source/core/recovery/subcomponentrecovery.hxx
new file mode 100644
index 000000000..26b81c63f
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentrecovery.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "subcomponents.hxx"
+
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaccess
+{
+
+ // SubComponentRecovery
+ class SubComponentRecovery
+ {
+ public:
+ SubComponentRecovery(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& i_rController,
+ const css::uno::Reference< css::lang::XComponent >& i_rComponent )
+ :m_rContext( i_rContext )
+ ,m_xDocumentUI( i_rController, css::uno::UNO_SET_THROW )
+ ,m_xComponent( i_rComponent )
+ ,m_eType( UNKNOWN )
+ ,m_aCompDesc()
+ {
+ impl_identifyComponent_throw();
+ }
+
+ SubComponentRecovery(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& i_rController,
+ const SubComponentType i_eType )
+ :m_rContext( i_rContext )
+ ,m_xDocumentUI( i_rController, css::uno::UNO_SET_THROW )
+ ,m_xComponent()
+ ,m_eType( i_eType )
+ ,m_aCompDesc()
+ {
+ }
+
+ // only to be used after being constructed with a component
+ void saveToRecoveryStorage(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ MapCompTypeToCompDescs& io_mapCompDescs
+ );
+
+ // only to be used after being constructed with a type
+ css::uno::Reference< css::lang::XComponent >
+ recoverFromStorage(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName,
+ const bool i_bForEditing
+ );
+
+ static OUString getComponentsStorageName( const SubComponentType i_eType );
+
+ private:
+ void impl_saveSubDocument_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rObjectStorage
+ );
+
+ void impl_saveQueryDesign_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rObjectStorage
+ );
+
+ css::uno::Reference< css::lang::XComponent >
+ impl_recoverSubDocument_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName,
+ const bool i_bForEditing
+ );
+
+ css::uno::Reference< css::lang::XComponent >
+ impl_recoverQueryDesign_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName,
+ const bool i_bForEditing
+ );
+
+ void impl_identifyComponent_throw();
+
+ private:
+ const css::uno::Reference< css::uno::XComponentContext >&
+ m_rContext;
+ css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >
+ m_xDocumentUI;
+ const css::uno::Reference< css::lang::XComponent >
+ m_xComponent;
+ SubComponentType m_eType;
+ SubComponentDescriptor m_aCompDesc;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponents.hxx b/dbaccess/source/core/recovery/subcomponents.hxx
new file mode 100644
index 000000000..5e4173605
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponents.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+
+#include <rtl/ustring.hxx>
+
+#include <map>
+#include <unordered_map>
+
+namespace dbaccess
+{
+
+ enum SubComponentType
+ {
+ TABLE = css::sdb::application::DatabaseObject::TABLE,
+ QUERY = css::sdb::application::DatabaseObject::QUERY,
+ FORM = css::sdb::application::DatabaseObject::FORM,
+ REPORT = css::sdb::application::DatabaseObject::REPORT,
+
+ RELATION_DESIGN = 1000,
+
+ UNKNOWN = 10001
+ };
+
+ struct SubComponentDescriptor
+ {
+ OUString sName;
+ bool bForEditing;
+
+ SubComponentDescriptor()
+ :sName()
+ ,bForEditing( false )
+ {
+ }
+ };
+
+ typedef std::unordered_map< OUString, SubComponentDescriptor > MapStringToCompDesc;
+ typedef std::map< SubComponentType, MapStringToCompDesc > MapCompTypeToCompDescs;
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/resource/core_resource.cxx b/dbaccess/source/core/resource/core_resource.cxx
new file mode 100644
index 000000000..fdef07e1f
--- /dev/null
+++ b/dbaccess/source/core/resource/core_resource.cxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+
+#include <unotools/resmgr.hxx>
+
+namespace dbaccess
+{
+ OUString ResourceManager::loadString(TranslateId pResId)
+ {
+ return Translate::get(pResId, Translate::Create("dba"));
+ }
+
+ OUString ResourceManager::loadString(TranslateId pResId, const char* _pPlaceholderAscii1, std::u16string_view _rReplace1,
+ const char* _pPlaceholderAscii2, std::u16string_view _rReplace2)
+ {
+ OUString sString(loadString(pResId));
+ sString = sString.replaceFirst( OUString::createFromAscii(_pPlaceholderAscii1), _rReplace1 );
+ sString = sString.replaceFirst( OUString::createFromAscii(_pPlaceholderAscii2), _rReplace2 );
+ return sString;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/alterparser.cxx b/dbaccess/source/filter/hsqldb/alterparser.cxx
new file mode 100644
index 000000000..1dd770b1f
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/alterparser.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <sal/log.hxx>
+#include "alterparser.hxx"
+#include "utils.hxx"
+
+namespace dbahsql
+{
+void AlterStmtParser::parse(const OUString& sSql)
+{
+ m_sStmt = sSql;
+ if (!sSql.startsWith("ALTER"))
+ {
+ SAL_WARN("dbaccess", "Not an ALTER statement");
+ return;
+ }
+
+ m_sTableName = utils::getTableNameFromStmt(sSql);
+ auto words = comphelper::string::split(sSql, sal_Unicode(u' '));
+
+ if (words[3] == "ALTER" && words[4] == "COLUMN")
+ {
+ m_sColumnName = words[5];
+ if (words[6] == "RESTART" && words[7] == "WITH")
+ {
+ m_eAction = AlterAction::IDENTITY_RESTART;
+ m_nIdentityParam = words[8].toInt32();
+ }
+ }
+ else if (words[3] == "ADD" && words[4] == "CONSTRAINT")
+ {
+ m_eAction = AlterAction::ADD_FOREIGN;
+ }
+}
+
+} // namespace dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/alterparser.hxx b/dbaccess/source/filter/hsqldb/alterparser.hxx
new file mode 100644
index 000000000..813ca7b0b
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/alterparser.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+namespace dbahsql
+{
+enum class AlterAction
+{
+ UNKNOWN,
+ ADD_FOREIGN,
+ IDENTITY_RESTART
+};
+
+class AlterStmtParser
+{
+private:
+ OUString m_sStmt;
+ OUString m_sTableName;
+ OUString m_sColumnName;
+ AlterAction m_eAction = AlterAction::UNKNOWN;
+ sal_Int32 m_nIdentityParam = 0;
+
+protected:
+ AlterAction getActionType() const { return m_eAction; }
+ OUString const& getColumnName() const { return m_sColumnName; }
+ sal_Int32 getIdentityParam() const { return m_nIdentityParam; }
+ OUString const& getStatement() const { return m_sStmt; }
+
+public:
+ virtual ~AlterStmtParser() = default;
+
+ /**
+ * @return name of the table which is to be created.
+ */
+ OUString const& getTableName() const { return m_sTableName; }
+
+ void parse(const OUString& sSql);
+
+ virtual OUString compose() const = 0;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/columndef.cxx b/dbaccess/source/filter/hsqldb/columndef.cxx
new file mode 100644
index 000000000..5a7b74108
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/columndef.cxx
@@ -0,0 +1,44 @@
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "columndef.hxx"
+#include <com/sun/star/sdbc/DataType.hpp>
+
+namespace dbahsql
+{
+using namespace css::sdbc;
+
+ColumnDefinition::ColumnDefinition(const OUString& sName, sal_Int32 eType,
+ std::vector<sal_Int32>&& aParams, bool bPrimary,
+ sal_Int32 nAutoIncr, bool bNullable, bool bCaseInsensitive,
+ const OUString& sDefault)
+ : m_sName(sName)
+ , m_eType(eType)
+ , m_aParams(std::move(aParams))
+ , m_bPrimaryKey(bPrimary)
+ , m_nAutoIncrement(nAutoIncr)
+ , m_bNullable(bNullable)
+ , m_bCaseInsensitive(bCaseInsensitive)
+ , m_sDefaultValue(sDefault)
+{
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/columndef.hxx b/dbaccess/source/filter/hsqldb/columndef.hxx
new file mode 100644
index 000000000..5ffa18ba5
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/columndef.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <vector>
+
+namespace dbahsql
+{
+/// nAutoIncrement: column is auto incremented started with value nAutoIncrement
+class ColumnDefinition
+{
+private:
+ OUString m_sName;
+ sal_Int32 m_eType; // css::sdbc::DataType
+ std::vector<sal_Int32> m_aParams;
+ bool m_bPrimaryKey;
+ sal_Int32 m_nAutoIncrement;
+ bool m_bNullable;
+ bool m_bCaseInsensitive;
+ OUString m_sDefaultValue;
+
+public:
+ ColumnDefinition(const OUString& sName, sal_Int32 eType, std::vector<sal_Int32>&& aParams,
+ bool bPrimary = false, sal_Int32 nAutoIncr = -1, bool bNullable = true,
+ bool bCaseInsensitive = false, const OUString& sDefault = OUString{});
+
+ OUString const& getName() const { return m_sName; }
+ sal_Int32 getDataType() const { return m_eType; }
+ bool isPrimaryKey() const { return m_bPrimaryKey; }
+ bool isNullable() const { return m_bNullable; }
+ bool isAutoIncremental() const { return m_nAutoIncrement >= 0; }
+ bool isCaseInsensitive() const { return m_bCaseInsensitive; }
+ sal_Int32 getStartValue() const { return m_nAutoIncrement; }
+ const std::vector<sal_Int32>& getParams() const { return m_aParams; }
+ OUString const& getDefault() const { return m_sDefaultValue; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/createparser.cxx b/dbaccess/source/filter/hsqldb/createparser.cxx
new file mode 100644
index 000000000..360741ce0
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/createparser.cxx
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+#include "createparser.hxx"
+#include "utils.hxx"
+#include <com/sun/star/sdbc/DataType.hpp>
+
+using namespace ::comphelper;
+using namespace css::sdbc;
+
+namespace
+{
+/// Returns substring of sSql from the first occurrence of '(' until the
+/// last occurrence of ')' (excluding the parenthesis)
+std::u16string_view lcl_getColumnPart(std::u16string_view sSql)
+{
+ size_t nBeginIndex = sSql.find('(');
+ if (nBeginIndex == std::u16string_view::npos)
+ {
+ SAL_WARN("dbaccess", "No column definitions found");
+ return std::u16string_view();
+ }
+ sal_Int32 nCount = sSql.rfind(')') - nBeginIndex - 1;
+ auto sPart = sSql.substr(nBeginIndex + 1, nCount);
+ return sPart;
+}
+
+/// Constructs a vector of strings that represents the definitions of each
+/// column or constraint.
+///
+/// @param sColumnPart part of the create statement inside the parenthesis
+/// containing the column definitions
+std::vector<OUString> lcl_splitColumnPart(std::u16string_view sColumnPart)
+{
+ std::vector<OUString> sParts = string::split(sColumnPart, sal_Unicode(u','));
+ std::vector<OUString> sReturn;
+
+ OUStringBuffer current(128);
+ for (auto const& part : sParts)
+ {
+ current.append(part);
+ if (current.lastIndexOf("(") > current.lastIndexOf(")"))
+ current.append(","); // it was false split
+ else
+ {
+ sReturn.push_back(current.toString());
+ current.setLength(0);
+ }
+ }
+ return sReturn;
+}
+
+sal_Int32 lcl_getAutoIncrementDefault(std::u16string_view sColumnDef)
+{
+ // TODO what if there are more spaces?
+ size_t nPos = sColumnDef.find(u"GENERATED BY DEFAULT AS IDENTITY");
+ if (nPos != std::u16string_view::npos && nPos > 0)
+ {
+ // TODO parse starting sequence stated by "START WITH"
+ return 0;
+ }
+ return -1;
+}
+
+std::u16string_view lcl_getDefaultValue(std::u16string_view sColumnDef)
+{
+ constexpr std::u16string_view DEFAULT_KW = u"DEFAULT";
+ size_t nDefPos = sColumnDef.find(DEFAULT_KW);
+ if (nDefPos > 0 && nDefPos != std::u16string_view::npos
+ && lcl_getAutoIncrementDefault(sColumnDef) < 0)
+ {
+ std::u16string_view fromDefault
+ = o3tl::trim(sColumnDef.substr(nDefPos + DEFAULT_KW.size()));
+
+ // next word is the value
+ size_t nNextSpace = fromDefault.find(' ');
+ return (nNextSpace > 0 && nNextSpace != std::u16string_view::npos)
+ ? fromDefault.substr(0, nNextSpace)
+ : fromDefault;
+ }
+ return std::u16string_view();
+}
+
+bool lcl_isNullable(std::u16string_view sColumnDef)
+{
+ return sColumnDef.find(u"NOT NULL") == std::u16string_view::npos;
+}
+
+bool lcl_isPrimaryKey(std::u16string_view sColumnDef)
+{
+ return sColumnDef.find(u"PRIMARY KEY") != std::u16string_view::npos;
+}
+
+sal_Int32 lcl_getDataTypeFromHsql(std::u16string_view sTypeName)
+{
+ if (sTypeName == u"CHAR")
+ return DataType::CHAR;
+ else if (sTypeName == u"VARCHAR" || sTypeName == u"VARCHAR_IGNORECASE")
+ return DataType::VARCHAR;
+ else if (sTypeName == u"TINYINT")
+ return DataType::TINYINT;
+ else if (sTypeName == u"SMALLINT")
+ return DataType::SMALLINT;
+ else if (sTypeName == u"INTEGER")
+ return DataType::INTEGER;
+ else if (sTypeName == u"BIGINT")
+ return DataType::BIGINT;
+ else if (sTypeName == u"NUMERIC")
+ return DataType::NUMERIC;
+ else if (sTypeName == u"DECIMAL")
+ return DataType::DECIMAL;
+ else if (sTypeName == u"BOOLEAN")
+ return DataType::BOOLEAN;
+ else if (sTypeName == u"LONGVARCHAR")
+ return DataType::LONGVARCHAR;
+ else if (sTypeName == u"LONGVARBINARY")
+ return DataType::LONGVARBINARY;
+ else if (sTypeName == u"CLOB")
+ return DataType::CLOB;
+ else if (sTypeName == u"BLOB")
+ return DataType::BLOB;
+ else if (sTypeName == u"BINARY")
+ return DataType::BINARY;
+ else if (sTypeName == u"VARBINARY")
+ return DataType::VARBINARY;
+ else if (sTypeName == u"DATE")
+ return DataType::DATE;
+ else if (sTypeName == u"TIME")
+ return DataType::TIME;
+ else if (sTypeName == u"TIMESTAMP")
+ return DataType::TIMESTAMP;
+ else if (sTypeName == u"DOUBLE")
+ return DataType::DOUBLE;
+ else if (sTypeName == u"REAL")
+ return DataType::REAL;
+ else if (sTypeName == u"FLOAT")
+ return DataType::FLOAT;
+
+ assert(false);
+ return -1;
+}
+
+void lcl_addDefaultParameters(std::vector<sal_Int32>& aParams, sal_Int32 eType)
+{
+ if (eType == DataType::CHAR || eType == DataType::BINARY || eType == DataType::VARBINARY
+ || eType == DataType::VARCHAR)
+ aParams.push_back(8000); // from SQL standard
+}
+
+struct ColumnTypeParts
+{
+ OUString typeName;
+ std::vector<sal_Int32> params;
+};
+
+/**
+ * Separates full type descriptions (e.g. NUMERIC(5,4)) to type name (NUMERIC) and
+ * parameters (5,4)
+ */
+ColumnTypeParts lcl_getColumnTypeParts(std::u16string_view sFullTypeName)
+{
+ ColumnTypeParts parts;
+ auto nParenPos = sFullTypeName.find('(');
+ if (nParenPos > 0 && nParenPos != std::u16string_view::npos)
+ {
+ parts.typeName = o3tl::trim(sFullTypeName.substr(0, nParenPos));
+ std::u16string_view sParamStr
+ = sFullTypeName.substr(nParenPos + 1, sFullTypeName.find(')') - nParenPos - 1);
+ auto sParams = string::split(sParamStr, sal_Unicode(u','));
+ for (const auto& sParam : sParams)
+ {
+ parts.params.push_back(sParam.toInt32());
+ }
+ }
+ else
+ {
+ parts.typeName = o3tl::trim(sFullTypeName);
+ lcl_addDefaultParameters(parts.params, lcl_getDataTypeFromHsql(parts.typeName));
+ }
+ return parts;
+}
+
+} // unnamed namespace
+
+namespace dbahsql
+{
+CreateStmtParser::CreateStmtParser() {}
+
+void CreateStmtParser::parsePrimaryKeys(std::u16string_view sPrimaryPart)
+{
+ size_t nParenPos = sPrimaryPart.find('(');
+ if (nParenPos > 0 && nParenPos != std::u16string_view::npos)
+ {
+ std::u16string_view sParamStr
+ = sPrimaryPart.substr(nParenPos + 1, sPrimaryPart.rfind(')') - nParenPos - 1);
+ auto sParams = string::split(sParamStr, sal_Unicode(u','));
+ for (const auto& sParam : sParams)
+ {
+ m_PrimaryKeys.push_back(sParam);
+ }
+ }
+}
+
+void CreateStmtParser::parseColumnPart(std::u16string_view sColumnPart)
+{
+ auto sColumns = lcl_splitColumnPart(sColumnPart);
+ for (const OUString& sColumn : sColumns)
+ {
+ if (sColumn.startsWithIgnoreAsciiCase("PRIMARY KEY"))
+ {
+ parsePrimaryKeys(sColumn);
+ continue;
+ }
+
+ if (sColumn.startsWithIgnoreAsciiCase("CONSTRAINT"))
+ {
+ m_aForeignParts.push_back(sColumn);
+ continue;
+ }
+
+ bool bIsQuoteUsedForColumnName(sColumn[0] == '\"');
+
+ // find next quote after the initial quote
+ // or next space if quote isn't used as delimiter
+ auto nEndColumnName
+ = bIsQuoteUsedForColumnName ? sColumn.indexOf("\"", 1) + 1 : sColumn.indexOf(" ");
+ OUString rColumnName = sColumn.copy(0, nEndColumnName);
+
+ const OUString sFromTypeName(o3tl::trim(sColumn.subView(nEndColumnName)));
+
+ // Now let's manage the column type
+ // search next space to get the whole type name
+ // eg: INTEGER, VARCHAR(10), DECIMAL(6,3)
+ auto nNextSpace = sFromTypeName.indexOf(" ");
+ std::u16string_view sFullTypeName;
+ if (nNextSpace > 0)
+ sFullTypeName = sFromTypeName.subView(0, nNextSpace);
+ // perhaps column type corresponds to the last info here
+ else
+ sFullTypeName = sFromTypeName;
+
+ ColumnTypeParts typeParts = lcl_getColumnTypeParts(sFullTypeName);
+
+ bool bCaseInsensitive = typeParts.typeName.indexOf("IGNORECASE") >= 0;
+ bool isPrimaryKey = lcl_isPrimaryKey(sColumn);
+
+ if (isPrimaryKey)
+ m_PrimaryKeys.push_back(rColumnName);
+
+ const std::u16string_view sColumnWithoutName
+ = sColumn.subView(sColumn.indexOf(typeParts.typeName));
+
+ ColumnDefinition aColDef(rColumnName, lcl_getDataTypeFromHsql(typeParts.typeName),
+ std::move(typeParts.params), isPrimaryKey,
+ lcl_getAutoIncrementDefault(sColumnWithoutName),
+ lcl_isNullable(sColumnWithoutName), bCaseInsensitive,
+ OUString(lcl_getDefaultValue(sColumnWithoutName)));
+
+ m_aColumns.push_back(aColDef);
+ }
+}
+
+void CreateStmtParser::parse(std::u16string_view sSql)
+{
+ // TODO Foreign keys
+ if (!o3tl::starts_with(sSql, u"CREATE"))
+ {
+ SAL_WARN("dbaccess", "Not a create statement");
+ return;
+ }
+
+ m_sTableName = utils::getTableNameFromStmt(sSql);
+ std::u16string_view sColumnPart = lcl_getColumnPart(sSql);
+ parseColumnPart(sColumnPart);
+}
+
+} // namespace dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/createparser.hxx b/dbaccess/source/filter/hsqldb/createparser.hxx
new file mode 100644
index 000000000..a92f74586
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/createparser.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vector>
+#include "columndef.hxx"
+
+namespace dbahsql
+{
+class SAL_DLLPUBLIC_EXPORT CreateStmtParser
+{
+private:
+ std::vector<ColumnDefinition> m_aColumns;
+ std::vector<OUString> m_aForeignParts;
+ std::vector<OUString> m_PrimaryKeys;
+ OUString m_sTableName;
+
+protected:
+ void parseColumnPart(std::u16string_view sColumnPart);
+ void parsePrimaryKeys(std::u16string_view sPrimaryPart);
+
+public:
+ CreateStmtParser();
+ virtual ~CreateStmtParser() {}
+
+ /**
+ * @return name of the table which is to be created.
+ */
+ OUString const& getTableName() const { return m_sTableName; }
+
+ /**
+ * @return primary keys of parsed table.
+ */
+ std::vector<OUString> const& getPrimaryKeys() const { return m_PrimaryKeys; }
+
+ /**
+ * @return a vector of column descriptors, representing the columns of the
+ * parsed statement.
+ */
+ const std::vector<ColumnDefinition>& getColumnDef() const { return m_aColumns; }
+
+ /**
+ * @return a vector of words.
+ */
+ const std::vector<OUString>& getForeignParts() const { return m_aForeignParts; }
+
+ /**
+ * Parses a create statement.
+ *
+ * @param SQL "CREATE" statement
+ */
+ void parse(std::u16string_view sSql);
+
+ /**
+ * Recreate the sql statement.
+ */
+ virtual OUString compose() const = 0;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/fbalterparser.cxx b/dbaccess/source/filter/hsqldb/fbalterparser.cxx
new file mode 100644
index 000000000..024598c0b
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/fbalterparser.cxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "fbalterparser.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+namespace dbahsql
+{
+OUString FbAlterStmtParser::compose() const
+{
+ if (getActionType() == AlterAction::UNKNOWN)
+ {
+ SAL_WARN("dbaccess", "Unknown type of ALTER statement in FbAlterStmtParser");
+ return OUString{};
+ }
+ else if (getActionType() == AlterAction::ADD_FOREIGN)
+ return getStatement(); // do nothing with that
+ OUStringBuffer sSql("ALTER TABLE ");
+ sSql.append(getTableName());
+
+ if (getActionType() == AlterAction::IDENTITY_RESTART)
+ {
+ sSql.append(" ALTER COLUMN ");
+ }
+ sSql.append(getColumnName());
+ sSql.append(" RESTART WITH ");
+
+ // Firebird: restart with 0 means the first number is 1, not 0.
+ sSql.append(getIdentityParam() - 1);
+
+ return sSql.makeStringAndClear();
+}
+
+} // dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/fbalterparser.hxx b/dbaccess/source/filter/hsqldb/fbalterparser.hxx
new file mode 100644
index 000000000..cd48d94d5
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/fbalterparser.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "alterparser.hxx"
+
+namespace dbahsql
+{
+class FbAlterStmtParser : public AlterStmtParser
+{
+protected:
+ void ensureProperTableLengths() const;
+
+public:
+ /**
+ * Compose the result of the parser to statements of Firebird dialect
+ */
+ virtual OUString compose() const override;
+};
+
+} // dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/fbcreateparser.cxx b/dbaccess/source/filter/hsqldb/fbcreateparser.cxx
new file mode 100644
index 000000000..f3399474c
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/fbcreateparser.cxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "fbcreateparser.hxx"
+#include "columndef.hxx"
+#include "utils.hxx"
+
+#include <com/sun/star/sdbc/DataType.hpp>
+
+#include <rtl/ustrbuf.hxx>
+
+using namespace css::sdbc;
+
+namespace
+{
+void lcl_appendWithSpace(OUStringBuffer& sBuff, std::u16string_view sStr)
+{
+ sBuff.append(" ");
+ sBuff.append(sStr);
+}
+
+OUString lcl_DataTypetoFbTypeName(sal_Int32 eType)
+{
+ switch (eType)
+ {
+ case DataType::CHAR:
+ case DataType::BINARY:
+ return "CHAR";
+ case DataType::VARCHAR:
+ case DataType::VARBINARY:
+ return "VARCHAR";
+ case DataType::TINYINT: // no such type in Firebird
+ case DataType::SMALLINT:
+ return "SMALLINT";
+ case DataType::INTEGER:
+ return "INTEGER";
+ case DataType::BIGINT:
+ return "BIGINT";
+ case DataType::NUMERIC:
+ return "NUMERIC";
+ case DataType::DECIMAL:
+ return "DECIMAL";
+ case DataType::BOOLEAN:
+ return "BOOLEAN";
+ case DataType::LONGVARCHAR:
+ case DataType::LONGVARBINARY:
+ case DataType::CLOB:
+ case DataType::BLOB:
+ case DataType::OTHER:
+ return "BLOB";
+ case DataType::DATE:
+ return "DATE";
+ case DataType::TIME:
+ return "TIME";
+ case DataType::TIMESTAMP:
+ return "TIMESTAMP";
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ return "DOUBLE PRECISION";
+ case DataType::FLOAT:
+ return "FLOAT";
+ default:
+ assert(false);
+ return OUString();
+ }
+}
+
+OUString lcl_getTypeModifier(sal_Int32 eType)
+{
+ // TODO bind -9546 magic number to a common definition. It also appears
+ // in the connectivity module.
+ switch (eType)
+ {
+ case DataType::CLOB:
+ case DataType::LONGVARCHAR:
+ return "SUB_TYPE 1";
+ case DataType::LONGVARBINARY:
+ return "SUB_TYPE -9546";
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ return "CHARACTER SET OCTETS";
+ default:
+ return OUString();
+ }
+}
+
+} // unnamed namespace
+
+namespace dbahsql
+{
+void FbCreateStmtParser::appendPrimaryKeyPart(OUStringBuffer& rSql) const
+{
+ const std::vector<OUString>& sPrimaryKeys = getPrimaryKeys();
+ if (sPrimaryKeys.empty())
+ return; // no primary key specified
+
+ rSql.append(",");
+ rSql.append("PRIMARY KEY(");
+ auto it = sPrimaryKeys.cbegin();
+ while (it != sPrimaryKeys.end())
+ {
+ rSql.append(*it);
+ ++it;
+ if (it != sPrimaryKeys.end())
+ rSql.append(",");
+ }
+
+ rSql.append(")"); // end of primary key declaration
+}
+
+void FbCreateStmtParser::ensureProperTableLengths() const
+{
+ const std::vector<ColumnDefinition>& rColumns = getColumnDef();
+ for (const auto& col : rColumns)
+ utils::ensureFirebirdTableLength(col.getName());
+}
+
+OUString FbCreateStmtParser::compose() const
+{
+ ensureProperTableLengths();
+ OUStringBuffer sSql(128);
+ sSql.append("CREATE TABLE ");
+ sSql.append(getTableName());
+
+ lcl_appendWithSpace(sSql, u"("); // column declaration
+ auto& rColumns = getColumnDef();
+ auto columnIter = rColumns.cbegin();
+ while (columnIter != rColumns.end())
+ {
+ lcl_appendWithSpace(sSql, columnIter->getName());
+ lcl_appendWithSpace(sSql, lcl_DataTypetoFbTypeName(columnIter->getDataType()));
+
+ std::vector<sal_Int32> params{ columnIter->getParams() };
+
+ if (columnIter->getDataType() == DataType::NUMERIC
+ || columnIter->getDataType() == DataType::DECIMAL)
+ {
+ // max precision is 18 here
+ if (params.at(0) > 18)
+ params[0] = 18;
+ }
+
+ // Firebird SQL dialect does not like parameters for TIMESTAMP
+ if (!params.empty() && columnIter->getDataType() != DataType::TIMESTAMP)
+ {
+ sSql.append("(");
+ auto it = params.cbegin();
+ while (it != params.end())
+ {
+ sSql.append(*it);
+ ++it;
+ if (it != params.end())
+ sSql.append(",");
+ }
+ sSql.append(")"); // end of param declaration
+ }
+
+ // special modifiers here, based on type (e.g. charset, subtype)
+ OUString sModifier = lcl_getTypeModifier(columnIter->getDataType());
+ if (!sModifier.isEmpty())
+ lcl_appendWithSpace(sSql, sModifier);
+
+ if (columnIter->isAutoIncremental())
+ {
+ lcl_appendWithSpace(sSql, u"GENERATED BY DEFAULT AS IDENTITY (START WITH ");
+
+ // start with 0:
+ // HSQLDB: first value will be 0.
+ // Firebird: first value will be 1.
+ sSql.append(columnIter->getStartValue() - 1);
+ sSql.append(")");
+ }
+ else if (!columnIter->isNullable())
+ lcl_appendWithSpace(sSql, u"NOT NULL");
+
+ if (columnIter->isCaseInsensitive())
+ lcl_appendWithSpace(sSql, u"COLLATE UNICODE_CI");
+
+ const OUString& sDefaultVal = columnIter->getDefault();
+ if (!sDefaultVal.isEmpty())
+ {
+ lcl_appendWithSpace(sSql, u"DEFAULT");
+ if (sDefaultVal.equalsIgnoreAsciiCase("NOW"))
+ lcl_appendWithSpace(sSql, u"\'NOW\'"); // Fb likes it single quoted
+ else
+ lcl_appendWithSpace(sSql, sDefaultVal);
+ }
+
+ ++columnIter;
+ if (columnIter != rColumns.end())
+ sSql.append(",");
+ }
+
+ appendPrimaryKeyPart(sSql);
+
+ sSql.append(")"); // end of column declaration
+ return sSql.makeStringAndClear();
+}
+
+} // dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/fbcreateparser.hxx b/dbaccess/source/filter/hsqldb/fbcreateparser.hxx
new file mode 100644
index 000000000..6706c05be
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/fbcreateparser.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "createparser.hxx"
+
+namespace dbahsql
+{
+class SAL_DLLPUBLIC_EXPORT FbCreateStmtParser : public CreateStmtParser
+{
+protected:
+ void ensureProperTableLengths() const;
+ void appendPrimaryKeyPart(rtl::OUStringBuffer& rSql) const;
+
+public:
+ /**
+ * Create statement parser, which can compose the result to statements of
+ * Firebird dialect.
+ */
+ FbCreateStmtParser() = default;
+
+ /**
+ * Compose the result of the parser to statements of Firebird dialect
+ */
+ virtual OUString compose() const override;
+};
+
+} // dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx b/dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx
new file mode 100644
index 000000000..c02da2c4b
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "hsqlbinarynode.hxx"
+#include "rowinputbinary.hxx"
+
+namespace dbahsql
+{
+HsqlBinaryNode::HsqlBinaryNode(sal_Int32 nPos)
+ : m_nPos(nPos)
+{
+}
+
+void HsqlBinaryNode::readChildren(HsqlRowInputStream const& input)
+{
+ SvStream* pStream = input.getInputStream();
+ if (!pStream)
+ return;
+
+ pStream->Seek(m_nPos + 8); // skip size and balance
+ pStream->ReadInt32(m_nLeft);
+ if (m_nLeft <= 0)
+ m_nLeft = -1;
+ pStream->ReadInt32(m_nRight);
+ if (m_nRight <= 0)
+ m_nRight = -1;
+}
+
+std::vector<css::uno::Any> HsqlBinaryNode::readRow(HsqlRowInputStream& input,
+ const std::vector<ColumnDefinition>& aColTypes,
+ sal_Int32 nIndexCount)
+{
+ // skip first 4 bytes (size), and index nodes, 16 bytes each
+ input.seek(m_nPos + 4 + nIndexCount * 16);
+ return input.readOneRow(aColTypes);
+}
+
+sal_Int32 HsqlBinaryNode::getLeft() const { return m_nLeft; }
+sal_Int32 HsqlBinaryNode::getRight() const { return m_nRight; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/hsqlbinarynode.hxx b/dbaccess/source/filter/hsqldb/hsqlbinarynode.hxx
new file mode 100644
index 000000000..97777e7d1
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/hsqlbinarynode.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include "rowinputbinary.hxx"
+#include "columndef.hxx"
+
+namespace dbahsql
+{
+class HsqlBinaryNode
+{
+private:
+ sal_Int32 m_nLeft = -1;
+ sal_Int32 m_nRight = -1;
+ sal_Int32 m_nPos = -1;
+
+public:
+ /**
+ * Represents one element of an AVL tree in the binary file which contains
+ * the data.
+ */
+ HsqlBinaryNode(sal_Int32 nPos);
+
+ /**
+ * Read position of children from data file.
+ *
+ * @param rInput input stream where the positions should be read from.
+ */
+ void readChildren(HsqlRowInputStream const& rInput);
+
+ /**
+ * Get Position of left children. It should be called only after position of
+ * children is read.
+ */
+ sal_Int32 getLeft() const;
+
+ /**
+ * Get Position of right children. It should be called only after position of
+ * children is read.
+ */
+ sal_Int32 getRight() const;
+
+ /**
+ * Read the row represented by this node.
+ *
+ * @param rInput input stream where the row should be read from.
+ */
+ std::vector<css::uno::Any> readRow(HsqlRowInputStream& rInput,
+ const std::vector<ColumnDefinition>& aColTypes,
+ sal_Int32 nIndexCount);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/hsqlimport.cxx b/dbaccess/source/filter/hsqldb/hsqlimport.cxx
new file mode 100644
index 000000000..045a32f93
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/hsqlimport.cxx
@@ -0,0 +1,388 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/util/Date.hpp>
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <vcl/weld.hxx>
+
+#include "hsqlimport.hxx"
+#include "parseschema.hxx"
+#include "rowinputbinary.hxx"
+
+namespace
+{
+using namespace css::io;
+using namespace css::uno;
+using namespace css::sdbc;
+
+void lcl_setParams(const std::vector<Any>& row, Reference<XParameters> const& xParam,
+ const std::vector<dbahsql::ColumnDefinition>& rColTypes)
+{
+ assert(row.size() == rColTypes.size());
+ size_t nColIndex = 0;
+ for (size_t i = 0; i < rColTypes.size(); ++i)
+ {
+ if (!row.at(i).hasValue())
+ xParam->setNull(i + 1, rColTypes.at(i).getDataType());
+
+ switch (rColTypes.at(i).getDataType())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ OUString sVal;
+ if (row.at(i) >>= sVal)
+ {
+ xParam->setString(nColIndex + 1, sVal);
+ }
+ }
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ {
+ sal_Int16 nVal;
+ if (row.at(i) >>= nVal)
+ {
+ xParam->setShort(nColIndex + 1, nVal);
+ }
+ }
+ break;
+ case DataType::INTEGER:
+ {
+ sal_Int32 nVal;
+ if (row.at(i) >>= nVal)
+ {
+ xParam->setInt(nColIndex + 1, nVal);
+ }
+ }
+ break;
+ case DataType::BIGINT:
+ {
+ sal_Int64 nVal;
+ if (row.at(i) >>= nVal)
+ {
+ xParam->setLong(nColIndex + 1, nVal);
+ }
+ }
+ break;
+ case DataType::REAL:
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ {
+ double nVal;
+ if (row.at(i) >>= nVal)
+ {
+ xParam->setDouble(nColIndex + 1, nVal);
+ }
+ }
+ break;
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ {
+ Sequence<Any> aNumeric;
+ if (row.at(i) >>= aNumeric)
+ {
+ sal_Int32 nScale = 0;
+ if (aNumeric[1] >>= nScale)
+ xParam->setObjectWithInfo(nColIndex + 1, aNumeric[0],
+ rColTypes.at(i).getDataType(), nScale);
+ }
+ }
+ break;
+ case DataType::DATE:
+ {
+ css::util::Date date;
+ if (row.at(i) >>= date)
+ {
+ xParam->setDate(nColIndex + 1, date);
+ }
+ }
+ break;
+ case DataType::TIME:
+ {
+ css::util::Time time;
+ if (row.at(i) >>= time)
+ {
+ xParam->setTime(nColIndex + 1, time);
+ }
+ }
+ break;
+ case DataType::TIMESTAMP:
+ {
+ css::util::DateTime dateTime;
+ if (row.at(i) >>= dateTime)
+ {
+ xParam->setTimestamp(nColIndex + 1, dateTime);
+ }
+ }
+ break;
+ case DataType::BOOLEAN:
+ {
+ bool bVal = false;
+ if (row.at(i) >>= bVal)
+ xParam->setBoolean(nColIndex + 1, bVal);
+ }
+ break;
+ case DataType::OTHER:
+ // TODO
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ {
+ Sequence<sal_Int8> nVal;
+ if (row.at(i) >>= nVal)
+ {
+ xParam->setBytes(nColIndex + 1, nVal);
+ }
+ break;
+ }
+ default:
+ throw WrongFormatException();
+ }
+ ++nColIndex;
+ }
+}
+
+OUString lcl_createInsertStatement(std::u16string_view sTableName,
+ const std::vector<dbahsql::ColumnDefinition>& rColTypes)
+{
+ assert(rColTypes.size() > 0);
+ OUStringBuffer sql("INSERT INTO ");
+ sql.append(sTableName);
+ sql.append(" (");
+
+ // column names
+ for (size_t i = 0; i < rColTypes.size(); ++i)
+ {
+ sql.append(rColTypes.at(i).getName());
+ if (i < rColTypes.size() - 1)
+ sql.append(", ");
+ }
+ sql.append(")");
+
+ sql.append(" VALUES (");
+ for (size_t i = 0; i < rColTypes.size(); ++i)
+ {
+ sql.append("?");
+ if (i < rColTypes.size() - 1)
+ sql.append(", ");
+ }
+ sql.append(")");
+ return sql.makeStringAndClear();
+}
+
+} // unnamed namespace
+
+namespace dbahsql
+{
+using namespace css::embed;
+
+HsqlImporter::HsqlImporter(Reference<XConnection>& rConnection, const Reference<XStorage>& rStorage)
+ : m_rConnection(rConnection)
+{
+ m_xStorage.set(rStorage);
+}
+
+void HsqlImporter::insertRow(const std::vector<css::uno::Any>& xRows,
+ std::u16string_view sTableName,
+ const std::vector<ColumnDefinition>& rColTypes)
+{
+ OUString sStatement = lcl_createInsertStatement(sTableName, rColTypes);
+ Reference<XPreparedStatement> xStatement = m_rConnection->prepareStatement(sStatement);
+
+ Reference<XParameters> xParameter(xStatement, UNO_QUERY);
+ assert(xParameter.is());
+ xParameter->clearParameters();
+
+ lcl_setParams(xRows, xParameter, rColTypes);
+ xStatement->executeQuery();
+}
+
+void HsqlImporter::processTree(HsqlBinaryNode& rNode, HsqlRowInputStream& rStream,
+ const std::vector<ColumnDefinition>& rColTypes,
+ const OUString& sTableName, sal_Int32 nIndexCount)
+{
+ rNode.readChildren(rStream);
+ sal_Int32 nNext = rNode.getLeft();
+ if (nNext > 0)
+ {
+ HsqlBinaryNode aLeft{ nNext };
+ processTree(aLeft, rStream, rColTypes, sTableName, nIndexCount);
+ }
+ std::vector<Any> row = rNode.readRow(rStream, rColTypes, nIndexCount);
+ insertRow(row, sTableName, rColTypes);
+
+ nNext = rNode.getRight();
+ if (nNext > 0)
+ {
+ HsqlBinaryNode aRight{ nNext };
+ processTree(aRight, rStream, rColTypes, sTableName, nIndexCount);
+ }
+}
+
+/**
+ * Format from the indexed file position is the following:
+ * <Node x20><Row>
+ * Where Node is a 20 byte data, representing the rows in a binary tree:
+ * <Size x4><Balance x4><Left x4> <Right x4><Parent x4>
+ *
+ * Size is the size of <Row>;
+ * Balance: ?
+ * Left/Right/Parent: File position of the Left/Right/Parent child
+ */
+void HsqlImporter::parseTableRows(const std::vector<sal_Int32>& rIndexes,
+ const std::vector<ColumnDefinition>& rColTypes,
+ const OUString& sTableName)
+{
+ static constexpr OUStringLiteral BINARY_FILENAME = u"data";
+
+ if (!m_xStorage->hasByName(BINARY_FILENAME))
+ {
+ SAL_WARN("dbaccess", "data file does not exist in storage during hsqldb import");
+ assert(false); // TODO throw error
+ }
+
+ Reference<css::io::XStream> xStream(
+ m_xStorage->openStreamElement(BINARY_FILENAME, ElementModes::READ));
+
+ HsqlRowInputStream rowInput;
+ Reference<XInputStream> xInput = xStream->getInputStream();
+ rowInput.setInputStream(xInput);
+
+ if (!rIndexes.empty())
+ {
+ HsqlBinaryNode aPrimaryNode{ rIndexes.at(0) };
+ processTree(aPrimaryNode, rowInput, rColTypes, sTableName, rIndexes.size());
+ }
+
+ xInput->closeInput();
+}
+
+void HsqlImporter::importHsqlDatabase(weld::Window* pParent)
+{
+ assert(m_xStorage);
+
+ SchemaParser parser(m_xStorage);
+ std::unique_ptr<SQLException> pException;
+ try
+ {
+ parser.parseSchema();
+ }
+ catch (SQLException& ex)
+ {
+ pException.reset(new SQLException{ std::move(ex) });
+ }
+
+ auto statements = parser.getCreateStatements();
+
+ if (statements.empty() && !pException)
+ {
+ SAL_WARN("dbaccess", "dbashql: there is nothing to import");
+ return; // there is nothing to import
+ }
+
+ // schema
+ for (const auto& sSql : statements)
+ {
+ Reference<XStatement> statement = m_rConnection->createStatement();
+ try
+ {
+ statement->executeQuery(sSql);
+ }
+ catch (SQLException& ex)
+ {
+ // chain errors and keep going
+ if (pException)
+ ex.NextException <<= *pException;
+ pException.reset(new SQLException{ std::move(ex) });
+ }
+ }
+
+ // data
+ for (const auto& tableIndex : parser.getTableIndexes())
+ {
+ try
+ {
+ std::vector<ColumnDefinition> aColTypes = parser.getTableColumnTypes(tableIndex.first);
+ parseTableRows(tableIndex.second, aColTypes, tableIndex.first);
+ }
+ catch (const std::out_of_range& e)
+ {
+ std::unique_ptr<SQLException> ex(new SQLException);
+ const char* msg = e.what();
+ ex->SQLState = OUString(msg, strlen(msg), RTL_TEXTENCODING_ASCII_US);
+ // chain errors and keep going
+ if (pException)
+ ex->NextException <<= *pException;
+ pException = std::move(ex);
+ }
+ catch (SQLException& ex)
+ {
+ // chain errors and keep going
+ if (pException)
+ ex.NextException <<= *pException;
+ pException.reset(new SQLException{ std::move(ex) });
+ }
+ }
+
+ // alter stmts
+ for (const auto& sSql : parser.getAlterStatements())
+ {
+ Reference<XStatement> statement = m_rConnection->createStatement();
+ try
+ {
+ statement->executeQuery(sSql);
+ }
+ catch (SQLException& ex)
+ {
+ // chain errors and keep going
+ if (pException)
+ ex.NextException <<= *pException;
+ pException.reset(new SQLException{ std::move(ex) });
+ }
+ }
+
+ if (pException)
+ {
+ SAL_WARN("dbaccess", "Error during migration");
+ dbtools::showError(dbtools::SQLExceptionInfo{ *pException },
+ pParent ? pParent->GetXWindow() : nullptr,
+ ::comphelper::getProcessComponentContext());
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/hsqlimport.hxx b/dbaccess/source/filter/hsqldb/hsqlimport.hxx
new file mode 100644
index 000000000..7bab53c24
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/hsqlimport.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include "rowinputbinary.hxx"
+#include "hsqlbinarynode.hxx"
+#include "columndef.hxx"
+
+namespace weld
+{
+class Window;
+}
+
+namespace dbahsql
+{
+class SAL_DLLPUBLIC_EXPORT HsqlImporter
+{
+private:
+ css::uno::Reference<css::sdbc::XConnection>& m_rConnection;
+ css::uno::Reference<css::embed::XStorage> m_xStorage;
+
+protected:
+ void insertRow(const std::vector<css::uno::Any>& xRows, std::u16string_view sTable,
+ const std::vector<ColumnDefinition>& rColTypes);
+ void processTree(HsqlBinaryNode& rNode, HsqlRowInputStream& rStream,
+ const std::vector<ColumnDefinition>& rColTypes, const OUString& sTableName,
+ sal_Int32 nIndexCount);
+ void parseTableRows(const std::vector<sal_Int32>& rIndexes,
+ const std::vector<ColumnDefinition>& rColTypes, const OUString& sTableName);
+
+public:
+ /**
+ * @param rConnection reference to an sdbc connection. The migration will
+ * perform to this connection.
+ *
+ * @param rStorage Storage where the HSQL database can be found. The schema
+ * definition should be in file "script" in form of DDL SQL statements. The
+ * data should be found in file "data". These are HSQLDB's own format.
+ */
+ HsqlImporter(css::uno::Reference<css::sdbc::XConnection>& rConnection,
+ const css::uno::Reference<css::embed::XStorage>& rStorage);
+
+ /**
+ * Migrate a HSQL database to another.
+ */
+ void importHsqlDatabase(weld::Window* pParent);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/parseschema.cxx b/dbaccess/source/filter/hsqldb/parseschema.cxx
new file mode 100644
index 000000000..b55340f2d
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/parseschema.cxx
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "parseschema.hxx"
+#include "fbcreateparser.hxx"
+#include "fbalterparser.hxx"
+#include "utils.hxx"
+
+#include <com/sun/star/io/TextInputStream.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <sal/log.hxx>
+#include <connectivity/dbexception.hxx>
+
+namespace
+{
+using namespace ::comphelper;
+
+using IndexVector = std::vector<sal_Int32>;
+
+class IndexStmtParser
+{
+private:
+ OUString m_sql;
+
+public:
+ IndexStmtParser(const OUString& sSql)
+ : m_sql(sSql)
+ {
+ }
+
+ bool isIndexStatement() const
+ {
+ return m_sql.startsWith("SET TABLE") && m_sql.indexOf("INDEX") >= 0;
+ }
+
+ IndexVector getIndexes() const
+ {
+ assert(isIndexStatement());
+
+ std::u16string_view sIndexPart = m_sql.subView(m_sql.indexOf("INDEX") + 5);
+ size_t nQuotePos = sIndexPart.find('\'');
+ if (nQuotePos == std::u16string_view::npos)
+ nQuotePos = 0;
+ else
+ ++nQuotePos;
+ std::u16string_view sIndexNums
+ = sIndexPart.substr(nQuotePos, sIndexPart.rfind('\'') - nQuotePos);
+
+ std::vector<OUString> sIndexes = string::split(sIndexNums, u' ');
+ IndexVector indexes;
+ for (const auto& sIndex : sIndexes)
+ indexes.push_back(sIndex.toInt32());
+
+ // ignore last element
+ // TODO this is an identity peek, which indicates the value of the next
+ // identity. At the current state all migrated identities start with 0.
+ indexes.pop_back();
+
+ return indexes;
+ }
+
+ OUString getTableName() const
+ {
+ // SET TABLE <tableName> or SET TABLE "<multi word table name>"
+ OUString sName = string::split(m_sql, u' ')[2];
+ if (sName.indexOf('"') >= 0)
+ {
+ // Table name with string delimiter
+ sName = "\"" + string::split(m_sql, u'"')[1] + "\"";
+ }
+ return sName;
+ }
+};
+
+OUString lcl_createAlterForeign(std::u16string_view sForeignPart, std::u16string_view sTableName)
+{
+ return OUString::Concat("ALTER TABLE ") + sTableName + " ADD " + sForeignPart;
+}
+
+} // anonymous namespace
+
+namespace dbahsql
+{
+using namespace css::io;
+using namespace css::uno;
+using namespace css::embed;
+
+SchemaParser::SchemaParser(Reference<XStorage>& rStorage)
+ : m_rStorage(rStorage)
+{
+}
+
+void SchemaParser::parseSchema()
+{
+ assert(m_rStorage);
+
+ static constexpr OUStringLiteral SCHEMA_FILENAME = u"script";
+ if (!m_rStorage->hasByName(SCHEMA_FILENAME))
+ {
+ SAL_WARN("dbaccess", "script file does not exist in storage during hsqldb import");
+ return;
+ }
+
+ Reference<XStream> xStream(m_rStorage->openStreamElement(SCHEMA_FILENAME, ElementModes::READ));
+
+ Reference<XComponentContext> rContext = comphelper::getProcessComponentContext();
+ Reference<XTextInputStream2> xTextInput = TextInputStream::create(rContext);
+ xTextInput->setEncoding("UTF-8");
+ xTextInput->setInputStream(xStream->getInputStream());
+
+ while (!xTextInput->isEOF())
+ {
+ // every line contains exactly one DDL statement
+ OUString sSql = utils::convertToUTF8(
+ OUStringToOString(xTextInput->readLine(), RTL_TEXTENCODING_UTF8));
+
+ IndexStmtParser indexParser{ sSql };
+ if (indexParser.isIndexStatement())
+ {
+ m_Indexes[indexParser.getTableName()] = indexParser.getIndexes();
+ }
+ else if (sSql.startsWith("SET") || sSql.startsWith("CREATE USER")
+ || sSql.startsWith("CREATE SCHEMA") || sSql.startsWith("GRANT"))
+ continue;
+ else if (sSql.startsWith("CREATE CACHED TABLE") || sSql.startsWith("CREATE TABLE"))
+ {
+ FbCreateStmtParser aCreateParser;
+ aCreateParser.parse(sSql);
+
+ for (const auto& foreignParts : aCreateParser.getForeignParts())
+ {
+ m_sAlterStatements.push_back(
+ lcl_createAlterForeign(foreignParts, aCreateParser.getTableName()));
+ }
+
+ sSql = aCreateParser.compose();
+
+ // save column definitions
+ m_ColumnTypes[aCreateParser.getTableName()] = aCreateParser.getColumnDef();
+
+ m_sCreateStatements.push_back(sSql);
+ }
+ else if (sSql.startsWith("ALTER"))
+ {
+ FbAlterStmtParser aAlterParser;
+ aAlterParser.parse(sSql);
+ OUString parsedStmt = aAlterParser.compose();
+
+ if (!parsedStmt.isEmpty())
+ m_sAlterStatements.push_back(parsedStmt);
+ }
+ else if (sSql.startsWith("CREATE VIEW"))
+ m_sCreateStatements.push_back(sSql);
+ }
+}
+
+std::vector<ColumnDefinition> SchemaParser::getTableColumnTypes(const OUString& sTableName) const
+{
+ if (m_ColumnTypes.count(sTableName) < 1)
+ {
+ static constexpr OUStringLiteral NOT_EXIST
+ = u"Internal error while getting column information of table";
+ SAL_WARN("dbaccess", NOT_EXIST << ". Table name is: " << sTableName);
+ dbtools::throwGenericSQLException(NOT_EXIST, ::comphelper::getProcessComponentContext());
+ }
+ return m_ColumnTypes.at(sTableName);
+}
+
+const std::map<OUString, std::vector<sal_Int32>>& SchemaParser::getTableIndexes() const
+{
+ return m_Indexes;
+}
+
+const std::map<OUString, std::vector<OUString>>& SchemaParser::getPrimaryKeys() const
+{
+ return m_PrimaryKeys;
+}
+
+} // namespace dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/parseschema.hxx b/dbaccess/source/filter/hsqldb/parseschema.hxx
new file mode 100644
index 000000000..04a8e0905
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/parseschema.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <vector>
+#include <map>
+
+#include "columndef.hxx"
+
+namespace dbahsql
+{
+using SqlStatementVector = std::vector<OUString>;
+
+class SchemaParser
+{
+private:
+ css::uno::Reference<css::embed::XStorage>& m_rStorage;
+
+ // column type for each table. It is filled after parsing schema.
+ std::map<OUString, std::vector<ColumnDefinition>> m_ColumnTypes;
+
+ // root element's position of data for each table
+ std::map<OUString, std::vector<sal_Int32>> m_Indexes;
+
+ // primary keys of each table
+ std::map<OUString, std::vector<OUString>> m_PrimaryKeys;
+
+ SqlStatementVector m_sCreateStatements;
+ SqlStatementVector m_sAlterStatements;
+
+public:
+ explicit SchemaParser(css::uno::Reference<css::embed::XStorage>& rStorage);
+
+ /**
+ * Parses table definitions contained by a file called "script" in storage.
+ */
+ void parseSchema();
+
+ /**
+ * @return A vector of schema definition SQL strings in Firebird dialect.
+ */
+ const SqlStatementVector& getCreateStatements() const { return m_sCreateStatements; }
+
+ /**
+ * @return A vector of alter SQL strings in Firebird dialect.
+ */
+ const SqlStatementVector& getAlterStatements() const { return m_sAlterStatements; }
+
+ /**
+ * Returns the column types of a table. It should not be called before
+ * calling parseSchema().
+ *
+ * @param sTableName name of the table.
+ *
+ * @return A vector of column descriptors.
+ */
+ std::vector<ColumnDefinition> getTableColumnTypes(const OUString& sTableName) const;
+
+ /**
+ * Returns a vector of indexes for each table. These indexes are used for
+ * locating the data related to the actual table in the binary file.
+ *
+ * The indexes point to root elements of AVL trees. Each node of the tree
+ * contains one row.
+ */
+ const std::map<OUString, std::vector<sal_Int32>>& getTableIndexes() const;
+
+ /**
+ * Returns a vector of column names for each table. These columns are the
+ * primary keys of the table.
+ */
+ const std::map<OUString, std::vector<OUString>>& getPrimaryKeys() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/rowinputbinary.cxx b/dbaccess/source/filter/hsqldb/rowinputbinary.cxx
new file mode 100644
index 000000000..95ce05f69
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/rowinputbinary.cxx
@@ -0,0 +1,399 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "rowinputbinary.hxx"
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <tools/stream.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+namespace
+{
+/**
+ * Converts binary represented big integer value to BCD (Binary Coded
+ * Decimal), and returns a string representation of the number.
+ *
+ * Bytes[0] is the most significant part of the number.
+ */
+OUString lcl_double_dabble(const std::vector<sal_uInt8>& bytes)
+{
+ size_t nbits = 8 * bytes.size(); // length of array in bits
+ size_t nscratch = nbits / 2; // length of scratch in bytes
+ std::vector<char> scratch(nscratch, 0);
+
+ for (size_t i = 0; i < bytes.size(); ++i)
+ {
+ for (size_t j = 0; j < 8; ++j)
+ {
+ /* This bit will be shifted in on the right. */
+ int shifted_in = (bytes[i] & (1 << (7 - j))) ? 1 : 0;
+
+ /* Add 3 everywhere that scratch[k] >= 5. */
+ for (size_t k = 0; k < nscratch; ++k)
+ scratch[k] += (scratch[k] >= 5) ? 3 : 0;
+
+ /* Shift scratch to the left by one position. */
+ for (size_t k = 0; k < nscratch - 1; ++k)
+ {
+ scratch[k] <<= 1;
+ scratch[k] &= 0xF;
+ scratch[k] |= (scratch[k + 1] >= 8) ? 1 : 0;
+ }
+
+ /* Shift in the new bit from arr. */
+ scratch[nscratch - 1] <<= 1;
+ scratch[nscratch - 1] &= 0xF;
+ scratch[nscratch - 1] |= shifted_in;
+ }
+ }
+
+ auto it = scratch.begin();
+ /* Remove leading zeros from the scratch space. */
+ while (*it == 0 && scratch.size() > 1)
+ {
+ it = scratch.erase(it);
+ }
+
+ /* Convert the scratch space from BCD digits to ASCII. */
+ for (auto& digit : scratch)
+ digit += '0';
+
+ /* Resize and return the resulting string. */
+ return OStringToOUString(std::string_view(scratch.data(), scratch.size()),
+ RTL_TEXTENCODING_UTF8);
+}
+
+OUString lcl_makeStringFromBigint(std::vector<sal_uInt8>&& aBytes)
+{
+ OUStringBuffer sRet;
+
+ // two's complement
+ if ((aBytes[0] & 0x80) != 0)
+ {
+ sRet.append("-");
+ for (auto& byte : aBytes)
+ byte = ~byte;
+ // add 1 to byte array
+ // FIXME e.g. 10000 valid ?
+ for (size_t i = aBytes.size() - 1; i != 0; --i)
+ {
+ aBytes[i] += 1;
+ if (aBytes[i] != 0)
+ break;
+ }
+ }
+ // convert binary to BCD
+ OUString sNum = lcl_double_dabble(aBytes);
+ sRet.append(sNum);
+ return sRet.makeStringAndClear();
+}
+
+OUString lcl_putDot(const OUString& sNum, sal_Int32 nScale)
+{
+ // e.g. sNum = "0", nScale = 2 -> "0.00"
+ OUStringBuffer sBuf{ sNum };
+ sal_Int32 nNullsToAppend = nScale - sNum.getLength() + 1;
+ for (sal_Int32 i = 0; i < nNullsToAppend; ++i)
+ sBuf.insert(0, "0");
+
+ if (nScale > 0)
+ sBuf.insert(sBuf.getLength() - 1 - nScale, ".");
+ return sBuf.makeStringAndClear();
+}
+}
+
+namespace dbahsql
+{
+using namespace css::uno;
+using namespace css::sdbc;
+using namespace css::io;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+HsqlRowInputStream::HsqlRowInputStream() {}
+
+void HsqlRowInputStream::setInputStream(Reference<XInputStream> const& rStream)
+{
+ m_pStream = utl::UcbStreamHelper::CreateStream(rStream, true);
+ m_pStream->SetEndian(SvStreamEndian::BIG);
+}
+
+SvStream* HsqlRowInputStream::getInputStream() const { return m_pStream.get(); }
+
+void HsqlRowInputStream::seek(sal_Int32 nPos) { m_pStream->Seek(nPos); }
+
+OUString HsqlRowInputStream::readString()
+{
+ sal_Int32 nLen = 0;
+ m_pStream->ReadInt32(nLen);
+ return readUTF(nLen);
+}
+
+OUString HsqlRowInputStream::readUTF(sal_Int32 nUTFLen)
+{
+ Sequence<sal_Unicode> aBuffer(nUTFLen);
+ sal_Unicode* pStr = aBuffer.getArray();
+
+ sal_Int32 nCount = 0;
+ sal_Int32 nStrLen = 0;
+ while (nCount < nUTFLen)
+ {
+ sal_uInt8 c = 0;
+ m_pStream->ReadUChar(c);
+ sal_uInt8 char2, char3;
+ switch (c >> 4)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ // 0xxxxxxx
+ nCount++;
+ pStr[nStrLen++] = c;
+ break;
+
+ case 12:
+ case 13:
+ // 110x xxxx 10xx xxxx
+ nCount += 2;
+ if (nCount > nUTFLen)
+ {
+ throw WrongFormatException();
+ }
+
+ m_pStream->ReadUChar(char2);
+ if ((char2 & 0xC0) != 0x80)
+ {
+ throw WrongFormatException();
+ }
+
+ pStr[nStrLen++] = (sal_Unicode(c & 0x1F) << 6) | (char2 & 0x3F);
+ break;
+
+ case 14:
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ nCount += 3;
+ if (nCount > nUTFLen)
+ {
+ throw WrongFormatException();
+ }
+
+ m_pStream->ReadUChar(char2);
+ m_pStream->ReadUChar(char3);
+
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ {
+ throw WrongFormatException();
+ }
+ pStr[nStrLen++] = (sal_Unicode(c & 0x0F) << 12) | (sal_Unicode(char2 & 0x3F) << 6)
+ | (char3 & 0x3F);
+ break;
+
+ default:
+ // 10xx xxxx, 1111 xxxx
+ throw WrongFormatException();
+ }
+ }
+ return OUString(pStr, nStrLen);
+}
+
+bool HsqlRowInputStream::checkNull()
+{
+ sal_uInt8 nNull = 0;
+ m_pStream->ReadUChar(nNull);
+ return nNull == 0;
+}
+
+std::vector<Any> HsqlRowInputStream::readOneRow(const std::vector<ColumnDefinition>& nColTypes)
+{
+ auto nLen = nColTypes.size();
+ std::vector<Any> aData;
+
+ for (size_t i = 0; i < nLen; ++i)
+ {
+ if (checkNull())
+ {
+ aData.push_back(Any());
+ continue;
+ }
+
+ sal_Int32 nType = nColTypes[i].getDataType();
+
+ // TODO throw error on EoF
+
+ switch (nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aData.push_back(Any(readString()));
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ {
+ sal_Int16 value = 0;
+ m_pStream->ReadInt16(value);
+ aData.push_back(Any(value));
+ }
+ break;
+ case DataType::INTEGER:
+ {
+ sal_Int32 value = 0;
+ m_pStream->ReadInt32(value);
+ aData.push_back(Any(value));
+ }
+ break;
+ case DataType::BIGINT:
+ {
+ sal_Int64 value = 0;
+ m_pStream->ReadInt64(value);
+ aData.push_back(Any(value));
+ }
+ break;
+ case DataType::REAL:
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ {
+ double value = 0;
+ m_pStream->ReadDouble(value);
+ // FIXME double is not necessarily 4 bytes
+ aData.push_back(Any(value));
+ }
+ break;
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ {
+ sal_Int32 nSize = 0;
+ m_pStream->ReadInt32(nSize);
+
+ std::vector<sal_uInt8> aBytes(nSize);
+ m_pStream->ReadBytes(aBytes.data(), nSize);
+ assert(aBytes.size() > 0);
+
+ sal_Int32 nScale = 0;
+ m_pStream->ReadInt32(nScale);
+
+ OUString sNum = lcl_makeStringFromBigint(std::move(aBytes));
+ Sequence<Any> result{ Any(lcl_putDot(sNum, nScale)), Any(nScale) };
+ aData.push_back(Any(result));
+ }
+ break;
+ case DataType::DATE:
+ {
+ sal_Int64 value = 0;
+ m_pStream->ReadInt64(value); // in millisec, from 1970
+ ptime epoch = time_from_string("1970-01-01 00:00:00.000");
+ ptime time = epoch + milliseconds(value);
+ date asDate = time.date();
+
+ css::util::Date loDate(asDate.day(), asDate.month(),
+ asDate.year()); // day, month, year
+ aData.push_back(Any(loDate));
+ }
+ break;
+ case DataType::TIME:
+ {
+ sal_Int64 value = 0;
+ m_pStream->ReadInt64(value);
+ auto valueInSecs = value / 1000;
+ /* Observed valueInSecs fall in the range from
+ negative one day to positive two days. Coerce
+ valueInSecs between zero and positive one day.*/
+ const int secPerDay = 24 * 60 * 60;
+ valueInSecs = (valueInSecs + secPerDay) % secPerDay;
+
+ auto nHours = valueInSecs / (60 * 60);
+ valueInSecs = valueInSecs % 3600;
+ const sal_uInt16 nMins = valueInSecs / 60;
+ const sal_uInt16 nSecs = valueInSecs % 60;
+ css::util::Time time((value % 1000) * 1000000, nSecs, nMins, nHours, true);
+ aData.push_back(Any(time));
+ }
+ break;
+ case DataType::TIMESTAMP:
+ {
+ sal_Int64 nEpochMillis = 0;
+ m_pStream->ReadInt64(nEpochMillis);
+ ptime epoch = time_from_string("1970-01-01 00:00:00.000");
+ ptime time = epoch + milliseconds(nEpochMillis);
+ date asDate = time.date();
+
+ sal_Int32 nNanos = 0;
+ m_pStream->ReadInt32(nNanos);
+
+ // convert into LO internal representation of dateTime
+ css::util::DateTime dateTime;
+ dateTime.NanoSeconds = nNanos;
+ dateTime.Seconds = time.time_of_day().seconds();
+ dateTime.Minutes = time.time_of_day().minutes();
+ dateTime.Hours = time.time_of_day().hours();
+ dateTime.Day = asDate.day();
+ dateTime.Month = asDate.month();
+ dateTime.Year = asDate.year();
+ aData.push_back(Any(dateTime));
+ }
+ break;
+ case DataType::BOOLEAN:
+ {
+ sal_uInt8 nBool = 0;
+ m_pStream->ReadUChar(nBool);
+ aData.push_back(Any(static_cast<bool>(nBool)));
+ }
+ break;
+ case DataType::OTHER:
+ aData.push_back(Any{}); // TODO
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ {
+ sal_Int32 nSize = 0;
+ m_pStream->ReadInt32(nSize);
+
+ Sequence<sal_Int8> aBytes(nSize);
+ m_pStream->ReadBytes(aBytes.getArray(), nSize);
+ aData.push_back(Any(aBytes));
+ }
+ break;
+
+ default:
+ throw WrongFormatException();
+ }
+ }
+ return aData;
+}
+
+} // namespace dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/rowinputbinary.hxx b/dbaccess/source/filter/hsqldb/rowinputbinary.hxx
new file mode 100644
index 000000000..f81fa446f
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/rowinputbinary.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vector>
+#include <tools/stream.hxx>
+
+#include <com/sun/star/io/XInputStream.hpp>
+
+#include "columndef.hxx"
+
+namespace dbahsql
+{
+class HsqlRowInputStream
+{
+private:
+ std::unique_ptr<SvStream> m_pStream;
+
+protected:
+ OUString readString();
+ bool checkNull();
+
+ OUString readUTF(sal_Int32 nLen);
+
+public:
+ HsqlRowInputStream();
+
+ /**
+ * Reads one row from the actual position.
+ * @param colTypes Field types of the row, in a strict order.
+ */
+ std::vector<css::uno::Any> readOneRow(const std::vector<ColumnDefinition>& colTypes);
+
+ /**
+ * Sets the file-pointer offset, measured from the beginning of the file
+ */
+ void seek(sal_Int32 nPos);
+
+ void setInputStream(css::uno::Reference<css::io::XInputStream> const& rStream);
+ SvStream* getInputStream() const;
+};
+
+} // namespace dbahsql
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/utils.cxx b/dbaccess/source/filter/hsqldb/utils.cxx
new file mode 100644
index 000000000..724ffccfb
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/utils.cxx
@@ -0,0 +1,141 @@
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <comphelper/processfactory.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include "utils.hxx"
+
+using namespace dbahsql;
+
+namespace
+{
+int getHexValue(sal_Unicode c)
+{
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+ else if (c >= 'A' && c <= 'F')
+ {
+ return c - 'A' + 10;
+ }
+ else if (c >= 'a' && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+} // unnamed namespace
+
+//Convert ascii escaped unicode to utf-8
+OUString utils::convertToUTF8(std::string_view original)
+{
+ OUString res = OStringToOUString(original, RTL_TEXTENCODING_UTF8);
+ for (sal_Int32 i = 0;;)
+ {
+ i = res.indexOf("\\u", i);
+ if (i == -1)
+ {
+ break;
+ }
+ i += 2;
+ if (res.getLength() - i >= 4)
+ {
+ bool escape = true;
+ sal_Unicode c = 0;
+ for (sal_Int32 j = 0; j != 4; ++j)
+ {
+ auto const n = getHexValue(res[i + j]);
+ if (n == -1)
+ {
+ escape = false;
+ break;
+ }
+ c = (c << 4) | n;
+ }
+ if (escape)
+ {
+ i -= 2;
+ res = res.replaceAt(i, 6, rtl::OUStringChar(c));
+ ++i;
+ }
+ }
+ }
+ return res;
+}
+
+OUString utils::getTableNameFromStmt(std::u16string_view sSql)
+{
+ auto stmtComponents = comphelper::string::split(sSql, sal_Unicode(u' '));
+ assert(stmtComponents.size() > 2);
+ auto wordIter = stmtComponents.begin();
+
+ if (*wordIter == "CREATE" || *wordIter == "ALTER")
+ ++wordIter;
+ if (*wordIter == "CACHED")
+ ++wordIter;
+ if (*wordIter == "TABLE")
+ ++wordIter;
+
+ // it may contain spaces if it's put into apostrophes.
+ if (wordIter->indexOf("\"") >= 0)
+ {
+ size_t nAposBegin = sSql.find('"');
+ size_t nAposEnd = nAposBegin;
+ bool bProperEndAposFound = false;
+ while (!bProperEndAposFound)
+ {
+ nAposEnd = sSql.find('"', nAposEnd + 1);
+ if (sSql[nAposEnd - 1] != u'\\')
+ bProperEndAposFound = true;
+ }
+ std::u16string_view result = sSql.substr(nAposBegin, nAposEnd - nAposBegin + 1);
+ return OUString(result);
+ }
+
+ // next word is the table's name
+ // it might stuck together with the column definitions.
+ sal_Int32 nParenPos = wordIter->indexOf("(");
+ if (nParenPos > 0)
+ return wordIter->copy(0, nParenPos);
+ else
+ return *wordIter;
+}
+
+void utils::ensureFirebirdTableLength(const OUString& sName)
+{
+ if (sName.getLength() > 30) // Firebird limitation
+ {
+ static constexpr OUStringLiteral NAME_TOO_LONG
+ = u"Firebird 3 doesn't support object (table, field) names "
+ "of more than 30 characters; please shorten your object "
+ "names in the original file and try again.";
+ dbtools::throwGenericSQLException(NAME_TOO_LONG,
+ ::comphelper::getProcessComponentContext());
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/hsqldb/utils.hxx b/dbaccess/source/filter/hsqldb/utils.hxx
new file mode 100644
index 000000000..cc3e2f0df
--- /dev/null
+++ b/dbaccess/source/filter/hsqldb/utils.hxx
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <rtl/ustring.hxx>
+
+namespace dbahsql::utils
+{
+OUString convertToUTF8(std::string_view original);
+
+OUString getTableNameFromStmt(std::u16string_view sSql);
+
+void ensureFirebirdTableLength(const OUString& sName);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/dbaxml.component b/dbaccess/source/filter/xml/dbaxml.component
new file mode 100644
index 000000000..4842eb4ad
--- /dev/null
+++ b/dbaccess/source/filter/xml/dbaxml.component
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdb.DBExportFilter"
+ constructor="com_sun_star_comp_sdb_DBExportFilter_get_implementation">
+ <service name="com.sun.star.document.ExportFilter"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.sdb.DBFilter"
+ constructor="com_sun_star_comp_sdb_DBFilter_get_implementation">
+ <service name="com.sun.star.document.ImportFilter"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.sdb.XMLFullExporter"
+ constructor="com_sun_star_comp_sdb_XMLFullExporter_get_implementation">
+ <service name="com.sun.star.document.ExportFilter"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.sdb.XMLSettingsExporter"
+ constructor="com_sun_star_comp_sdb_XMLSettingsExporter_get_implementation">
+ <service name="com.sun.star.document.ExportFilter"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.dbflt.DBContentLoader2"
+ constructor="org_openoffice_comp_dbflt_DBContentLoader2_get_implementation">
+ <service name="com.sun.star.frame.FrameLoader"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.dbflt.DBTypeDetection"
+ constructor="org_openoffice_comp_dbflt_DBTypeDetection_get_implementation">
+ <service name="com.sun.star.document.ExtendedTypeDetection"/>
+ </implementation>
+</component>
diff --git a/dbaccess/source/filter/xml/dbloader2.cxx b/dbaccess/source/filter/xml/dbloader2.cxx
new file mode 100644
index 000000000..0513af5a2
--- /dev/null
+++ b/dbaccess/source/filter/xml/dbloader2.cxx
@@ -0,0 +1,535 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XFrameLoader.hpp>
+#include <com/sun/star/frame/XLoadEventListener.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/task/XJobExecutor.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <com/sun/star/frame/XLoadable.hpp>
+
+#include <comphelper/documentconstants.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+using namespace ::ucbhelper;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::ui::dialogs;
+using ::com::sun::star::awt::XWindow;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+namespace dbaxml
+{
+
+namespace {
+
+class DBTypeDetection : public ::cppu::WeakImplHelper< XExtendedFilterDetection, XServiceInfo>
+{
+ const Reference< XComponentContext > m_aContext;
+
+public:
+ explicit DBTypeDetection(const Reference< XComponentContext >&);
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ virtual OUString SAL_CALL detect( css::uno::Sequence< css::beans::PropertyValue >& Descriptor ) override;
+};
+
+}
+
+DBTypeDetection::DBTypeDetection(const Reference< XComponentContext >& _rxContext)
+ :m_aContext( _rxContext )
+{
+}
+
+OUString SAL_CALL DBTypeDetection::detect( css::uno::Sequence< css::beans::PropertyValue >& Descriptor )
+{
+ try
+ {
+ ::comphelper::NamedValueCollection aMedia( Descriptor );
+ bool bStreamFromDescr = false;
+ OUString sURL = aMedia.getOrDefault( "URL", OUString() );
+
+ Reference< XInputStream > xInStream( aMedia.getOrDefault( "InputStream", Reference< XInputStream >() ) );
+ Reference< XPropertySet > xStorageProperties;
+ if ( xInStream.is() )
+ {
+ bStreamFromDescr = true;
+ xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromInputStream(
+ xInStream, m_aContext ), UNO_QUERY );
+ }
+ else
+ {
+ OUString sSalvagedURL( aMedia.getOrDefault( "SalvagedFile", OUString() ) );
+
+ OUString sFileLocation( sSalvagedURL.isEmpty() ? sURL : sSalvagedURL );
+ if ( !sFileLocation.isEmpty() )
+ {
+ xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromURL(
+ sFileLocation, ElementModes::READ, m_aContext ), UNO_QUERY );
+ }
+ }
+
+ if ( xStorageProperties.is() )
+ {
+ OUString sMediaType;
+ xStorageProperties->getPropertyValue( INFO_MEDIATYPE ) >>= sMediaType;
+ if ( sMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII || sMediaType == MIMETYPE_VND_SUN_XML_BASE_ASCII )
+ {
+ if ( bStreamFromDescr && !sURL.startsWith( "private:stream" ) )
+ {
+ // After fixing of the i88522 issue ( use the new file locking for database files ) the stream from the type detection can be used further
+ // for now the file should be reopened to have read/write access
+ aMedia.remove( "InputStream" );
+ aMedia.remove( "Stream" );
+ aMedia >>= Descriptor;
+ try
+ {
+ ::comphelper::disposeComponent(xStorageProperties);
+ if ( xInStream.is() )
+ xInStream->closeInput();
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ return "StarBase";
+ }
+ ::comphelper::disposeComponent(xStorageProperties);
+ }
+ } catch(Exception&){}
+ return OUString();
+}
+
+// XServiceInfo
+OUString SAL_CALL DBTypeDetection::getImplementationName()
+{
+ return "org.openoffice.comp.dbflt.DBTypeDetection";
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL DBTypeDetection::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > SAL_CALL DBTypeDetection::getSupportedServiceNames()
+{
+ return { "com.sun.star.document.ExtendedTypeDetection" };
+}
+
+} // namespace dbaxml
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbflt_DBTypeDetection_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaxml::DBTypeDetection(context));
+}
+
+namespace dbaxml
+{
+
+namespace {
+
+class DBContentLoader : public ::cppu::WeakImplHelper< XFrameLoader, XServiceInfo>
+{
+private:
+ const Reference< XComponentContext > m_aContext;
+ Reference< XFrameLoader > m_xMySelf;
+ OUString m_sCurrentURL;
+ ImplSVEvent * m_nStartWizard;
+
+ DECL_LINK( OnStartTableWizard, void*, void );
+public:
+ explicit DBContentLoader(const Reference< XComponentContext >&);
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XLoader
+ virtual void SAL_CALL load( const Reference< XFrame > & _rFrame, const OUString& _rURL,
+ const Sequence< PropertyValue >& _rArgs,
+ const Reference< XLoadEventListener > & _rListener) override;
+ virtual void SAL_CALL cancel() override;
+
+private:
+ bool impl_executeNewDatabaseWizard( Reference< XModel > const & _rxModel, bool& _bShouldStartTableWizard );
+};
+
+}
+
+DBContentLoader::DBContentLoader(const Reference< XComponentContext >& _rxFactory)
+ :m_aContext( _rxFactory )
+ ,m_nStartWizard(nullptr)
+{
+
+}
+
+// XServiceInfo
+OUString SAL_CALL DBContentLoader::getImplementationName()
+{
+ return "org.openoffice.comp.dbflt.DBContentLoader2";
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.FrameLoader" };
+}
+
+
+namespace
+{
+ bool lcl_urlAllowsInteraction( const Reference<XComponentContext> & _rContext, const OUString& _rURL )
+ {
+ bool bDoesAllow = false;
+ try
+ {
+ Reference< XURLTransformer > xTransformer( URLTransformer::create(_rContext) );
+ URL aURL;
+ aURL.Complete = _rURL;
+ xTransformer->parseStrict( aURL );
+ bDoesAllow = aURL.Arguments == "Interactive";
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "lcl_urlAllowsInteraction: caught an exception while analyzing the URL!" );
+ }
+ return bDoesAllow;
+ }
+
+ Reference< XWindow > lcl_getTopMostWindow( const Reference<XComponentContext> & _rxContext )
+ {
+ Reference< XWindow > xWindow;
+ // get the top most window
+ Reference < XDesktop2 > xDesktop = Desktop::create(_rxContext);
+ Reference < XFrame > xActiveFrame = xDesktop->getActiveFrame();
+ if ( xActiveFrame.is() )
+ {
+ xWindow = xActiveFrame->getContainerWindow();
+ Reference<XFrame> xFrame = xActiveFrame;
+ while ( xFrame.is() && !xFrame->isTop() )
+ xFrame = xFrame->getCreator();
+
+ if ( xFrame.is() )
+ xWindow = xFrame->getContainerWindow();
+ }
+ return xWindow;
+ }
+}
+
+bool DBContentLoader::impl_executeNewDatabaseWizard( Reference< XModel > const & _rxModel, bool& _bShouldStartTableWizard )
+{
+ Sequence<Any> aWizardArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"ParentWindow", Any(lcl_getTopMostWindow( m_aContext ))},
+ {"InitialSelection", Any(_rxModel)}
+ }));
+
+ // create the dialog
+ Reference< XExecutableDialog > xAdminDialog( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.sdb.DatabaseWizardDialog", aWizardArgs, m_aContext), UNO_QUERY_THROW);
+
+ // execute it
+ if ( RET_OK != xAdminDialog->execute() )
+ return false;
+
+ Reference<XPropertySet> xProp(xAdminDialog,UNO_QUERY);
+ bool bSuccess = false;
+ xProp->getPropertyValue("OpenDatabase") >>= bSuccess;
+ xProp->getPropertyValue("StartTableWizard") >>= _bShouldStartTableWizard;
+ return bSuccess;
+}
+
+void SAL_CALL DBContentLoader::load(const Reference< XFrame > & rFrame, const OUString& _rURL,
+ const Sequence< PropertyValue >& rArgs,
+ const Reference< XLoadEventListener > & rListener)
+{
+ // first check if preview is true, if so return without creating a controller. Preview is not supported
+ ::comphelper::NamedValueCollection aMediaDesc( rArgs );
+ bool bPreview = aMediaDesc.getOrDefault( "Preview", false );
+ if ( bPreview )
+ {
+ if (rListener.is())
+ rListener->loadCancelled(this);
+ return;
+ }
+
+ Reference< XModel > xModel = aMediaDesc.getOrDefault( "Model", Reference< XModel >() );
+ OUString sSalvagedURL = aMediaDesc.getOrDefault( "SalvagedFile", _rURL );
+
+ bool bCreateNew = false; // does the URL denote the private:factory URL?
+ bool bStartTableWizard = false; // start the table wizard after everything was loaded successfully?
+
+ bool bSuccess = true;
+
+ // If there's no interaction handler in the media descriptor, put one.
+ // By definition, loading via loadComponentFromURL (and thus via the content loader here)
+ // is allowed to raise UI. To not burden every place inside the document with creating
+ // a default handler, we simply ensure there is one.
+ // If a handler is present in the media descriptor, even if it is NULL, we will
+ // not touch it.
+ if ( !aMediaDesc.has( "InteractionHandler" ) )
+ {
+ Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(m_aContext, nullptr) );
+ aMediaDesc.put( "InteractionHandler", xHandler );
+ }
+
+ // it's allowed to pass an existing document
+ Reference< XOfficeDatabaseDocument > xExistentDBDoc;
+ xModel.set( aMediaDesc.getOrDefault( "Model", xExistentDBDoc ), UNO_QUERY );
+ aMediaDesc.remove( "Model" );
+
+ // also, it's allowed to specify the type of view which should be created
+ OUString sViewName = aMediaDesc.getOrDefault( "ViewName", OUString( "Default" ) );
+ aMediaDesc.remove( "ViewName" );
+
+ // this needs to stay alive for duration of this method
+ Reference< XDatabaseContext > xDatabaseContext;
+
+ sal_Int32 nInitialSelection = -1;
+ if ( !xModel.is() )
+ {
+ xDatabaseContext = DatabaseContext::create(m_aContext);
+
+ OUString sFactoryName = SvtModuleOptions().GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::DATABASE);
+ bCreateNew = sFactoryName.match(_rURL);
+
+ Reference< XDocumentDataSource > xDocumentDataSource;
+ bool bNewAndInteractive = false;
+ if ( bCreateNew )
+ {
+ bNewAndInteractive = lcl_urlAllowsInteraction( m_aContext, _rURL );
+ xDocumentDataSource.set( xDatabaseContext->createInstance(), UNO_QUERY_THROW );
+ }
+ else
+ {
+ ::comphelper::NamedValueCollection aCreationArgs;
+ aCreationArgs.put( INFO_POOLURL, sSalvagedURL );
+ xDocumentDataSource.set( xDatabaseContext->createInstanceWithArguments( aCreationArgs.getWrappedNamedValues() ), UNO_QUERY_THROW );
+ }
+
+ xModel.set( xDocumentDataSource->getDatabaseDocument(), UNO_QUERY );
+
+ if ( bCreateNew && xModel.is() )
+ {
+ if ( bNewAndInteractive )
+ {
+ bSuccess = impl_executeNewDatabaseWizard( xModel, bStartTableWizard );
+ }
+ else
+ {
+ try
+ {
+ Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
+ xLoad->initNew();
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ bSuccess = false;
+ }
+ }
+
+ // initially select the "Tables" category (will be done below)
+ nInitialSelection = css::sdb::application::DatabaseObjectContainer::TABLES;
+ }
+ }
+
+ if ( !xModel.is() )
+ {
+ if ( rListener.is() )
+ rListener->loadCancelled(this);
+ return;
+ }
+
+ if ( !bCreateNew )
+ {
+ // We need to XLoadable::load the document if it does not yet have a URL.
+ // If it already *does* have a URL, then it was either passed in the arguments, or a previous incarnation
+ // of that model existed before (which can happen if a model is closed, but an associated DataSource is kept
+ // alive 'til loading the document again).
+ bool bNeedLoad = xModel->getURL().isEmpty();
+ try
+ {
+ aMediaDesc.put( "FileName", _rURL );
+ Sequence< PropertyValue > aResource( aMediaDesc.getPropertyValues() );
+
+ if ( bNeedLoad )
+ {
+ Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
+ xLoad->load( aResource );
+ }
+
+ // always attach the resource, even if the document has not been freshly loaded
+ xModel->attachResource( _rURL, aResource );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ bSuccess = false;
+ }
+ }
+
+ if ( bSuccess )
+ {
+ try
+ {
+ Reference< XModel2 > xModel2( xModel, UNO_QUERY_THROW );
+ Reference< XController2 > xController( xModel2->createViewController( sViewName, Sequence< PropertyValue >(), rFrame ), UNO_SET_THROW );
+
+ xController->attachModel( xModel );
+ xModel->connectController( xController );
+ rFrame->setComponent( xController->getComponentWindow(), xController );
+ xController->attachFrame( rFrame );
+ xModel->setCurrentController( xController );
+
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ bSuccess = false;
+ }
+ }
+
+ if (bSuccess)
+ {
+ if ( rListener.is() )
+ rListener->loadFinished(this);
+
+ if ( nInitialSelection != -1 )
+ {
+ Reference< css::view::XSelectionSupplier > xDocView( xModel->getCurrentController(), UNO_QUERY );
+ if ( xDocView.is() )
+ {
+ NamedDatabaseObject aSelection;
+ aSelection.Type = nInitialSelection;
+ xDocView->select( Any( aSelection ) );
+ }
+ }
+
+ if ( bStartTableWizard )
+ {
+ // reset the data of the previous async drop (if any)
+ if ( m_nStartWizard )
+ Application::RemoveUserEvent(m_nStartWizard);
+ m_sCurrentURL = xModel->getURL();
+ m_xMySelf = this;
+ m_nStartWizard = Application::PostUserEvent(LINK(this, DBContentLoader, OnStartTableWizard));
+ }
+ }
+ else
+ {
+ if ( rListener.is() )
+ rListener->loadCancelled( this );
+ }
+
+ if ( !bSuccess )
+ ::comphelper::disposeComponent(xModel);
+}
+
+void DBContentLoader::cancel()
+{
+}
+
+IMPL_LINK_NOARG( DBContentLoader, OnStartTableWizard, void*, void )
+{
+ m_nStartWizard = nullptr;
+ try
+ {
+ Sequence<Any> aWizArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"DatabaseLocation", Any(m_sCurrentURL)}
+ }));
+ SolarMutexGuard aGuard;
+ Reference< XJobExecutor > xTableWizard( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.wizards.table.CallTableWizard", aWizArgs, m_aContext), UNO_QUERY);
+ if ( xTableWizard.is() )
+ xTableWizard->trigger("start");
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "caught an exception while starting the table wizard!");
+ }
+ m_xMySelf = nullptr;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbflt_DBContentLoader2_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaxml::DBContentLoader(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlAutoStyle.cxx b/dbaccess/source/filter/xml/xmlAutoStyle.cxx
new file mode 100644
index 000000000..991015671
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlAutoStyle.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlAutoStyle.hxx"
+#include "xmlHelper.hxx"
+#include "xmlExport.hxx"
+#include <xmloff/families.hxx>
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+void OXMLAutoStylePoolP::exportStyleAttributes(
+ SvXMLAttributeList& rAttrList,
+ XmlStyleFamily nFamily,
+ const std::vector< XMLPropertyState >& rProperties,
+ const SvXMLExportPropertyMapper& rPropExp
+ , const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap
+ ) const
+{
+ SvXMLAutoStylePoolP::exportStyleAttributes( rAttrList, nFamily, rProperties, rPropExp, rUnitConverter, rNamespaceMap );
+ if ( nFamily != XmlStyleFamily::TABLE_COLUMN )
+ return;
+
+ rtl::Reference< XMLPropertySetMapper > aPropMapper = rODBExport.GetColumnStylesPropertySetMapper();
+ for (auto const& property : rProperties)
+ {
+ sal_Int16 nContextID = aPropMapper->GetEntryContextId(property.mnIndex);
+ switch (nContextID)
+ {
+ case CTF_DB_NUMBERFORMAT :
+ {
+ sal_Int32 nNumberFormat = 0;
+ if ( property.maValue >>= nNumberFormat )
+ {
+ OUString sAttrValue = rODBExport.getDataStyleName(nNumberFormat);
+ if ( !sAttrValue.isEmpty() )
+ {
+ GetExport().AddAttribute(
+ aPropMapper->GetEntryNameSpace(property.mnIndex),
+ aPropMapper->GetEntryXMLName(property.mnIndex),
+ sAttrValue );
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+OXMLAutoStylePoolP::OXMLAutoStylePoolP(ODBExport& rTempODBExport):
+ SvXMLAutoStylePoolP(rTempODBExport),
+ rODBExport(rTempODBExport)
+{
+
+}
+
+OXMLAutoStylePoolP::~OXMLAutoStylePoolP()
+{
+
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlAutoStyle.hxx b/dbaccess/source/filter/xml/xmlAutoStyle.hxx
new file mode 100644
index 000000000..54748a22c
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlAutoStyle.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <xmloff/maptype.hxx>
+#include <xmloff/xmlaustp.hxx>
+
+namespace dbaxml
+{
+ class ODBExport;
+ class OXMLAutoStylePoolP : public SvXMLAutoStylePoolP
+ {
+ ODBExport& rODBExport;
+
+ virtual void exportStyleAttributes(
+ SvXMLAttributeList& rAttrList,
+ XmlStyleFamily nFamily,
+ const std::vector< XMLPropertyState >& rProperties,
+ const SvXMLExportPropertyMapper& rPropExp,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& rNamespaceMap
+ ) const override;
+
+ public:
+ explicit OXMLAutoStylePoolP(ODBExport& rXMLExport);
+ virtual ~OXMLAutoStylePoolP() override;
+ };
+} // dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlColumn.cxx b/dbaccess/source/filter/xml/xmlColumn.cxx
new file mode 100644
index 000000000..1afbf9f0f
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlColumn.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlColumn.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <strings.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include "xmlStyleImport.hxx"
+#include <osl/diagnose.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLColumn::OXMLColumn( ODBFilter& rImport
+ ,const Reference< XFastAttributeList > & _xAttrList
+ ,const Reference< XNameAccess >& _xParentContainer
+ ,const Reference< XPropertySet >& _xTable
+ ) :
+ SvXMLImportContext( rImport )
+ ,m_xParentContainer(_xParentContainer)
+ ,m_xTable(_xTable)
+ ,m_bHidden(false)
+{
+ OUString sType;
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_NAME:
+ m_sName = aIter.toString();
+ break;
+ case XML_STYLE_NAME:
+ m_sStyleName = aIter.toString();
+ break;
+ case XML_HELP_MESSAGE:
+ m_sHelpMessage = aIter.toString();
+ break;
+ case XML_VISIBILITY:
+ m_bHidden = aIter.toView() != "visible";
+ break;
+ case XML_TYPE_NAME:
+ sType = aIter.toString();
+ OSL_ENSURE(!sType.isEmpty(),"No type name set");
+ break;
+ case XML_DEFAULT_VALUE:
+ if ( !(aIter.isEmpty() || sType.isEmpty()) )
+ m_aDefaultValue <<= aIter.toString();
+ break;
+ case XML_VISIBLE:
+ m_bHidden = aIter.toView() == "false";
+ break;
+ case XML_DEFAULT_CELL_STYLE_NAME:
+ m_sCellStyleName = aIter.toString();
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+}
+
+OXMLColumn::~OXMLColumn()
+{
+
+}
+
+void OXMLColumn::endFastElement(sal_Int32 )
+{
+ Reference<XDataDescriptorFactory> xFac(m_xParentContainer,UNO_QUERY);
+ if ( xFac.is() && !m_sName.isEmpty() )
+ {
+ Reference<XPropertySet> xProp(xFac->createDataDescriptor());
+ if ( xProp.is() )
+ {
+ xProp->setPropertyValue(PROPERTY_NAME,Any(m_sName));
+ xProp->setPropertyValue(PROPERTY_HIDDEN,Any(m_bHidden));
+ if ( !m_sHelpMessage.isEmpty() )
+ xProp->setPropertyValue(PROPERTY_HELPTEXT,Any(m_sHelpMessage));
+
+ if ( m_aDefaultValue.hasValue() )
+ xProp->setPropertyValue(PROPERTY_CONTROLDEFAULT,m_aDefaultValue);
+
+ Reference<XAppend> xAppend(m_xParentContainer,UNO_QUERY);
+ if ( xAppend.is() )
+ xAppend->appendByDescriptor(xProp);
+ m_xParentContainer->getByName(m_sName) >>= xProp;
+
+ if ( !m_sStyleName.isEmpty() )
+ {
+ const SvXMLStylesContext* pAutoStyles = GetOwnImport().GetAutoStyles();
+ if ( pAutoStyles )
+ {
+ OTableStyleContext* pAutoStyle = const_cast<OTableStyleContext*>(
+ dynamic_cast< const OTableStyleContext* >(pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_COLUMN,m_sStyleName)));
+ if ( pAutoStyle )
+ {
+ pAutoStyle->FillPropertySet(xProp);
+ }
+ }
+ }
+ if ( !m_sCellStyleName.isEmpty() )
+ {
+ const SvXMLStylesContext* pAutoStyles = GetOwnImport().GetAutoStyles();
+ if ( pAutoStyles )
+ {
+ OTableStyleContext* pAutoStyle = const_cast<OTableStyleContext*>(dynamic_cast<const OTableStyleContext* >(pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_CELL,m_sCellStyleName)));
+ if ( pAutoStyle )
+ {
+ pAutoStyle->FillPropertySet(xProp);
+ // we also have to do this on the table to import text-properties
+ pAutoStyle->FillPropertySet(m_xTable);
+ }
+ }
+ }
+
+ }
+ }
+ else if ( !m_sCellStyleName.isEmpty() )
+ {
+ const SvXMLStylesContext* pAutoStyles = GetOwnImport().GetAutoStyles();
+ if ( pAutoStyles )
+ {
+ OTableStyleContext* pAutoStyle = const_cast<OTableStyleContext*>(dynamic_cast< const OTableStyleContext* >(pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_CELL,m_sCellStyleName)));
+ if ( pAutoStyle )
+ {
+ // we also have to do this on the table to import text-properties
+ pAutoStyle->FillPropertySet(m_xTable);
+ }
+ }
+ }
+}
+
+ODBFilter& OXMLColumn::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlColumn.hxx b/dbaccess/source/filter/xml/xmlColumn.hxx
new file mode 100644
index 000000000..8deca87c7
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlColumn.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLColumn : public SvXMLImportContext
+ {
+ css::uno::Reference< css::container::XNameAccess > m_xParentContainer;
+ css::uno::Reference< css::beans::XPropertySet > m_xTable;
+
+ OUString m_sName;
+ OUString m_sStyleName;
+ OUString m_sCellStyleName;
+ OUString m_sHelpMessage;
+ css::uno::Any m_aDefaultValue;
+ bool m_bHidden;
+
+ ODBFilter& GetOwnImport();
+ public:
+
+ OXMLColumn( ODBFilter& rImport
+ ,const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList
+ ,const css::uno::Reference< css::container::XNameAccess >& _xParentContainer
+ ,const css::uno::Reference< css::beans::XPropertySet >& _xTable
+ );
+ virtual ~OXMLColumn() override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlComponent.cxx b/dbaccess/source/filter/xml/xmlComponent.cxx
new file mode 100644
index 000000000..97423f14a
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlComponent.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlComponent.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <strings.hxx>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <tools/diagnose_ex.h>
+#include <comphelper/propertysequence.hxx>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLComponent::OXMLComponent( ODBFilter& rImport
+ ,const Reference< XFastAttributeList > & _xAttrList
+ ,const Reference< XNameAccess >& _xParentContainer
+ ,const OUString& _sComponentServiceName
+ ) :
+ SvXMLImportContext( rImport )
+{
+ OUString sName;
+ OUString sHREF;
+ bool bAsTemplate(false);
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ switch( aIter.getToken() )
+ {
+ case XML_ELEMENT(XLINK, XML_HREF):
+ sHREF = aIter.toString();
+ break;
+ case XML_ELEMENT(DB, XML_NAME):
+ case XML_ELEMENT(DB_OASIS, XML_NAME):
+ sName = aIter.toString();
+ // sanitize the name. Previously, we allowed to create forms/reports/queries which contain
+ // a / in their name, which nowadays is forbidden. To not lose such objects if they're contained
+ // in older files, we replace the slash with something less offending.
+ sName = sName.replace( '/', '_' );
+ break;
+ case XML_ELEMENT(DB, XML_AS_TEMPLATE):
+ case XML_ELEMENT(DB_OASIS, XML_AS_TEMPLATE):
+ bAsTemplate = IsXMLToken(aIter, XML_TRUE);
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+ if ( !(!sHREF.isEmpty() && !sName.isEmpty() && _xParentContainer.is()) )
+ return;
+
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {PROPERTY_NAME, Any(sName)}, // set as folder
+ {PROPERTY_PERSISTENT_NAME, Any(sHREF.copy(sHREF.lastIndexOf('/')+1))},
+ {PROPERTY_AS_TEMPLATE, Any(bAsTemplate)},
+ }));
+ try
+ {
+ Reference< XMultiServiceFactory > xORB( _xParentContainer, UNO_QUERY_THROW );
+ Reference< XInterface > xComponent( xORB->createInstanceWithArguments( _sComponentServiceName, aArguments ) );
+ Reference< XNameContainer > xNameContainer( _xParentContainer, UNO_QUERY_THROW );
+ xNameContainer->insertByName( sName, Any( xComponent ) );
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OXMLComponent::~OXMLComponent()
+{
+
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlComponent.hxx b/dbaccess/source/filter/xml/xmlComponent.hxx
new file mode 100644
index 000000000..136d5b685
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlComponent.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLComponent : public SvXMLImportContext
+ {
+ public:
+
+ OXMLComponent( ODBFilter& rImport
+ ,const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList
+ ,const css::uno::Reference< css::container::XNameAccess >& _xParentContainer
+ ,const OUString& _sComponentServiceName
+ );
+ virtual ~OXMLComponent() override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlConnectionData.cxx b/dbaccess/source/filter/xml/xmlConnectionData.cxx
new file mode 100644
index 000000000..221358537
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlConnectionData.cxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlConnectionData.hxx"
+#include "xmlLogin.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+#include "xmlDatabaseDescription.hxx"
+#include "xmlConnectionResource.hxx"
+#include <osl/diagnose.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLConnectionData::OXMLConnectionData( ODBFilter& rImport) :
+ SvXMLImportContext( rImport )
+ ,m_bFoundOne(false)
+{
+ rImport.setNewFormat(true);
+}
+
+OXMLConnectionData::~OXMLConnectionData()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLConnectionData::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_LOGIN:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLLogin( GetOwnImport(), xAttrList );
+ break;
+ case XML_DATABASE_DESCRIPTION:
+ if ( !m_bFoundOne )
+ {
+ m_bFoundOne = true;
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDatabaseDescription( GetOwnImport() );
+ }
+ break;
+ case XML_CONNECTION_RESOURCE:
+ if ( !m_bFoundOne )
+ {
+ m_bFoundOne = true;
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLConnectionResource( GetOwnImport(), xAttrList );
+ }
+ break;
+ case XML_COMPOUND_DATABASE:
+ if ( !m_bFoundOne )
+ {
+ m_bFoundOne = true;
+ OSL_FAIL("Not supported yet!");
+ }
+ break;
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLConnectionData::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlConnectionData.hxx b/dbaccess/source/filter/xml/xmlConnectionData.hxx
new file mode 100644
index 000000000..466c04788
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlConnectionData.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLConnectionData : public SvXMLImportContext
+ {
+ bool m_bFoundOne;
+
+ ODBFilter& GetOwnImport();
+ public:
+
+ OXMLConnectionData( ODBFilter& rImport );
+ virtual ~OXMLConnectionData() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlConnectionResource.cxx b/dbaccess/source/filter/xml/xmlConnectionResource.cxx
new file mode 100644
index 000000000..2df2a1a73
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlConnectionResource.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlConnectionResource.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <strings.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLConnectionResource::OXMLConnectionResource( ODBFilter& rImport,
+ const Reference< XFastAttributeList > & _xAttrList) :
+ SvXMLImportContext( rImport )
+{
+ Reference<XPropertySet> xDataSource = rImport.getDataSource();
+
+ PropertyValue aProperty;
+
+ if (!xDataSource.is())
+ return;
+
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ aProperty.Name.clear();
+ aProperty.Value = Any();
+
+ switch( aIter.getToken() )
+ {
+ case XML_ELEMENT(XLINK, XML_HREF):
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_URL,Any(aIter.toString()));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ break;
+ case XML_ELEMENT(XLINK, XML_TYPE):
+ aProperty.Name = PROPERTY_TYPE;
+ break;
+ case XML_ELEMENT(XLINK, XML_SHOW):
+ aProperty.Name = "Show";
+ break;
+ case XML_ELEMENT(XLINK, XML_ACTUATE):
+ aProperty.Name = "Actuate";
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ if ( !aProperty.Name.isEmpty() )
+ {
+ if ( !aProperty.Value.hasValue() )
+ aProperty.Value <<= aIter.toString();
+ rImport.addInfo(aProperty);
+ }
+ }
+}
+
+OXMLConnectionResource::~OXMLConnectionResource()
+{
+
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlConnectionResource.hxx b/dbaccess/source/filter/xml/xmlConnectionResource.hxx
new file mode 100644
index 000000000..357bbe1e1
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlConnectionResource.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLConnectionResource : public SvXMLImportContext
+ {
+ public:
+
+ OXMLConnectionResource( ODBFilter& rImport,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList );
+ virtual ~OXMLConnectionResource() override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSource.cxx b/dbaccess/source/filter/xml/xmlDataSource.cxx
new file mode 100644
index 000000000..bf63d4f79
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSource.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlDataSource.hxx"
+#include "xmlLogin.hxx"
+#include "xmlTableFilterList.hxx"
+#include "xmlDataSourceInfo.hxx"
+#include "xmlDataSourceSettings.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+#include <strings.hxx>
+#include <tools/diagnose_ex.h>
+#include "xmlConnectionData.hxx"
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLDataSource::OXMLDataSource( ODBFilter& rImport,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _xAttrList,
+ const UsedFor _eUsedFor ) :
+ SvXMLImportContext( rImport )
+{
+
+ Reference<XPropertySet> xDataSource = rImport.getDataSource();
+
+ PropertyValue aProperty;
+ bool bFoundParamNameSubstitution = false;
+ bool bFoundTableNameLengthLimited = false;
+ bool bFoundAppendTableAliasName = false;
+ bool bFoundSuppressVersionColumns = false;
+
+ if (xDataSource.is())
+ {
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ aProperty.Name.clear();
+ aProperty.Value = Any();
+
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_CONNECTION_RESOURCE:
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_URL,Any(aIter.toString()));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ break;
+ case XML_SUPPRESS_VERSION_COLUMNS:
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_SUPPRESSVERSIONCL,Any(IsXMLToken(aIter, XML_TRUE)));
+ bFoundSuppressVersionColumns = true;
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ break;
+ case XML_JAVA_DRIVER_CLASS:
+ aProperty.Name = INFO_JDBCDRIVERCLASS;
+ break;
+ case XML_EXTENSION:
+ aProperty.Name = INFO_TEXTFILEEXTENSION;
+ break;
+ case XML_IS_FIRST_ROW_HEADER_LINE:
+ aProperty.Name = INFO_TEXTFILEHEADER;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ break;
+ case XML_SHOW_DELETED:
+ aProperty.Name = INFO_SHOWDELETEDROWS;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ break;
+ case XML_IS_TABLE_NAME_LENGTH_LIMITED:
+ aProperty.Name = INFO_ALLOWLONGTABLENAMES;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ bFoundTableNameLengthLimited = true;
+ break;
+ case XML_SYSTEM_DRIVER_SETTINGS:
+ aProperty.Name = INFO_ADDITIONALOPTIONS;
+ break;
+ case XML_ENABLE_SQL92_CHECK:
+ aProperty.Name = PROPERTY_ENABLESQL92CHECK;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ break;
+ case XML_APPEND_TABLE_ALIAS_NAME:
+ aProperty.Name = INFO_APPEND_TABLE_ALIAS;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ bFoundAppendTableAliasName = true;
+ break;
+ case XML_PARAMETER_NAME_SUBSTITUTION:
+ aProperty.Name = INFO_PARAMETERNAMESUBST;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ bFoundParamNameSubstitution = true;
+ break;
+ case XML_IGNORE_DRIVER_PRIVILEGES:
+ aProperty.Name = INFO_IGNOREDRIVER_PRIV;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ break;
+ case XML_BOOLEAN_COMPARISON_MODE:
+ aProperty.Name = PROPERTY_BOOLEANCOMPARISONMODE;
+ if ( aIter.toView() == "equal-integer" )
+ aProperty.Value <<= sal_Int32(0);
+ else if ( aIter.toView() == "is-boolean" )
+ aProperty.Value <<= sal_Int32(1);
+ else if ( aIter.toView() == "equal-boolean" )
+ aProperty.Value <<= sal_Int32(2);
+ else if ( aIter.toView() == "equal-use-only-zero" )
+ aProperty.Value <<= sal_Int32(3);
+ break;
+ case XML_USE_CATALOG:
+ aProperty.Name = INFO_USECATALOG;
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ break;
+ case XML_BASE_DN:
+ aProperty.Name = INFO_CONN_LDAP_BASEDN;
+ break;
+ case XML_MAX_ROW_COUNT:
+ aProperty.Name = INFO_CONN_LDAP_ROWCOUNT;
+ aProperty.Value <<= aIter.toInt32();
+ break;
+ case XML_JAVA_CLASSPATH:
+ aProperty.Name = "JavaDriverClassPath";
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ if ( !aProperty.Name.isEmpty() )
+ {
+ if ( !aProperty.Value.hasValue() )
+ aProperty.Value <<= aIter.toString();
+ rImport.addInfo(aProperty);
+ }
+ }
+ }
+ if ( !rImport.isNewFormat() )
+ return;
+
+ if ( !bFoundTableNameLengthLimited && ( _eUsedFor == eAppSettings ) )
+ {
+ aProperty.Name = INFO_ALLOWLONGTABLENAMES;
+ aProperty.Value <<= true;
+ rImport.addInfo(aProperty);
+ }
+ if ( !bFoundParamNameSubstitution && ( _eUsedFor == eDriverSettings ) )
+ {
+ aProperty.Name = INFO_PARAMETERNAMESUBST;
+ aProperty.Value <<= true;
+ rImport.addInfo(aProperty);
+ }
+ if ( !bFoundAppendTableAliasName && ( _eUsedFor == eAppSettings ) )
+ {
+ aProperty.Name = INFO_APPEND_TABLE_ALIAS;
+ aProperty.Value <<= true;
+ rImport.addInfo(aProperty);
+ }
+ if ( !bFoundSuppressVersionColumns && ( _eUsedFor == eAppSettings ) )
+ {
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_SUPPRESSVERSIONCL,Any(true));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+OXMLDataSource::~OXMLDataSource()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLDataSource::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_LOGIN:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLLogin( GetOwnImport(), xAttrList );
+ break;
+
+ case XML_TABLE_FILTER:
+ case XML_TABLE_TYPE_FILTER:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLTableFilterList( GetImport() );
+ break;
+ case XML_AUTO_INCREMENT:
+ case XML_DELIMITER:
+ case XML_FONT_CHARSET:
+ case XML_CHARACTER_SET:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSourceInfo( GetOwnImport(), nElement, xAttrList );
+ break;
+ case XML_DATA_SOURCE_SETTINGS:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSourceSettings( GetOwnImport() );
+ break;
+ case XML_CONNECTION_DATA:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLConnectionData( GetOwnImport() );
+ break;
+ case XML_DRIVER_SETTINGS:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSource( GetOwnImport(), xAttrList, OXMLDataSource::eDriverSettings );
+ break;
+ case XML_APPLICATION_CONNECTION_SETTINGS:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSource( GetOwnImport(), xAttrList, OXMLDataSource::eAppSettings );
+ break;
+ default:
+ SAL_WARN("dbaccess", "unknown element " << nElement);
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLDataSource::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSource.hxx b/dbaccess/source/filter/xml/xmlDataSource.hxx
new file mode 100644
index 000000000..5b78ff4fe
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSource.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLDataSource : public SvXMLImportContext
+ {
+ ODBFilter& GetOwnImport();
+ public:
+ enum UsedFor
+ {
+ eDataSource,
+ eDriverSettings,
+ eAppSettings
+ };
+
+ OXMLDataSource( ODBFilter& rImport,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& _xAttrList,
+ const UsedFor _eUsedFor );
+ virtual ~OXMLDataSource() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSourceInfo.cxx b/dbaccess/source/filter/xml/xmlDataSourceInfo.cxx
new file mode 100644
index 000000000..eefc08e41
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSourceInfo.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlDataSourceInfo.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <strings.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLDataSourceInfo::OXMLDataSourceInfo( ODBFilter& rImport
+ ,sal_Int32 nElement
+ ,const Reference< XFastAttributeList > & _xAttrList) :
+ SvXMLImportContext( rImport )
+{
+ PropertyValue aProperty;
+ bool bAutoEnabled = false;
+ bool bFoundField = false,bFoundThousand = false, bFoundCharset = false;
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ aProperty.Name.clear();
+
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_ADDITIONAL_COLUMN_STATEMENT:
+ aProperty.Name = PROPERTY_AUTOINCREMENTCREATION;
+ bAutoEnabled = true;
+ break;
+ case XML_ROW_RETRIEVING_STATEMENT:
+ aProperty.Name = INFO_AUTORETRIEVEVALUE;
+ bAutoEnabled = true;
+ break;
+ case XML_STRING:
+ aProperty.Name = INFO_TEXTDELIMITER;
+ break;
+ case XML_FIELD:
+ aProperty.Name = INFO_FIELDDELIMITER;
+ bFoundField = true;
+ break;
+ case XML_DECIMAL:
+ aProperty.Name = INFO_DECIMALDELIMITER;
+ break;
+ case XML_THOUSAND:
+ aProperty.Name = INFO_THOUSANDSDELIMITER;
+ bFoundThousand = true;
+ break;
+ case XML_ENCODING:
+ aProperty.Name = INFO_CHARSET;
+ bFoundCharset = true;
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ if ( !aProperty.Name.isEmpty() )
+ {
+ aProperty.Value <<= aIter.toString();
+ rImport.addInfo(aProperty);
+ }
+ }
+ if ( bAutoEnabled )
+ {
+ aProperty.Name = INFO_AUTORETRIEVEENABLED;
+ aProperty.Value <<= true;
+ rImport.addInfo(aProperty);
+ }
+ if ( !rImport.isNewFormat() )
+ return;
+
+ if ( (nElement & TOKEN_MASK) == XML_DELIMITER )
+ {
+ if ( !bFoundField )
+ {
+ aProperty.Name = INFO_FIELDDELIMITER;
+ aProperty.Value <<= OUString(";");
+ rImport.addInfo(aProperty);
+ }
+ if ( !bFoundThousand )
+ {
+ aProperty.Name = INFO_THOUSANDSDELIMITER;
+ aProperty.Value <<= OUString(",");
+ rImport.addInfo(aProperty);
+ }
+ }
+ if ( (nElement & TOKEN_MASK) == XML_FONT_CHARSET && !bFoundCharset )
+ {
+ aProperty.Name = INFO_CHARSET;
+ aProperty.Value <<= OUString("utf8");
+ rImport.addInfo(aProperty);
+ }
+}
+
+OXMLDataSourceInfo::~OXMLDataSourceInfo()
+{
+
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSourceInfo.hxx b/dbaccess/source/filter/xml/xmlDataSourceInfo.hxx
new file mode 100644
index 000000000..e29d37a7d
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSourceInfo.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLDataSourceInfo : public SvXMLImportContext
+ {
+ public:
+
+ OXMLDataSourceInfo( ODBFilter& rImport,
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList);
+ virtual ~OXMLDataSourceInfo() override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSourceSetting.cxx b/dbaccess/source/filter/xml/xmlDataSourceSetting.cxx
new file mode 100644
index 000000000..9402bb399
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSourceSetting.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <map>
+
+#include "xmlDataSourceSetting.hxx"
+#include <sax/tools/converter.hxx>
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+#include <osl/diagnose.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLDataSourceSetting::OXMLDataSourceSetting( ODBFilter& rImport
+ ,const Reference< XFastAttributeList > & _xAttrList
+ ,OXMLDataSourceSetting* _pContainer) :
+ SvXMLImportContext( rImport )
+ ,m_pContainer(_pContainer)
+ ,m_bIsList(false)
+{
+
+ m_aPropType = cppu::UnoType<void>::get();
+
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_DATA_SOURCE_SETTING_IS_LIST:
+ m_bIsList = aIter.toView() == "true";
+ break;
+ case XML_DATA_SOURCE_SETTING_TYPE:
+ {
+ // needs to be translated into a css::uno::Type
+ static std::map< OUString, css::uno::Type > s_aTypeNameMap = []()
+ {
+ std::map< OUString, css::uno::Type > tmp;
+ tmp[GetXMLToken( XML_BOOLEAN)] = cppu::UnoType<bool>::get();
+ // Not a copy paste error, see comment xmloff/source/forms/propertyimport.cxx lines 244-248
+ tmp[GetXMLToken( XML_FLOAT)] = ::cppu::UnoType<double>::get();
+ tmp[GetXMLToken( XML_DOUBLE)] = ::cppu::UnoType<double>::get();
+ tmp[GetXMLToken( XML_STRING)] = ::cppu::UnoType<OUString>::get();
+ tmp[GetXMLToken( XML_INT)] = ::cppu::UnoType<sal_Int32>::get();
+ tmp[GetXMLToken( XML_SHORT)] = ::cppu::UnoType<sal_Int16>::get();
+ tmp[GetXMLToken( XML_VOID)] = cppu::UnoType<void>::get();
+ return tmp;
+ }();
+
+ const std::map< OUString, css::uno::Type >::const_iterator aTypePos = s_aTypeNameMap.find(aIter.toString());
+ OSL_ENSURE(s_aTypeNameMap.end() != aTypePos, "OXMLDataSourceSetting::OXMLDataSourceSetting: invalid type!");
+ if (s_aTypeNameMap.end() != aTypePos)
+ m_aPropType = aTypePos->second;
+ }
+ break;
+ case XML_DATA_SOURCE_SETTING_NAME:
+ m_aSetting.Name = aIter.toString();
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+
+}
+
+OXMLDataSourceSetting::~OXMLDataSourceSetting()
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLDataSourceSetting::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_DATA_SOURCE_SETTING:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSourceSetting( GetOwnImport(), xAttrList);
+ break;
+ case XML_DATA_SOURCE_SETTING_VALUE:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSourceSetting( GetOwnImport(), xAttrList,this );
+ break;
+ }
+
+ return pContext;
+}
+
+void OXMLDataSourceSetting::endFastElement(sal_Int32 )
+{
+ if ( !m_aSetting.Name.isEmpty() )
+ {
+ if ( m_bIsList && m_aInfoSequence.hasElements() )
+ m_aSetting.Value <<= m_aInfoSequence;
+
+ // if our property is of type string, but was empty, ensure that
+ // we don't add a VOID value
+ if ( !m_bIsList && ( m_aPropType.getTypeClass() == TypeClass_STRING ) && !m_aSetting.Value.hasValue() )
+ m_aSetting.Value <<= OUString();
+
+ GetOwnImport().addInfo(m_aSetting);
+ }
+}
+
+void OXMLDataSourceSetting::characters( const OUString& rChars )
+{
+ if ( m_pContainer )
+ m_pContainer->addValue(rChars);
+}
+
+void OXMLDataSourceSetting::addValue(const OUString& _sValue)
+{
+ Any aValue;
+ if( TypeClass_VOID != m_aPropType.getTypeClass() )
+ aValue = convertString(m_aPropType, _sValue);
+
+ if ( !m_bIsList )
+ m_aSetting.Value = aValue;
+ else
+ {
+ sal_Int32 nPos = m_aInfoSequence.getLength();
+ m_aInfoSequence.realloc(nPos+1);
+ m_aInfoSequence.getArray()[nPos] = aValue;
+ }
+}
+
+ODBFilter& OXMLDataSourceSetting::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+Any OXMLDataSourceSetting::convertString(const css::uno::Type& _rExpectedType, const OUString& _rReadCharacters)
+{
+ Any aReturn;
+ switch (_rExpectedType.getTypeClass())
+ {
+ case TypeClass_BOOLEAN: // sal_Bool
+ {
+ bool bValue(false);
+ bool const bSuccess =
+ ::sax::Converter::convertBool(bValue, _rReadCharacters);
+ SAL_WARN_IF(!bSuccess, "dbaccess",
+ "OXMLDataSourceSetting::convertString: could not convert \""
+ << _rReadCharacters << "\" into a boolean!");
+ aReturn <<= bValue;
+ }
+ break;
+ case TypeClass_SHORT: // sal_Int16
+ case TypeClass_LONG: // sal_Int32
+ { // it's a real int32/16 property
+ sal_Int32 nValue(0);
+ bool const bSuccess =
+ ::sax::Converter::convertNumber(nValue, _rReadCharacters);
+ SAL_WARN_IF(!bSuccess, "dbaccess",
+ "OXMLDataSourceSetting::convertString: could not convert \""
+ << _rReadCharacters << "\" into an integer!");
+ if (TypeClass_SHORT == _rExpectedType.getTypeClass())
+ aReturn <<= static_cast<sal_Int16>(nValue);
+ else
+ aReturn <<= nValue;
+ break;
+ }
+ case TypeClass_HYPER:
+ {
+ OSL_FAIL("OXMLDataSourceSetting::convertString: 64-bit integers not implemented yet!");
+ }
+ break;
+ case TypeClass_DOUBLE:
+ {
+ double nValue = 0.0;
+ bool const bSuccess =
+ ::sax::Converter::convertDouble(nValue, _rReadCharacters);
+ SAL_WARN_IF(!bSuccess, "dbaccess",
+ "OXMLDataSourceSetting::convertString: could not convert \""
+ << _rReadCharacters << "\" into a double!");
+ aReturn <<= nValue;
+ }
+ break;
+ case TypeClass_STRING:
+ aReturn <<= _rReadCharacters;
+ break;
+ default:
+ SAL_WARN("dbaccess",
+ "OXMLDataSourceSetting::convertString: invalid type class!");
+ }
+
+ return aReturn;
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSourceSetting.hxx b/dbaccess/source/filter/xml/xmlDataSourceSetting.hxx
new file mode 100644
index 000000000..3ed92f80e
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSourceSetting.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLDataSourceSetting : public SvXMLImportContext
+ {
+ css::beans::PropertyValue m_aSetting;
+ css::uno::Sequence< css::uno::Any> m_aInfoSequence;
+ OXMLDataSourceSetting* m_pContainer;
+ css::uno::Type m_aPropType; // the type of the property the instance imports currently
+ bool m_bIsList;
+
+ ODBFilter& GetOwnImport();
+ static css::uno::Any convertString(const css::uno::Type& _rExpectedType, const OUString& _rReadCharacters);
+ public:
+
+ OXMLDataSourceSetting( ODBFilter& rImport
+ ,const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList
+ ,OXMLDataSourceSetting* _pContainer = nullptr);
+ virtual ~OXMLDataSourceSetting() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ virtual void SAL_CALL characters( const OUString& rChars ) override;
+
+ /** adds value to property
+ @param _sValue
+ The value to add.
+ */
+ void addValue(const OUString& _sValue);
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSourceSettings.cxx b/dbaccess/source/filter/xml/xmlDataSourceSettings.cxx
new file mode 100644
index 000000000..49847ef54
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSourceSettings.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlDataSourceSettings.hxx"
+#include "xmlDataSourceSetting.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLDataSourceSettings::OXMLDataSourceSettings( ODBFilter& rImport ) :
+ SvXMLImportContext( rImport )
+{
+
+}
+
+OXMLDataSourceSettings::~OXMLDataSourceSettings()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLDataSourceSettings::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_DATA_SOURCE_SETTING:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSourceSetting( GetOwnImport(), xAttrList );
+ break;
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLDataSourceSettings::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDataSourceSettings.hxx b/dbaccess/source/filter/xml/xmlDataSourceSettings.hxx
new file mode 100644
index 000000000..50fea5c00
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDataSourceSettings.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLDataSourceSettings : public SvXMLImportContext
+ {
+ ODBFilter& GetOwnImport();
+ public:
+
+ OXMLDataSourceSettings( ODBFilter& rImport );
+ virtual ~OXMLDataSourceSettings() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDatabase.cxx b/dbaccess/source/filter/xml/xmlDatabase.cxx
new file mode 100644
index 000000000..2f629caff
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDatabase.cxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlDatabase.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlDataSource.hxx"
+#include "xmlDocuments.hxx"
+#include "xmlEnums.hxx"
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <strings.hxx>
+#include <connectivity/dbtools.hxx>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLDatabase::OXMLDatabase( ODBFilter& rImport ) :
+ SvXMLImportContext( rImport )
+{
+
+}
+
+OXMLDatabase::~OXMLDatabase()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLDatabase::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_DATA_SOURCE:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLDataSource( GetOwnImport(), xAttrList, OXMLDataSource::eDataSource );
+ break;
+ case XML_FORMS:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ Any aValue;
+ OUString sService;
+ dbtools::getDataSourceSetting(GetOwnImport().getDataSource(),"Forms",aValue);
+ aValue >>= sService;
+ if ( sService.isEmpty() )
+ {
+ Reference<XFormDocumentsSupplier> xSup(GetOwnImport().GetModel(),UNO_QUERY);
+ if ( xSup.is() )
+ pContext = new OXMLDocuments( GetOwnImport(), xSup->getFormDocuments(),SERVICE_NAME_FORM_COLLECTION,SERVICE_SDB_DOCUMENTDEFINITION);
+ }
+ }
+ break;
+ case XML_REPORTS:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ Any aValue;
+ OUString sService;
+ dbtools::getDataSourceSetting(GetOwnImport().getDataSource(),"Reports",aValue);
+ aValue >>= sService;
+ if ( sService.isEmpty() )
+ {
+ Reference<XReportDocumentsSupplier> xSup(GetOwnImport().GetModel(),UNO_QUERY);
+ if ( xSup.is() )
+ pContext = new OXMLDocuments( GetOwnImport(), xSup->getReportDocuments(),SERVICE_NAME_REPORT_COLLECTION,SERVICE_SDB_DOCUMENTDEFINITION);
+ }
+ }
+ break;
+ case XML_QUERIES:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ Any aValue;
+ OUString sService;
+ dbtools::getDataSourceSetting(GetOwnImport().getDataSource(),"CommandDefinitions",aValue);
+ aValue >>= sService;
+ if ( sService.isEmpty() )
+ {
+ Reference<XQueryDefinitionsSupplier> xSup(GetOwnImport().getDataSource(),UNO_QUERY);
+ if ( xSup.is() )
+ pContext = new OXMLDocuments( GetOwnImport(), xSup->getQueryDefinitions(),SERVICE_NAME_QUERY_COLLECTION);
+ }
+ }
+ break;
+ case XML_TABLE_REPRESENTATIONS:
+ case XML_SCHEMA_DEFINITION:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ Reference<XTablesSupplier> xSup(GetOwnImport().getDataSource(),UNO_QUERY);
+ if ( xSup.is() )
+ pContext = new OXMLDocuments( GetOwnImport(), xSup->getTables());
+ }
+ break;
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLDatabase::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+void OXMLDatabase::endFastElement(sal_Int32)
+{
+ GetOwnImport().setPropertyInfo();
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDatabase.hxx b/dbaccess/source/filter/xml/xmlDatabase.hxx
new file mode 100644
index 000000000..0dab56c51
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDatabase.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLDatabase final : public SvXMLImportContext
+ {
+ ODBFilter& GetOwnImport();
+ public:
+
+ OXMLDatabase( ODBFilter& rImport );
+ virtual ~OXMLDatabase() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDatabaseDescription.cxx b/dbaccess/source/filter/xml/xmlDatabaseDescription.cxx
new file mode 100644
index 000000000..a8168e129
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDatabaseDescription.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlDatabaseDescription.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+#include "xmlFileBasedDatabase.hxx"
+#include "xmlServerDatabase.hxx"
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLDatabaseDescription::OXMLDatabaseDescription( ODBFilter& rImport ) :
+ SvXMLImportContext( rImport )
+ ,m_bFoundOne(false)
+{
+}
+
+OXMLDatabaseDescription::~OXMLDatabaseDescription()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLDatabaseDescription::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_FILE_BASED_DATABASE:
+ if ( !m_bFoundOne )
+ {
+ m_bFoundOne = true;
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLFileBasedDatabase( GetOwnImport(), xAttrList );
+ }
+ break;
+ case XML_SERVER_DATABASE:
+ if ( !m_bFoundOne )
+ {
+ m_bFoundOne = true;
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLServerDatabase( GetOwnImport(), xAttrList );
+ }
+ break;
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLDatabaseDescription::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDatabaseDescription.hxx b/dbaccess/source/filter/xml/xmlDatabaseDescription.hxx
new file mode 100644
index 000000000..146ecb401
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDatabaseDescription.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLDatabaseDescription : public SvXMLImportContext
+ {
+ bool m_bFoundOne;
+
+ ODBFilter& GetOwnImport();
+ public:
+
+ OXMLDatabaseDescription( ODBFilter& rImport);
+ virtual ~OXMLDatabaseDescription() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDocuments.cxx b/dbaccess/source/filter/xml/xmlDocuments.cxx
new file mode 100644
index 000000000..71d5b4589
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDocuments.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlDocuments.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlQuery.hxx"
+#include "xmlTable.hxx"
+#include "xmlComponent.hxx"
+#include "xmlHierarchyCollection.hxx"
+#include "xmlEnums.hxx"
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLDocuments::OXMLDocuments( ODBFilter& rImport
+ ,const Reference< XNameAccess >& _xContainer
+ ,const OUString& _sCollectionServiceName
+ ,const OUString& _sComponentServiceName) :
+ SvXMLImportContext( rImport )
+ ,m_xContainer(_xContainer)
+ ,m_sCollectionServiceName(_sCollectionServiceName)
+ ,m_sComponentServiceName(_sComponentServiceName)
+{
+
+}
+
+OXMLDocuments::OXMLDocuments( ODBFilter& rImport
+ ,const Reference< XNameAccess >& _xContainer
+ ,const OUString& _sCollectionServiceName
+ ) :
+ SvXMLImportContext( rImport )
+ ,m_xContainer(_xContainer)
+ ,m_sCollectionServiceName(_sCollectionServiceName)
+{
+}
+
+OXMLDocuments::~OXMLDocuments()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLDocuments::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_TABLE:
+ case XML_TABLE_REPRESENTATION:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLTable( GetOwnImport(), xAttrList, m_xContainer, "com.sun.star.sdb.TableDefinition");
+ break;
+ case XML_QUERY:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLQuery( GetOwnImport(), xAttrList, m_xContainer );
+ break;
+ case XML_COMPONENT:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLComponent( GetOwnImport(), xAttrList, m_xContainer,m_sComponentServiceName );
+ break;
+ case XML_COMPONENT_COLLECTION:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLHierarchyCollection( GetOwnImport(), xAttrList, m_xContainer,m_sCollectionServiceName,m_sComponentServiceName );
+ break;
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLDocuments::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlDocuments.hxx b/dbaccess/source/filter/xml/xmlDocuments.hxx
new file mode 100644
index 000000000..c0542dcfb
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlDocuments.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLDocuments : public SvXMLImportContext
+ {
+ private:
+ css::uno::Reference< css::container::XNameAccess > m_xContainer;
+ OUString m_sCollectionServiceName;
+ OUString m_sComponentServiceName;
+
+ ODBFilter& GetOwnImport();
+ public:
+
+ // for forms and reports
+ OXMLDocuments( ODBFilter& rImport
+ ,const css::uno::Reference< css::container::XNameAccess >& _xContainer
+ ,const OUString& _sCollectionServiceName
+ ,const OUString& _sComponentServiceName);
+
+ // for queries
+ OXMLDocuments( ODBFilter& rImport
+ ,const css::uno::Reference< css::container::XNameAccess >& _xContainer
+ ,const OUString& _sCollectionServiceName = OUString()
+ );
+
+ virtual ~OXMLDocuments() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlEnums.hxx b/dbaccess/source/filter/xml/xmlEnums.hxx
new file mode 100644
index 000000000..552f7eb24
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlEnums.hxx
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#define PROGRESS_BAR_STEP 20
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlExport.cxx b/dbaccess/source/filter/xml/xmlExport.cxx
new file mode 100644
index 000000000..74cb97721
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlExport.cxx
@@ -0,0 +1,1342 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlExport.hxx"
+#include "xmlAutoStyle.hxx"
+#include <sax/tools/converter.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/types.hxx>
+#include <strings.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <xmloff/xmluconv.hxx>
+#include "xmlHelper.hxx"
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <svl/filenotation.hxx>
+#include <unotools/pathoptions.hxx>
+#include <tools/diagnose_ex.h>
+#include <connectivity/DriversConfig.hxx>
+#include <connectivity/dbtools.hxx>
+
+#include <optional>
+#include <memory>
+
+using namespace comphelper;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sdb_DBExportFilter_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ::dbaxml::ODBExport(context,
+ "com.sun.star.comp.sdb.DBExportFilter"));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sdb_XMLSettingsExporter_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ::dbaxml::ODBExport(context,
+ "com.sun.star.comp.sdb.XMLSettingsExporter",
+ SvXMLExportFlags::SETTINGS | SvXMLExportFlags::PRETTY ));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sdb_XMLFullExporter_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ::dbaxml::ODBExport(context,
+ "com.sun.star.comp.sdb.XMLFullExporter",
+ SvXMLExportFlags::ALL));
+}
+
+namespace dbaxml
+{
+ static OUString lcl_implGetPropertyXMLType(const Type& _rType)
+ {
+ // possible types we can write (either because we recognize them directly or because we convert _rValue
+ // into one of these types)
+
+ // handle the type description
+ switch (_rType.getTypeClass())
+ {
+ case TypeClass_STRING:
+ return "string";
+ case TypeClass_DOUBLE:
+ return "double";
+ case TypeClass_BOOLEAN:
+ return "boolean";
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ return "short";
+ case TypeClass_LONG:
+ return "int";
+ case TypeClass_HYPER:
+ return "long";
+ case TypeClass_ENUM:
+ return "int";
+
+ default:
+ OSL_FAIL( "lcl_implGetPropertyXMLType: unsupported value type!" );
+ return "double";
+ }
+ }
+
+ namespace {
+
+ class OSpecialHandleXMLExportPropertyMapper : public SvXMLExportPropertyMapper
+ {
+ public:
+ explicit OSpecialHandleXMLExportPropertyMapper(const rtl::Reference< XMLPropertySetMapper >& rMapper) : SvXMLExportPropertyMapper(rMapper )
+ {
+ }
+ /** this method is called for every item that has the
+ MID_FLAG_SPECIAL_ITEM_EXPORT flag set */
+ virtual void handleSpecialItem(
+ SvXMLAttributeList& /*rAttrList*/,
+ const XMLPropertyState& /*rProperty*/,
+ const SvXMLUnitConverter& /*rUnitConverter*/,
+ const SvXMLNamespaceMap& /*rNamespaceMap*/,
+ const std::vector< XMLPropertyState > * /*pProperties*/ ,
+ sal_uInt32 /*nIdx*/ ) const override
+ {
+ // nothing to do here
+ }
+ };
+
+ }
+
+ODBExport::ODBExport(const Reference< XComponentContext >& _rxContext, OUString const & implementationName, SvXMLExportFlags nExportFlag)
+: SvXMLExport( _rxContext, implementationName, util::MeasureUnit::MM_10TH, XML_DATABASE,
+ SvXMLExportFlags::OASIS | nExportFlag)
+,m_aTypeCollection(_rxContext)
+,m_bAllreadyFilled(false)
+{
+ GetMM100UnitConverter().SetCoreMeasureUnit(util::MeasureUnit::MM_10TH);
+ GetMM100UnitConverter().SetXMLMeasureUnit(util::MeasureUnit::CM);
+
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE );
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO );
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG );
+
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_DB), GetXMLToken(XML_N_DB_OASIS), XML_NAMESPACE_DB );
+
+ if( nExportFlag & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS) )
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO );
+
+ if( nExportFlag & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::SETTINGS) )
+ {
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK );
+ }
+ if( nExportFlag & SvXMLExportFlags::SETTINGS )
+ {
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG );
+ }
+
+ if( nExportFlag & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::FONTDECLS) )
+ {
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE );
+ }
+
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE );
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_NUMBER), GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER );
+
+ m_xExportHelper = new SvXMLExportPropertyMapper(GetTableStylesPropertySetMapper());
+ m_xColumnExportHelper = new OSpecialHandleXMLExportPropertyMapper(GetColumnStylesPropertySetMapper());
+
+ m_xCellExportHelper = new OSpecialHandleXMLExportPropertyMapper(GetCellStylesPropertySetMapper());
+ m_xRowExportHelper = new OSpecialHandleXMLExportPropertyMapper(OXMLHelper::GetRowStylesPropertySetMapper());
+
+ GetAutoStylePool()->AddFamily(
+ XmlStyleFamily::TABLE_TABLE,
+ OUString(XML_STYLE_FAMILY_TABLE_TABLE_STYLES_NAME ),
+ m_xExportHelper.get(),
+ OUString(XML_STYLE_FAMILY_TABLE_TABLE_STYLES_PREFIX ));
+
+ GetAutoStylePool()->AddFamily(
+ XmlStyleFamily::TABLE_COLUMN,
+ OUString(XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME ),
+ m_xColumnExportHelper.get(),
+ OUString(XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX ));
+
+ GetAutoStylePool()->AddFamily(
+ XmlStyleFamily::TABLE_CELL,
+ OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME ),
+ m_xCellExportHelper.get(),
+ OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX ));
+
+ GetAutoStylePool()->AddFamily(
+ XmlStyleFamily::TABLE_ROW,
+ OUString(XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME ),
+ m_xRowExportHelper.get(),
+ OUString(XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX ));
+}
+
+void ODBExport::exportDataSource()
+{
+ try
+ {
+ Reference<XPropertySet> xProp( getDataSource(), UNO_SET_THROW );
+
+ bool bAutoIncrementEnabled = true;
+ TStringPair aAutoIncrement;
+
+ Reference< XPropertySet > xDataSourceSettings;
+ OSL_VERIFY( xProp->getPropertyValue( PROPERTY_SETTINGS ) >>= xDataSourceSettings );
+ Reference< XPropertyState > xSettingsState( xDataSourceSettings, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xSettingsInfo( xDataSourceSettings->getPropertySetInfo(), UNO_SET_THROW );
+
+ TDelimiter aDelimiter;
+ xSettingsState->getPropertyDefault( INFO_TEXTDELIMITER ) >>= aDelimiter.sText;
+ xSettingsState->getPropertyDefault( INFO_FIELDDELIMITER ) >>= aDelimiter.sField;
+ xSettingsState->getPropertyDefault( INFO_DECIMALDELIMITER ) >>= aDelimiter.sDecimal;
+ xSettingsState->getPropertyDefault( INFO_THOUSANDSDELIMITER ) >>= aDelimiter.sThousand;
+
+ ::connectivity::DriversConfig aDriverConfig(getComponentContext());
+ const OUString sURL = ::comphelper::getString(xProp->getPropertyValue(PROPERTY_URL));
+ const ::comphelper::NamedValueCollection& aDriverSupportedProperties( aDriverConfig.getProperties( sURL ) );
+
+ static OUString s_sTrue(::xmloff::token::GetXMLToken( XML_TRUE ));
+ static OUString s_sFalse(::xmloff::token::GetXMLToken( XML_FALSE ));
+ // loop through the properties, and export only those which are not defaulted
+ TSettingsMap aSettingsMap;
+ // Don't try to get XPropertySetInfo from xProp, simply wrap the attempt into try block
+ try
+ {
+ const Any aValue = xProp->getPropertyValue(PROPERTY_SUPPRESSVERSIONCL);
+ if (!getBOOL(aValue)) // default in the XML schema is true -> only write false
+ aSettingsMap.emplace(XML_SUPPRESS_VERSION_COLUMNS, s_sFalse);
+ }
+ catch (const UnknownPropertyException&)
+ {
+ }
+
+ Sequence< Property > aProperties = xSettingsInfo->getProperties();
+ const Property* pProperties = aProperties.getConstArray();
+ const Property* pPropertiesEnd = pProperties + aProperties.getLength();
+ for ( ; pProperties != pPropertiesEnd; ++pProperties )
+ {
+ OUString sValue;
+ Any aValue = xDataSourceSettings->getPropertyValue( pProperties->Name );
+ switch ( aValue.getValueTypeClass() )
+ {
+ case TypeClass_STRING:
+ aValue >>= sValue;
+ break;
+ case TypeClass_DOUBLE:
+ // let the unit converter format is as string
+ sValue = OUString::number( getDouble( aValue ) );
+ break;
+ case TypeClass_BOOLEAN:
+ sValue = ::xmloff::token::GetXMLToken( getBOOL( aValue ) ? XML_TRUE : XML_FALSE );
+ break;
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_LONG:
+ // let the unit converter format is as string
+ sValue = OUString::number( getINT32( aValue ) );
+ break;
+ default:
+ break;
+ }
+
+ ::xmloff::token::XMLTokenEnum eToken = XML_TOKEN_INVALID;
+
+ struct PropertyMap
+ {
+ const OUString sPropertyName;
+ const XMLTokenEnum eAttributeToken;
+ const ::std::optional< OUString > aXMLDefault;
+
+ PropertyMap( const OUString& _rPropertyName, const XMLTokenEnum _eToken )
+ :sPropertyName( _rPropertyName )
+ ,eAttributeToken( _eToken )
+ ,aXMLDefault()
+ {
+ }
+
+ PropertyMap( const OUString& _rPropertyName, const XMLTokenEnum _eToken, const OUString& _rDefault )
+ :sPropertyName( _rPropertyName )
+ ,eAttributeToken( _eToken )
+ ,aXMLDefault( _rDefault )
+ {
+ }
+ };
+
+ const PropertyMap aTokens[] =
+ {
+ PropertyMap( INFO_TEXTFILEHEADER, XML_IS_FIRST_ROW_HEADER_LINE, s_sTrue ),
+ PropertyMap( INFO_SHOWDELETEDROWS, XML_SHOW_DELETED, s_sFalse ),
+ PropertyMap( INFO_ALLOWLONGTABLENAMES, XML_IS_TABLE_NAME_LENGTH_LIMITED, s_sTrue ),
+ PropertyMap( INFO_ADDITIONALOPTIONS, XML_SYSTEM_DRIVER_SETTINGS ),
+ PropertyMap( PROPERTY_ENABLESQL92CHECK, XML_ENABLE_SQL92_CHECK, s_sFalse ),
+ PropertyMap( INFO_APPEND_TABLE_ALIAS, XML_APPEND_TABLE_ALIAS_NAME, s_sTrue ),
+ PropertyMap( INFO_PARAMETERNAMESUBST, XML_PARAMETER_NAME_SUBSTITUTION, s_sTrue ),
+ PropertyMap( INFO_IGNOREDRIVER_PRIV, XML_IGNORE_DRIVER_PRIVILEGES, s_sTrue ),
+ PropertyMap( INFO_USECATALOG, XML_USE_CATALOG, s_sFalse ),
+ PropertyMap( INFO_CONN_LDAP_BASEDN, XML_BASE_DN ),
+ PropertyMap( INFO_CONN_LDAP_ROWCOUNT, XML_MAX_ROW_COUNT )
+ };
+
+ bool bIsXMLDefault = false;
+ for (const auto & aToken : aTokens)
+ {
+ if ( pProperties->Name == aToken.sPropertyName )
+ {
+ eToken = aToken.eAttributeToken;
+
+ if ( !!aToken.aXMLDefault
+ && ( sValue == *aToken.aXMLDefault )
+ )
+ {
+ bIsXMLDefault = true;
+ }
+ break;
+ }
+ }
+
+ if ( bIsXMLDefault )
+ // the property has the value which is specified as default in the XML schema -> no need to write it
+ continue;
+
+ if ( eToken == XML_TOKEN_INVALID )
+ {
+ // for properties which are not REMOVABLE, we care for their state, and
+ // only export them if they're not DEFAULTed
+ if ( ( pProperties->Attributes & PropertyAttribute::REMOVABLE ) == 0 )
+ {
+ PropertyState ePropertyState = xSettingsState->getPropertyState( pProperties->Name );
+ if ( PropertyState_DEFAULT_VALUE == ePropertyState )
+ continue;
+ }
+
+ // special handlings
+ if ( pProperties->Name == PROPERTY_BOOLEANCOMPARISONMODE )
+ {
+ if ( sValue == "0" )
+ sValue = "equal-integer";
+ else if ( sValue == "1" )
+ sValue = "is-boolean";
+ else if ( sValue == "2" )
+ sValue = "equal-boolean";
+ else if ( sValue == "3" )
+ sValue = "equal-use-only-zero";
+ if ( sValue == "equal-integer" )
+ continue;
+ eToken = XML_BOOLEAN_COMPARISON_MODE;
+ }
+ else if ( pProperties->Name == INFO_AUTORETRIEVEENABLED )
+ {
+ aValue >>= bAutoIncrementEnabled;
+ continue;
+ }
+ else if ( pProperties->Name == INFO_AUTORETRIEVEVALUE )
+ {
+ aAutoIncrement.first = sValue;
+ continue;
+ }
+ else if ( pProperties->Name == PROPERTY_AUTOINCREMENTCREATION )
+ {
+ aAutoIncrement.second = sValue;
+ continue;
+ }
+ else if ( pProperties->Name == INFO_TEXTDELIMITER )
+ {
+ aDelimiter.sText = sValue;
+ aDelimiter.bUsed = true;
+ continue;
+ }
+ else if ( pProperties->Name == INFO_FIELDDELIMITER )
+ {
+ aDelimiter.sField = sValue;
+ aDelimiter.bUsed = true;
+ continue;
+ }
+ else if ( pProperties->Name == INFO_DECIMALDELIMITER )
+ {
+ aDelimiter.sDecimal = sValue;
+ aDelimiter.bUsed = true;
+ continue;
+ }
+ else if ( pProperties->Name == INFO_THOUSANDSDELIMITER )
+ {
+ aDelimiter.sThousand = sValue;
+ aDelimiter.bUsed = true;
+ continue;
+ }
+ else if ( pProperties->Name == INFO_CHARSET )
+ {
+ m_sCharSet = sValue;
+ continue;
+ }
+ else
+ {
+ if ( !aDriverSupportedProperties.has(pProperties->Name) || aDriverSupportedProperties.get(pProperties->Name) != aValue )
+ {
+ m_aDataSourceSettings.emplace_back(
+ pProperties->Name, pProperties->Type, aValue );
+ }
+ continue;
+ }
+ }
+
+ aSettingsMap.emplace(eToken,sValue);
+ }
+ if ( bAutoIncrementEnabled && !(aAutoIncrement.first.isEmpty() && aAutoIncrement.second.isEmpty()) )
+ m_aAutoIncrement.reset( new TStringPair(aAutoIncrement));
+ if ( aDelimiter.bUsed )
+ m_aDelimiter.reset( new TDelimiter( aDelimiter ) );
+
+ SvXMLElementExport aElem(*this, XML_NAMESPACE_DB, XML_DATA_SOURCE, true, true);
+
+ exportConnectionData();
+ exportDriverSettings(aSettingsMap);
+ exportApplicationConnectionSettings(aSettingsMap);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODBExport::exportApplicationConnectionSettings(const TSettingsMap& _aSettings)
+{
+ const ::xmloff::token::XMLTokenEnum pSettings[] = {
+ XML_IS_TABLE_NAME_LENGTH_LIMITED
+ ,XML_ENABLE_SQL92_CHECK
+ ,XML_APPEND_TABLE_ALIAS_NAME
+ ,XML_IGNORE_DRIVER_PRIVILEGES
+ ,XML_BOOLEAN_COMPARISON_MODE
+ ,XML_USE_CATALOG
+ ,XML_MAX_ROW_COUNT
+ ,XML_SUPPRESS_VERSION_COLUMNS
+ };
+ for (::xmloff::token::XMLTokenEnum i : pSettings)
+ {
+ TSettingsMap::const_iterator aFind = _aSettings.find(i);
+ if ( aFind != _aSettings.end() )
+ AddAttribute(XML_NAMESPACE_DB, aFind->first,aFind->second);
+ }
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_APPLICATION_CONNECTION_SETTINGS, true, true);
+
+ Reference<XPropertySet> xProp(getDataSource());
+ Sequence< OUString> aValue;
+ xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= aValue;
+ if ( aValue.hasElements() )
+ {
+ SvXMLElementExport aElem2(*this,XML_NAMESPACE_DB, XML_TABLE_FILTER, true, true);
+ exportSequence(aValue,XML_TABLE_INCLUDE_FILTER,XML_TABLE_FILTER_PATTERN);
+ }
+
+ xProp->getPropertyValue(PROPERTY_TABLETYPEFILTER) >>= aValue;
+ if ( aValue.hasElements() )
+ exportSequence(aValue,XML_TABLE_TYPE_FILTER,XML_TABLE_TYPE);
+
+ exportDataSourceSettings();
+}
+
+void ODBExport::exportDriverSettings(const TSettingsMap& _aSettings)
+{
+ const ::xmloff::token::XMLTokenEnum pSettings[] = {
+ XML_SHOW_DELETED
+ ,XML_SYSTEM_DRIVER_SETTINGS
+ ,XML_BASE_DN
+ ,XML_IS_FIRST_ROW_HEADER_LINE
+ ,XML_PARAMETER_NAME_SUBSTITUTION
+ };
+ for (::xmloff::token::XMLTokenEnum nSetting : pSettings)
+ {
+ TSettingsMap::const_iterator aFind = _aSettings.find(nSetting);
+ if ( aFind != _aSettings.end() )
+ AddAttribute(XML_NAMESPACE_DB, aFind->first,aFind->second);
+ }
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_DRIVER_SETTINGS, true, true);
+ exportAutoIncrement();
+ exportDelimiter();
+ exportCharSet();
+}
+
+void ODBExport::exportConnectionData()
+{
+ SvXMLElementExport aConnData(*this,XML_NAMESPACE_DB, XML_CONNECTION_DATA, true, true);
+
+ {
+ OUString sValue;
+ Reference<XPropertySet> xProp(getDataSource());
+ xProp->getPropertyValue(PROPERTY_URL) >>= sValue;
+ if ( m_aTypeCollection.isFileSystemBased(sValue) )
+ {
+ SvXMLElementExport aDatabaseDescription(*this,XML_NAMESPACE_DB, XML_DATABASE_DESCRIPTION, true, true);
+ {
+ SvtPathOptions aPathOptions;
+ const OUString sOrigUrl = m_aTypeCollection.cutPrefix(sValue);
+ OUString sFileName = aPathOptions.SubstituteVariable(sOrigUrl);
+ if ( sOrigUrl == sFileName )
+ {
+ ::svt::OFileNotation aTransformer( sFileName );
+ OUStringBuffer sURL( aTransformer.get( ::svt::OFileNotation::N_URL ) );
+ if (sURL.isEmpty() || sURL[sURL.getLength() - 1] != '/')
+ sURL.append('/');
+
+ AddAttribute(XML_NAMESPACE_XLINK,XML_HREF,GetRelativeReference(sURL.makeStringAndClear()));
+ }
+ else
+ AddAttribute(XML_NAMESPACE_XLINK,XML_HREF,sOrigUrl);
+ AddAttribute(XML_NAMESPACE_DB,XML_MEDIA_TYPE,m_aTypeCollection.getMediaType(sValue));
+ const ::dbaccess::DATASOURCE_TYPE eType = m_aTypeCollection.determineType(sValue);
+ try
+ {
+ OUString sExtension;
+ if ( eType == dbaccess::DST_MSACCESS )
+ sExtension = "mdb";
+ else
+ {
+ Reference< XPropertySet > xDataSourceSettings;
+ OSL_VERIFY( xProp->getPropertyValue( PROPERTY_SETTINGS ) >>= xDataSourceSettings );
+ xDataSourceSettings->getPropertyValue( INFO_TEXTFILEEXTENSION ) >>= sExtension;
+ }
+ if ( !sExtension.isEmpty() )
+ AddAttribute(XML_NAMESPACE_DB,XML_EXTENSION,sExtension);
+ }
+ catch(const Exception&)
+ {
+ }
+ SvXMLElementExport aFileBasedDB(*this,XML_NAMESPACE_DB, XML_FILE_BASED_DATABASE, true, true);
+ }
+ }
+ else
+ {
+ OUString sDatabaseName,sHostName;
+ sal_Int32 nPort = -1;
+ m_aTypeCollection.extractHostNamePort(sValue,sDatabaseName,sHostName,nPort);
+ if ( sHostName.getLength() )
+ {
+ SvXMLElementExport aDatabaseDescription(*this,XML_NAMESPACE_DB, XML_DATABASE_DESCRIPTION, true, true);
+ {
+ OUString sType = comphelper::string::stripEnd(m_aTypeCollection.getPrefix(sValue), ':');
+ AddAttribute(XML_NAMESPACE_DB,XML_TYPE,sType);
+ AddAttribute(XML_NAMESPACE_DB,XML_HOSTNAME,sHostName);
+ if ( nPort != -1 )
+ AddAttribute(XML_NAMESPACE_DB,XML_PORT,OUString::number(nPort));
+ if ( sDatabaseName.getLength() )
+ AddAttribute(XML_NAMESPACE_DB,XML_DATABASE_NAME,sDatabaseName);
+
+ try
+ {
+ Reference< XPropertySet > xDataSourceSettings( xProp->getPropertyValue( PROPERTY_SETTINGS ), UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xSettingsInfo( xDataSourceSettings->getPropertySetInfo(), UNO_SET_THROW );
+
+
+ static const OUStringLiteral sPropertyName = u"LocalSocket";
+ if ( xSettingsInfo->hasPropertyByName( sPropertyName ) )
+ {
+ OUString sPropertyValue;
+ if ( ( xDataSourceSettings->getPropertyValue( sPropertyName ) >>= sPropertyValue ) && !sPropertyValue.isEmpty() )
+ AddAttribute( XML_NAMESPACE_DB, XML_LOCAL_SOCKET, sPropertyValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ SvXMLElementExport aServerDB(*this,XML_NAMESPACE_DB, XML_SERVER_DATABASE, true, true);
+ }
+ }
+ else
+ {
+ AddAttribute(XML_NAMESPACE_XLINK, XML_HREF,sValue);
+ AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_CONNECTION_RESOURCE, true, true);
+ }
+ }
+
+ }
+
+ exportLogin();
+}
+
+template< typename T > void ODBExport::exportDataSourceSettingsSequence(
+ std::vector< TypedPropertyValue >::iterator const & in)
+{
+ css::uno::Sequence<T> anySeq;
+ bool bSuccess = in->Value >>= anySeq;
+ assert(bSuccess); (void)bSuccess;
+ for (T const & i : std::as_const(anySeq) )
+ {
+ SvXMLElementExport aDataValue(*this,XML_NAMESPACE_DB, XML_DATA_SOURCE_SETTING_VALUE, true, false);
+ // (no whitespace inside the tag)
+ Characters(implConvertAny(css::uno::Any(i)));
+ }
+}
+
+void ODBExport::exportDataSourceSettings()
+{
+ if ( m_aDataSourceSettings.empty() )
+ return;
+
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_DATA_SOURCE_SETTINGS, true, true);
+ std::vector< TypedPropertyValue >::iterator aIter = m_aDataSourceSettings.begin();
+ std::vector< TypedPropertyValue >::const_iterator aEnd = m_aDataSourceSettings.end();
+ for ( ; aIter != aEnd; ++aIter )
+ {
+ const bool bIsSequence = TypeClass_SEQUENCE == aIter->Type.getTypeClass();
+
+ Type aSimpleType(bIsSequence ? comphelper::getSequenceElementType(aIter->Value.getValueType()) : aIter->Type);
+
+ AddAttribute( XML_NAMESPACE_DB, XML_DATA_SOURCE_SETTING_IS_LIST,bIsSequence ? XML_TRUE : XML_FALSE );
+ AddAttribute( XML_NAMESPACE_DB, XML_DATA_SOURCE_SETTING_NAME, aIter->Name );
+
+ OUString sTypeName = lcl_implGetPropertyXMLType( aSimpleType );
+ if ( bIsSequence && aSimpleType.getTypeClass() == TypeClass_ANY )
+ {
+ Sequence<Any> aSeq;
+ aIter->Value >>= aSeq;
+ if ( aSeq.hasElements() )
+ sTypeName = lcl_implGetPropertyXMLType(aSeq[0].getValueType());
+ }
+
+ AddAttribute( XML_NAMESPACE_DB, XML_DATA_SOURCE_SETTING_TYPE, sTypeName );
+
+ SvXMLElementExport aDataSourceSetting( *this, XML_NAMESPACE_DB, XML_DATA_SOURCE_SETTING, true, true );
+
+ if ( !bIsSequence )
+ {
+ SvXMLElementExport aDataValue( *this, XML_NAMESPACE_DB, XML_DATA_SOURCE_SETTING_VALUE, true, false );
+ // (no whitespace inside the tag)
+ Characters( implConvertAny( aIter->Value ) );
+ }
+ else
+ {
+ // the not-that-simple case, we need to iterate through the sequence elements
+ switch (aSimpleType.getTypeClass())
+ {
+ case TypeClass_STRING:
+ exportDataSourceSettingsSequence< OUString >(
+ aIter );
+ break;
+ case TypeClass_DOUBLE:
+ exportDataSourceSettingsSequence< double >( aIter );
+ break;
+ case TypeClass_BOOLEAN:
+ exportDataSourceSettingsSequence< sal_Bool >( aIter );
+ break;
+ case TypeClass_BYTE:
+ exportDataSourceSettingsSequence< sal_Int8 >( aIter );
+ break;
+ case TypeClass_SHORT:
+ exportDataSourceSettingsSequence< sal_Int16 >( aIter );
+ break;
+ case TypeClass_LONG:
+ exportDataSourceSettingsSequence< sal_Int32 >( aIter );
+ break;
+ case TypeClass_ANY:
+ exportDataSourceSettingsSequence< Any >( aIter );
+ break;
+ default:
+ OSL_FAIL("unsupported sequence type !");
+ break;
+ }
+ }
+ }
+}
+
+void ODBExport::exportCharSet()
+{
+ if ( !m_sCharSet.isEmpty() )
+ {
+ AddAttribute(XML_NAMESPACE_DB, XML_ENCODING,m_sCharSet);
+
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_FONT_CHARSET, true, true);
+ }
+}
+
+void ODBExport::exportDelimiter()
+{
+ if ( m_aDelimiter && m_aDelimiter->bUsed )
+ {
+ AddAttribute(XML_NAMESPACE_DB, XML_FIELD,m_aDelimiter->sField);
+ AddAttribute(XML_NAMESPACE_DB, XML_STRING,m_aDelimiter->sText);
+ AddAttribute(XML_NAMESPACE_DB, XML_DECIMAL,m_aDelimiter->sDecimal);
+ AddAttribute(XML_NAMESPACE_DB, XML_THOUSAND,m_aDelimiter->sThousand);
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_DELIMITER, true, true);
+ }
+}
+
+void ODBExport::exportAutoIncrement()
+{
+ if (m_aAutoIncrement)
+ {
+ AddAttribute(XML_NAMESPACE_DB, XML_ADDITIONAL_COLUMN_STATEMENT,m_aAutoIncrement->second);
+ AddAttribute(XML_NAMESPACE_DB, XML_ROW_RETRIEVING_STATEMENT,m_aAutoIncrement->first);
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_AUTO_INCREMENT, true, true);
+ }
+}
+
+void ODBExport::exportSequence(const Sequence< OUString>& _aValue
+ ,::xmloff::token::XMLTokenEnum _eTokenFilter
+ ,::xmloff::token::XMLTokenEnum _eTokenType)
+{
+ if ( _aValue.hasElements() )
+ {
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, _eTokenFilter, true, true);
+
+ const OUString* pIter = _aValue.getConstArray();
+ const OUString* pEnd = pIter + _aValue.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ SvXMLElementExport aDataSource(*this,XML_NAMESPACE_DB, _eTokenType, true, false);
+ Characters(*pIter);
+ }
+ }
+}
+
+void ODBExport::exportLogin()
+{
+ Reference<XPropertySet> xProp(getDataSource());
+ OUString sValue;
+ xProp->getPropertyValue(PROPERTY_USER) >>= sValue;
+ bool bAddLogin = !sValue.isEmpty();
+ if ( bAddLogin )
+ AddAttribute(XML_NAMESPACE_DB, XML_USER_NAME,sValue);
+ bool bValue = false;
+ if ( xProp->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED) >>= bValue )
+ {
+ bAddLogin = true;
+ AddAttribute(XML_NAMESPACE_DB, XML_IS_PASSWORD_REQUIRED,bValue ? XML_TRUE : XML_FALSE);
+ }
+ if ( bAddLogin )
+ SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_LOGIN, true, true);
+}
+
+void ODBExport::exportCollection(const Reference< XNameAccess >& _xCollection
+ ,enum ::xmloff::token::XMLTokenEnum _eComponents
+ ,enum ::xmloff::token::XMLTokenEnum _eSubComponents
+ ,bool _bExportContext
+ ,const ::comphelper::mem_fun1_t<ODBExport,XPropertySet* >& _aMemFunc
+ )
+{
+ if ( !_xCollection.is() )
+ return;
+
+ std::unique_ptr<SvXMLElementExport> pComponents;
+ if ( _bExportContext )
+ pComponents.reset( new SvXMLElementExport(*this,XML_NAMESPACE_DB, _eComponents, true, true));
+ Sequence< OUString> aSeq = _xCollection->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ Reference<XPropertySet> xProp(_xCollection->getByName(*pIter),UNO_QUERY);
+ if ( _bExportContext && XML_TABLE_REPRESENTATIONS != _eComponents )
+ AddAttribute(XML_NAMESPACE_DB, XML_NAME,*pIter);
+ Reference< XNameAccess > xSub(xProp,UNO_QUERY);
+ if ( xSub.is() )
+ {
+ exportCollection(xSub,_eSubComponents,_eSubComponents,_bExportContext,_aMemFunc);
+ }
+ else if ( xProp.is() )
+ _aMemFunc(this,xProp.get());
+ }
+}
+
+void ODBExport::exportComponent(XPropertySet* _xProp)
+{
+ OUString sValue;
+ _xProp->getPropertyValue(PROPERTY_PERSISTENT_NAME) >>= sValue;
+ bool bIsForm = true;
+ _xProp->getPropertyValue("IsForm") >>= bIsForm;
+ if ( bIsForm )
+ sValue = "forms/" + sValue;
+ else
+ sValue = "reports/" + sValue;
+
+ AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sValue);
+ AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
+ bool bAsTemplate = false;
+ _xProp->getPropertyValue(PROPERTY_AS_TEMPLATE) >>= bAsTemplate;
+ AddAttribute(XML_NAMESPACE_DB, XML_AS_TEMPLATE,bAsTemplate ? XML_TRUE : XML_FALSE);
+ SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, XML_COMPONENT, true, true);
+}
+
+void ODBExport::exportQuery(XPropertySet* _xProp)
+{
+ AddAttribute(XML_NAMESPACE_DB, XML_COMMAND,getString(_xProp->getPropertyValue(PROPERTY_COMMAND)));
+
+ if ( getBOOL(_xProp->getPropertyValue(PROPERTY_APPLYFILTER)) )
+ AddAttribute(XML_NAMESPACE_DB, XML_APPLY_FILTER,XML_TRUE);
+
+ if ( _xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_APPLYORDER)
+ && getBOOL(_xProp->getPropertyValue(PROPERTY_APPLYORDER)) )
+ AddAttribute(XML_NAMESPACE_DB, XML_APPLY_ORDER,XML_TRUE);
+
+ if ( ! getBOOL(_xProp->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) )
+ AddAttribute(XML_NAMESPACE_DB, XML_ESCAPE_PROCESSING,XML_FALSE);
+
+ exportStyleName(_xProp,GetAttrList());
+
+ SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, XML_QUERY, true, true);
+ Reference<XColumnsSupplier> xCol(_xProp,UNO_QUERY);
+ exportColumns(xCol);
+ exportFilter(_xProp,PROPERTY_FILTER,XML_FILTER_STATEMENT);
+ exportFilter(_xProp,PROPERTY_ORDER,XML_ORDER_STATEMENT);
+ exportTableName(_xProp,true);
+}
+
+void ODBExport::exportTable(XPropertySet* _xProp)
+{
+ exportTableName(_xProp,false);
+
+ if ( _xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_DESCRIPTION) )
+ AddAttribute(XML_NAMESPACE_DB, XML_DESCRIPTION,getString(_xProp->getPropertyValue(PROPERTY_DESCRIPTION)));
+
+ if ( getBOOL(_xProp->getPropertyValue(PROPERTY_APPLYFILTER)) )
+ AddAttribute(XML_NAMESPACE_DB, XML_APPLY_FILTER,XML_TRUE);
+
+ if ( _xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_APPLYORDER)
+ && getBOOL(_xProp->getPropertyValue(PROPERTY_APPLYORDER)) )
+ AddAttribute(XML_NAMESPACE_DB, XML_APPLY_ORDER,XML_TRUE);
+
+ exportStyleName(_xProp,GetAttrList());
+
+ SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, XML_TABLE_REPRESENTATION, true, true);
+ Reference<XColumnsSupplier> xCol(_xProp,UNO_QUERY);
+ exportColumns(xCol);
+ exportFilter(_xProp,PROPERTY_FILTER,XML_FILTER_STATEMENT);
+ exportFilter(_xProp,PROPERTY_ORDER,XML_ORDER_STATEMENT);
+}
+
+void ODBExport::exportStyleName(XPropertySet* _xProp,SvXMLAttributeList& _rAtt)
+{
+ Reference<XPropertySet> xFind(_xProp);
+ exportStyleName(XML_STYLE_NAME,xFind,_rAtt,m_aAutoStyleNames);
+ exportStyleName(XML_DEFAULT_CELL_STYLE_NAME,xFind,_rAtt,m_aCellAutoStyleNames);
+ exportStyleName(XML_DEFAULT_ROW_STYLE_NAME,xFind,_rAtt,m_aRowAutoStyleNames);
+}
+
+void ODBExport::exportStyleName(const ::xmloff::token::XMLTokenEnum _eToken,const uno::Reference<beans::XPropertySet>& _xProp,SvXMLAttributeList& _rAtt,TPropertyStyleMap& _rMap)
+{
+ TPropertyStyleMap::const_iterator aFind = _rMap.find(_xProp);
+ if ( aFind != _rMap.end() )
+ {
+ _rAtt.AddAttribute( GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DB, GetXMLToken(_eToken) ),
+ aFind->second );
+ _rMap.erase(aFind);
+ }
+}
+
+void ODBExport::exportTableName(XPropertySet* _xProp,bool _bUpdate)
+{
+ OUString sValue;
+ _xProp->getPropertyValue(_bUpdate ? OUString(PROPERTY_UPDATE_TABLENAME) : OUString(PROPERTY_NAME)) >>= sValue;
+ if ( sValue.isEmpty() )
+ return;
+
+ AddAttribute(XML_NAMESPACE_DB, XML_NAME,sValue);
+ _xProp->getPropertyValue(_bUpdate ? OUString(PROPERTY_UPDATE_SCHEMANAME) : OUString(PROPERTY_SCHEMANAME)) >>= sValue;
+ if ( !sValue.isEmpty() )
+ AddAttribute(XML_NAMESPACE_DB, XML_SCHEMA_NAME,sValue);
+ _xProp->getPropertyValue(_bUpdate ? OUString(PROPERTY_UPDATE_CATALOGNAME) : OUString(PROPERTY_CATALOGNAME)) >>= sValue;
+ if ( !sValue.isEmpty() )
+ AddAttribute(XML_NAMESPACE_DB, XML_CATALOG_NAME,sValue);
+
+ if ( _bUpdate )
+ {
+ SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, XML_UPDATE_TABLE, true, true);
+ }
+}
+
+void ODBExport::exportFilter(XPropertySet* _xProp
+ ,const OUString& _sProp
+ ,enum ::xmloff::token::XMLTokenEnum _eStatementType)
+{
+ OSL_PRECOND(!GetAttrList().getLength(),"Invalid attribute length!");
+ OUString sCommand;
+ _xProp->getPropertyValue(_sProp) >>= sCommand;
+ if ( !sCommand.isEmpty() )
+ {
+ AddAttribute(XML_NAMESPACE_DB, XML_COMMAND,sCommand);
+ SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, _eStatementType, true, true);
+ }
+ SAL_WARN_IF(GetAttrList().getLength(), "dbaccess", "Invalid attribute length!");
+}
+
+void ODBExport::exportColumns(const Reference<XColumnsSupplier>& _xColSup)
+{
+ OSL_PRECOND( _xColSup.is(), "ODBExport::exportColumns: invalid columns supplier!" );
+ if ( !_xColSup.is() )
+ return;
+
+ try
+ {
+ Reference<XNameAccess> xNameAccess( _xColSup->getColumns(), UNO_SET_THROW );
+ if ( !xNameAccess->hasElements() )
+ {
+ Reference< XPropertySet > xComponent(_xColSup,UNO_QUERY);
+ TTableColumnMap::const_iterator aFind = m_aTableDummyColumns.find(xComponent);
+ if ( aFind != m_aTableDummyColumns.end() )
+ {
+ SvXMLElementExport aColumns(*this,XML_NAMESPACE_DB, XML_COLUMNS, true, true);
+ rtl::Reference<SvXMLAttributeList> pAtt = new SvXMLAttributeList;
+ exportStyleName(aFind->second.get(),*pAtt);
+ AddAttributeList(pAtt);
+ SvXMLElementExport aColumn(*this,XML_NAMESPACE_DB, XML_COLUMN, true, true);
+
+ }
+ return;
+ }
+
+ SvXMLElementExport aColumns(*this,XML_NAMESPACE_DB, XML_COLUMNS, true, true);
+ Sequence< OUString> aSeq = xNameAccess->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for( ; pIter != pEnd ; ++pIter)
+ {
+ Reference<XPropertySet> xProp(xNameAccess->getByName(*pIter),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ rtl::Reference<SvXMLAttributeList> pAtt = new SvXMLAttributeList;
+ exportStyleName(xProp.get(),*pAtt);
+
+ bool bHidden = getBOOL(xProp->getPropertyValue(PROPERTY_HIDDEN));
+
+ OUString sValue;
+ xProp->getPropertyValue(PROPERTY_HELPTEXT) >>= sValue;
+ Any aColumnDefault = xProp->getPropertyValue(PROPERTY_CONTROLDEFAULT);
+
+ if ( bHidden || !sValue.isEmpty() || aColumnDefault.hasValue() || pAtt->getLength() )
+ {
+ AddAttribute(XML_NAMESPACE_DB, XML_NAME,*pIter);
+ if ( bHidden )
+ AddAttribute(XML_NAMESPACE_DB, XML_VISIBLE,XML_FALSE);
+
+ if ( !sValue.isEmpty() )
+ AddAttribute(XML_NAMESPACE_DB, XML_HELP_MESSAGE,sValue);
+
+ if ( aColumnDefault.hasValue() )
+ {
+ OUStringBuffer sColumnDefaultString,sType;
+ ::sax::Converter::convertAny(
+ sColumnDefaultString, sType, aColumnDefault );
+ AddAttribute(XML_NAMESPACE_DB, XML_TYPE_NAME,sType.makeStringAndClear());
+ AddAttribute(XML_NAMESPACE_DB, XML_DEFAULT_VALUE,sColumnDefaultString.makeStringAndClear());
+ }
+
+ if ( pAtt->getLength() )
+ AddAttributeList(pAtt);
+ }
+
+ if ( GetAttrList().getLength() )
+ {
+ SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, XML_COLUMN, true, true);
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODBExport::exportForms()
+{
+ Any aValue;
+ OUString sService;
+ dbtools::getDataSourceSetting(getDataSource(),"Forms",aValue);
+ aValue >>= sService;
+ if ( !sService.isEmpty() )
+ return;
+
+ Reference<XFormDocumentsSupplier> xSup(GetModel(),UNO_QUERY);
+ if ( xSup.is() )
+ {
+ Reference< XNameAccess > xCollection = xSup->getFormDocuments();
+ if ( xCollection.is() && xCollection->hasElements() )
+ {
+ ::comphelper::mem_fun1_t<ODBExport,XPropertySet* > aMemFunc(&ODBExport::exportComponent);
+ exportCollection(xCollection,XML_FORMS,XML_COMPONENT_COLLECTION,true,aMemFunc);
+ }
+ }
+}
+
+void ODBExport::exportReports()
+{
+ Any aValue;
+ OUString sService;
+ dbtools::getDataSourceSetting(getDataSource(),"Reports",aValue);
+ aValue >>= sService;
+ if ( !sService.isEmpty() )
+ return;
+
+ Reference<XReportDocumentsSupplier> xSup(GetModel(),UNO_QUERY);
+ if ( xSup.is() )
+ {
+ Reference< XNameAccess > xCollection = xSup->getReportDocuments();
+ if ( xCollection.is() && xCollection->hasElements() )
+ {
+ ::comphelper::mem_fun1_t<ODBExport,XPropertySet* > aMemFunc(&ODBExport::exportComponent);
+ exportCollection(xCollection,XML_REPORTS,XML_COMPONENT_COLLECTION,true,aMemFunc);
+ }
+ }
+}
+
+void ODBExport::exportQueries(bool _bExportContext)
+{
+ Any aValue;
+ OUString sService;
+ dbtools::getDataSourceSetting(getDataSource(),"CommandDefinitions",aValue);
+ aValue >>= sService;
+ if ( !sService.isEmpty() )
+ return;
+
+ Reference<XQueryDefinitionsSupplier> xSup(getDataSource(),UNO_QUERY);
+ if ( !xSup.is() )
+ return;
+
+ Reference< XNameAccess > xCollection = xSup->getQueryDefinitions();
+ if ( xCollection.is() && xCollection->hasElements() )
+ {
+ std::unique_ptr< ::comphelper::mem_fun1_t<ODBExport,XPropertySet* > > pMemFunc;
+ if ( _bExportContext )
+ pMemFunc.reset( new ::comphelper::mem_fun1_t<ODBExport,XPropertySet* >(&ODBExport::exportQuery) );
+ else
+ pMemFunc.reset( new ::comphelper::mem_fun1_t<ODBExport,XPropertySet* >(&ODBExport::exportAutoStyle) );
+
+ exportCollection(xCollection,XML_QUERIES,XML_QUERY_COLLECTION,_bExportContext,*pMemFunc);
+ }
+}
+
+void ODBExport::exportTables(bool _bExportContext)
+{
+ Reference<XTablesSupplier> xSup(getDataSource(),UNO_QUERY);
+ if ( !xSup.is() )
+ return;
+
+ Reference< XNameAccess > xCollection = xSup->getTables();
+ if ( xCollection.is() && xCollection->hasElements() )
+ {
+ std::unique_ptr< ::comphelper::mem_fun1_t<ODBExport,XPropertySet* > > pMemFunc;
+ if ( _bExportContext )
+ pMemFunc.reset( new ::comphelper::mem_fun1_t<ODBExport,XPropertySet* >(&ODBExport::exportTable) );
+ else
+ pMemFunc.reset( new ::comphelper::mem_fun1_t<ODBExport,XPropertySet* >(&ODBExport::exportAutoStyle) );
+ exportCollection(xCollection,XML_TABLE_REPRESENTATIONS,XML_TOKEN_INVALID,_bExportContext,*pMemFunc);
+ }
+}
+
+void ODBExport::exportAutoStyle(XPropertySet* _xProp)
+{
+ typedef std::pair<TPropertyStyleMap*,XmlStyleFamily> TEnumMapperPair;
+ typedef std::pair< rtl::Reference < SvXMLExportPropertyMapper> , TEnumMapperPair> TExportPropMapperPair;
+ Reference<XColumnsSupplier> xSup(_xProp,UNO_QUERY);
+ if ( xSup.is() )
+ {
+ const TExportPropMapperPair pExportHelper[] = {
+ TExportPropMapperPair(m_xExportHelper,TEnumMapperPair(&m_aAutoStyleNames,XmlStyleFamily::TABLE_TABLE ))
+ // ,TExportPropMapperPair(m_xCellExportHelper,TEnumMapperPair(&m_aCellAutoStyleNames,XmlStyleFamily::TABLE_CELL))
+ ,TExportPropMapperPair(m_xRowExportHelper,TEnumMapperPair(&m_aRowAutoStyleNames,XmlStyleFamily::TABLE_ROW))
+ };
+
+ for (const auto & i : pExportHelper)
+ {
+ std::vector< XMLPropertyState > aPropertyStates = i.first->Filter(*this, _xProp);
+ if ( !aPropertyStates.empty() )
+ i.second.first->emplace( _xProp,GetAutoStylePool()->Add( i.second.second, std::move(aPropertyStates) ) );
+ }
+
+ Reference< XNameAccess > xCollection;
+ try
+ {
+ xCollection.set( xSup->getColumns(), UNO_SET_THROW );
+ awt::FontDescriptor aFont;
+ _xProp->getPropertyValue(PROPERTY_FONT) >>= aFont;
+ GetFontAutoStylePool()->Add(aFont.Name,aFont.StyleName,static_cast<FontFamily>(aFont.Family),
+ static_cast<FontPitch>(aFont.Pitch),aFont.CharSet );
+
+ m_aCurrentPropertyStates = m_xCellExportHelper->Filter(*this, _xProp);
+ if ( !m_aCurrentPropertyStates.empty() && !xCollection->hasElements() )
+ {
+ Reference< XDataDescriptorFactory> xFac(xCollection,UNO_QUERY);
+ if ( xFac.is() )
+ {
+ Reference< XPropertySet> xColumn = xFac->createDataDescriptor();
+ m_aTableDummyColumns.emplace( Reference< XPropertySet>(_xProp),xColumn );
+ exportAutoStyle(xColumn.get());
+ }
+ }
+ else
+ {
+ ::comphelper::mem_fun1_t<ODBExport,XPropertySet* > aMemFunc(&ODBExport::exportAutoStyle);
+ exportCollection(xCollection,XML_TOKEN_INVALID,XML_TOKEN_INVALID,false,aMemFunc);
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_aCurrentPropertyStates.clear();
+ }
+ else
+ { // here I know I have a column
+ const TExportPropMapperPair pExportHelper[] = {
+ TExportPropMapperPair(m_xColumnExportHelper,TEnumMapperPair(&m_aAutoStyleNames,XmlStyleFamily::TABLE_COLUMN ))
+ ,TExportPropMapperPair(m_xCellExportHelper,TEnumMapperPair(&m_aCellAutoStyleNames,XmlStyleFamily::TABLE_CELL))
+ };
+ for (const auto & i : pExportHelper)
+ {
+ std::vector< XMLPropertyState > aPropStates = i.first->Filter(*this, _xProp);
+ if ( !aPropStates.empty() )
+ {
+ const rtl::Reference < XMLPropertySetMapper >& pStyle = i.first->getPropertySetMapper();
+ for (auto & propState : aPropStates)
+ {
+ if ( propState.mnIndex != -1 )
+ {
+ switch ( pStyle->GetEntryContextId(propState.mnIndex) )
+ {
+ case CTF_DB_NUMBERFORMAT:
+ {
+ sal_Int32 nNumberFormat = -1;
+ if ( propState.maValue >>= nNumberFormat )
+ addDataStyle(nNumberFormat);
+ }
+ break;
+ case CTF_DB_COLUMN_TEXT_ALIGN:
+ if ( !propState.maValue.hasValue() )
+ propState.maValue <<= css::awt::TextAlign::LEFT;
+ break;
+ }
+ }
+ }
+
+ }
+ if ( XmlStyleFamily::TABLE_CELL == i.second.second )
+ aPropStates.insert( aPropStates.end(), m_aCurrentPropertyStates.begin(), m_aCurrentPropertyStates.end() );
+ if ( !aPropStates.empty() )
+ i.second.first->emplace( _xProp,GetAutoStylePool()->Add( i.second.second, std::move(aPropStates) ) );
+ }
+ }
+}
+
+void ODBExport::ExportContent_()
+{
+ exportDataSource();
+ exportForms();
+ exportReports();
+ exportQueries(true);
+ exportTables(true);
+}
+
+void ODBExport::ExportMasterStyles_()
+{
+ GetPageExport()->exportMasterStyles( true );
+}
+
+void ODBExport::ExportAutoStyles_()
+{
+ // there are no styles that require their own autostyles
+ if ( getExportFlags() & SvXMLExportFlags::CONTENT )
+ {
+ collectComponentStyles();
+ GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_TABLE);
+ GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_COLUMN);
+ GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_CELL);
+ GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_ROW);
+ exportDataStyles();
+ }
+}
+
+void ODBExport::GetViewSettings(Sequence<PropertyValue>& aProps)
+{
+ Reference<XQueryDefinitionsSupplier> xSup(getDataSource(),UNO_QUERY);
+ if ( !xSup.is() )
+ return;
+
+ Reference< XNameAccess > xCollection = xSup->getQueryDefinitions();
+ if ( !(xCollection.is() && xCollection->hasElements()) )
+ return;
+
+ try
+ {
+ sal_Int32 nLength = aProps.getLength();
+ aProps.realloc(nLength + 1);
+ auto pProps = aProps.getArray();
+ pProps[nLength].Name = "Queries";
+ Sequence< OUString> aSeq = xCollection->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+
+ Sequence<PropertyValue> aQueries(aSeq.getLength());
+ auto aQueriesRange = asNonConstRange(aQueries);
+ for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i)
+ {
+ Reference<XPropertySet> xProp(xCollection->getByName(*pIter),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ aQueriesRange[i].Name = *pIter;
+ aQueriesRange[i].Value = xProp->getPropertyValue(PROPERTY_LAYOUTINFORMATION);
+ }
+ }
+ pProps[nLength].Value <<= aQueries;
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "ODBExport::GetViewSettings");
+ }
+
+}
+
+void ODBExport::GetConfigurationSettings(Sequence<PropertyValue>& aProps)
+{
+ Reference<XPropertySet> xProp(getDataSource());
+ if ( !xProp.is() )
+ return;
+
+ sal_Int32 nLength = aProps.getLength();
+ try
+ {
+ Any aValue = xProp->getPropertyValue(PROPERTY_LAYOUTINFORMATION);
+ Sequence< PropertyValue > aPropValues;
+ aValue >>= aPropValues;
+ if ( aPropValues.hasElements() )
+ {
+ aProps.realloc(nLength + 1);
+ auto pProps = aProps.getArray();
+ pProps[nLength].Name = "layout-settings";
+ pProps[nLength].Value = aValue;
+ }
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Could not access layout information from the data source!");
+ }
+}
+
+OUString ODBExport::implConvertAny(const Any& _rValue)
+{
+ OUStringBuffer aBuffer;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_STRING:
+ { // extract the string
+ OUString sCurrentValue;
+ _rValue >>= sCurrentValue;
+ aBuffer.append(sCurrentValue);
+ }
+ break;
+ case TypeClass_DOUBLE:
+ // let the unit converter format is as string
+ ::sax::Converter::convertDouble(aBuffer, getDouble(_rValue));
+ break;
+ case TypeClass_BOOLEAN:
+ aBuffer = getBOOL(_rValue) ? ::xmloff::token::GetXMLToken(XML_TRUE) : ::xmloff::token::GetXMLToken(XML_FALSE);
+ break;
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_LONG:
+ // let the unit converter format is as string
+ aBuffer.append(getINT32(_rValue));
+ break;
+ default:
+ OSL_FAIL("ODBExport::implConvertAny: Invalid type");
+ }
+
+ return aBuffer.makeStringAndClear();
+}
+
+rtl::Reference < XMLPropertySetMapper > const & ODBExport::GetTableStylesPropertySetMapper() const
+{
+ if ( !m_xTableStylesPropertySetMapper.is() )
+ {
+ m_xTableStylesPropertySetMapper = OXMLHelper::GetTableStylesPropertySetMapper( true);
+ }
+ return m_xTableStylesPropertySetMapper;
+}
+
+rtl::Reference < XMLPropertySetMapper > const & ODBExport::GetCellStylesPropertySetMapper() const
+{
+ if ( !m_xCellStylesPropertySetMapper.is() )
+ {
+ m_xCellStylesPropertySetMapper = OXMLHelper::GetCellStylesPropertySetMapper( true);
+ }
+ return m_xCellStylesPropertySetMapper;
+}
+
+rtl::Reference < XMLPropertySetMapper > const & ODBExport::GetColumnStylesPropertySetMapper() const
+{
+ if ( !m_xColumnStylesPropertySetMapper.is() )
+ {
+ m_xColumnStylesPropertySetMapper = OXMLHelper::GetColumnStylesPropertySetMapper( true);
+ }
+ return m_xColumnStylesPropertySetMapper;
+}
+
+SvXMLAutoStylePoolP* ODBExport::CreateAutoStylePool()
+{
+ return new OXMLAutoStylePoolP(*this);
+}
+
+void SAL_CALL ODBExport::setSourceDocument( const Reference< XComponent >& xDoc )
+{
+ Reference<XOfficeDatabaseDocument> xOfficeDoc(xDoc,UNO_QUERY_THROW);
+ m_xDataSource.set(xOfficeDoc->getDataSource(),UNO_QUERY_THROW);
+ OSL_ENSURE(m_xDataSource.is(),"DataSource is NULL!");
+ Reference< XNumberFormatsSupplier > xNum(m_xDataSource->getPropertyValue(PROPERTY_NUMBERFORMATSSUPPLIER),UNO_QUERY);
+ SetNumberFormatsSupplier(xNum);
+ SvXMLExport::setSourceDocument(xDoc);
+}
+
+void ODBExport::ExportFontDecls_()
+{
+ GetFontAutoStylePool(); // make sure the pool is created
+ collectComponentStyles();
+ SvXMLExport::ExportFontDecls_();
+}
+
+void ODBExport::collectComponentStyles()
+{
+ if ( m_bAllreadyFilled )
+ return;
+
+ m_bAllreadyFilled = true;
+ exportQueries(false);
+ exportTables(false);
+}
+
+}// dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlExport.hxx b/dbaccess/source/filter/xml/xmlExport.hxx
new file mode 100644
index 000000000..7e1d148e1
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlExport.hxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/io/XActiveDataSource.hpp>
+#include <xmloff/maptype.hxx>
+#include <xmloff/txtprmap.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmlexppr.hxx>
+#include <dsntypes.hxx>
+#include <comphelper/stl_types.hxx>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+
+#include <memory>
+
+
+namespace dbaxml {
+
+using namespace ::xmloff::token;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::xml::sax;
+
+
+class ODBExport : public SvXMLExport
+{
+ typedef std::map< ::xmloff::token::XMLTokenEnum, OUString> TSettingsMap;
+
+ typedef std::pair< OUString ,OUString> TStringPair;
+ struct TDelimiter
+ {
+ OUString sText;
+ OUString sField;
+ OUString sDecimal;
+ OUString sThousand;
+ bool bUsed;
+
+ TDelimiter() : bUsed( false ) { }
+ };
+ typedef std::map< Reference<XPropertySet> ,OUString > TPropertyStyleMap;
+ typedef std::map< Reference<XPropertySet> ,Reference<XPropertySet> > TTableColumnMap;
+
+ struct TypedPropertyValue
+ {
+ OUString Name;
+ css::uno::Type Type;
+ css::uno::Any Value;
+
+ TypedPropertyValue( const OUString& _name, const css::uno::Type& _type, const css::uno::Any& _value )
+ :Name( _name )
+ ,Type( _type )
+ ,Value( _value )
+ {
+ }
+ };
+
+ std::unique_ptr< TStringPair > m_aAutoIncrement;
+ std::unique_ptr< TDelimiter > m_aDelimiter;
+ std::vector< TypedPropertyValue > m_aDataSourceSettings;
+ std::vector< XMLPropertyState > m_aCurrentPropertyStates;
+ TPropertyStyleMap m_aAutoStyleNames;
+ TPropertyStyleMap m_aCellAutoStyleNames;
+ TPropertyStyleMap m_aRowAutoStyleNames;
+ TTableColumnMap m_aTableDummyColumns;
+ OUString m_sCharSet;
+ rtl::Reference < SvXMLExportPropertyMapper> m_xExportHelper;
+ rtl::Reference < SvXMLExportPropertyMapper> m_xColumnExportHelper;
+ rtl::Reference < SvXMLExportPropertyMapper> m_xCellExportHelper;
+ rtl::Reference < SvXMLExportPropertyMapper> m_xRowExportHelper;
+
+ mutable rtl::Reference < XMLPropertySetMapper > m_xTableStylesPropertySetMapper;
+ mutable rtl::Reference < XMLPropertySetMapper > m_xColumnStylesPropertySetMapper;
+ mutable rtl::Reference < XMLPropertySetMapper > m_xCellStylesPropertySetMapper;
+
+ Reference<XPropertySet> m_xDataSource;
+ ::dbaccess::ODsnTypeCollection m_aTypeCollection;
+ bool m_bAllreadyFilled;
+
+ void exportDataSource();
+ void exportConnectionData();
+ void exportDriverSettings(const TSettingsMap& _aSettings);
+ void exportApplicationConnectionSettings(const TSettingsMap& _aSettings);
+ void exportLogin();
+ void exportSequence(const Sequence< OUString>& _aValue
+ ,::xmloff::token::XMLTokenEnum _eTokenFilter
+ ,::xmloff::token::XMLTokenEnum _eTokenType);
+ void exportDelimiter();
+ void exportAutoIncrement();
+ void exportCharSet();
+ template< typename T > void exportDataSourceSettingsSequence(
+ std::vector< TypedPropertyValue >::iterator const & in);
+ void exportDataSourceSettings();
+ void exportForms();
+ void exportReports();
+ void exportQueries(bool _bExportContext);
+ void exportTables(bool _bExportContext);
+ void exportStyleName(XPropertySet* _xProp,SvXMLAttributeList& _rAtt);
+ void exportStyleName(const ::xmloff::token::XMLTokenEnum _eToken,const Reference<XPropertySet>& _xProp,SvXMLAttributeList& _rAtt,TPropertyStyleMap& _rMap);
+ void exportCollection(const Reference< XNameAccess >& _xCollection
+ ,enum ::xmloff::token::XMLTokenEnum _eComponents
+ ,enum ::xmloff::token::XMLTokenEnum _eSubComponents
+ ,bool _bExportContext
+ ,const ::comphelper::mem_fun1_t<ODBExport,XPropertySet* >& _aMemFunc
+ );
+ void exportComponent(XPropertySet* _xProp);
+ void exportQuery(XPropertySet* _xProp);
+ void exportTable(XPropertySet* _xProp);
+ void exportFilter(XPropertySet* _xProp
+ ,const OUString& _sProp
+ ,enum ::xmloff::token::XMLTokenEnum _eStatementType);
+ void exportTableName(XPropertySet* _xProp,bool _bUpdate);
+ void exportAutoStyle(XPropertySet* _xProp);
+ void exportColumns(const Reference<XColumnsSupplier>& _xColSup);
+ void collectComponentStyles();
+
+ static OUString implConvertAny(const Any& _rValue);
+
+ rtl::Reference < XMLPropertySetMapper > const & GetTableStylesPropertySetMapper() const;
+
+ ODBExport() = delete;
+protected:
+
+ virtual void ExportAutoStyles_() override;
+ virtual void ExportContent_() override;
+ virtual void ExportMasterStyles_() override;
+ virtual void ExportFontDecls_() override;
+ virtual SvXMLAutoStylePoolP* CreateAutoStylePool() override;
+
+ virtual void GetViewSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override;
+ virtual void GetConfigurationSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override;
+
+ virtual ~ODBExport() override {};
+public:
+
+ ODBExport(const Reference< XComponentContext >& _rxContext, OUString const & implementationName, SvXMLExportFlags nExportFlag = SvXMLExportFlags::CONTENT | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::PRETTY | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::SCRIPTS );
+
+ rtl::Reference < XMLPropertySetMapper > const & GetColumnStylesPropertySetMapper() const;
+ rtl::Reference < XMLPropertySetMapper > const & GetCellStylesPropertySetMapper() const;
+
+ // XExporter
+ virtual void SAL_CALL setSourceDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override;
+
+ const Reference<XPropertySet>& getDataSource() const { return m_xDataSource; }
+};
+
+} // dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlFileBasedDatabase.cxx b/dbaccess/source/filter/xml/xmlFileBasedDatabase.cxx
new file mode 100644
index 000000000..37e4058ab
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlFileBasedDatabase.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlFileBasedDatabase.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <strings.hxx>
+#include <tools/diagnose_ex.h>
+#include <svl/filenotation.hxx>
+#include <unotools/pathoptions.hxx>
+#include <dsntypes.hxx>
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLFileBasedDatabase::OXMLFileBasedDatabase( ODBFilter& rImport,
+ const Reference< XFastAttributeList > & _xAttrList) :
+ SvXMLImportContext( rImport )
+{
+ Reference<XPropertySet> xDataSource = rImport.getDataSource();
+
+ PropertyValue aProperty;
+
+ OUString sLocation,sMediaType,sFileTypeExtension;
+ if (xDataSource.is())
+ {
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ OUString sValue = aIter.toString();
+
+ aProperty.Name.clear();
+ aProperty.Value = Any();
+
+ switch( aIter.getToken() )
+ {
+ case XML_ELEMENT(XLINK, XML_HREF):
+ {
+ SvtPathOptions aPathOptions;
+ OUString sFileName = aPathOptions.SubstituteVariable(sValue);
+ if ( sValue == sFileName )
+ {
+ const sal_Int32 nFileNameLength = sFileName.getLength();
+ if ( sFileName.endsWith("/") )
+ sFileName = sFileName.copy( 0, nFileNameLength - 1 );
+
+ sLocation = ::svt::OFileNotation( rImport.GetAbsoluteReference( sFileName ) ).get( ::svt::OFileNotation::N_SYSTEM );
+ }
+
+ if ( sLocation.isEmpty() )
+ sLocation = sValue;
+ }
+ break;
+ case XML_ELEMENT(DB, XML_MEDIA_TYPE):
+ case XML_ELEMENT(DB_OASIS, XML_MEDIA_TYPE):
+ sMediaType = sValue;
+ break;
+ case XML_ELEMENT(DB, XML_EXTENSION):
+ case XML_ELEMENT(DB_OASIS, XML_EXTENSION):
+ aProperty.Name = INFO_TEXTFILEEXTENSION;
+ sFileTypeExtension = sValue;
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ if ( !aProperty.Name.isEmpty() )
+ {
+ if ( !aProperty.Value.hasValue() )
+ aProperty.Value <<= sValue;
+ rImport.addInfo(aProperty);
+ }
+ }
+ }
+ if ( sLocation.isEmpty() || sMediaType.isEmpty() )
+ return;
+
+ ::dbaccess::ODsnTypeCollection aTypeCollection(rImport.GetComponentContext());
+ OUString sURL = aTypeCollection.getDatasourcePrefixFromMediaType(sMediaType,sFileTypeExtension) + sLocation;
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_URL,Any(sURL));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OXMLFileBasedDatabase::~OXMLFileBasedDatabase()
+{
+
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlFileBasedDatabase.hxx b/dbaccess/source/filter/xml/xmlFileBasedDatabase.hxx
new file mode 100644
index 000000000..3720e1da3
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlFileBasedDatabase.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLFileBasedDatabase : public SvXMLImportContext
+ {
+ public:
+
+ OXMLFileBasedDatabase( ODBFilter& rImport,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList );
+ virtual ~OXMLFileBasedDatabase() override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlHelper.cxx b/dbaccess/source/filter/xml/xmlHelper.cxx
new file mode 100644
index 000000000..85b98ec1e
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlHelper.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlHelper.hxx"
+#include <xmloff/XMLConstantsPropertyHandler.hxx>
+#include <xmloff/xmlement.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmltypes.hxx>
+#include <xmloff/maptype.hxx>
+
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <strings.hxx>
+#include <rtl/ref.hxx>
+
+namespace dbaxml
+{
+ using namespace ::xmloff::token;
+ using namespace ::com::sun::star::awt;
+
+OPropertyHandlerFactory::OPropertyHandlerFactory()
+{
+}
+
+OPropertyHandlerFactory::~OPropertyHandlerFactory()
+{
+
+}
+
+const XMLPropertyHandler* OPropertyHandlerFactory::GetPropertyHandler(sal_Int32 _nType) const
+{
+ const XMLPropertyHandler* pHandler = nullptr;
+
+ switch (_nType)
+ {
+ case XML_DB_TYPE_EQUAL:
+ if (!m_pDisplayHandler)
+ {
+ static const SvXMLEnumMapEntry<bool> aDisplayMap[] =
+ {
+ { XML_VISIBLE, true },
+ { XML_COLLAPSE, false },
+ { XML_TOKEN_INVALID, false }
+ };
+ m_pDisplayHandler.reset(new XMLConstantsPropertyHandler(aDisplayMap, XML_TOKEN_INVALID ));
+ }
+ pHandler = m_pDisplayHandler.get();
+ break;
+ }
+ if ( !pHandler )
+ pHandler = OControlPropertyHandlerFactory::GetPropertyHandler(_nType);
+ return pHandler;
+}
+
+rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetTableStylesPropertySetMapper( bool bForExport )
+{
+ static const XMLPropertyMapEntry s_aTableStylesProperties[] =
+ {
+ { nullptr, 0, XML_TOKEN_INVALID, 0 , 0, SvtSaveOptions::ODFSVER_010, false}
+ };
+ rtl::Reference < XMLPropertyHandlerFactory> xFac = new ::xmloff::OControlPropertyHandlerFactory();
+ return new XMLPropertySetMapper(s_aTableStylesProperties, xFac, bForExport);
+}
+
+rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetColumnStylesPropertySetMapper( bool bForExport )
+{
+ static const XMLPropertyMapEntry s_aColumnStylesProperties[] =
+ {
+ { PROPERTY_WIDTH, XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH, XML_TYPE_MEASURE|XML_TYPE_PROP_TABLE_COLUMN, 0, SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_HIDDEN, XML_NAMESPACE_TABLE, XML_DISPLAY, XML_DB_TYPE_EQUAL|MID_FLAG_SPECIAL_ITEM|XML_TYPE_PROP_TABLE_COLUMN,
+ CTF_DB_ISVISIBLE, SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_NUMBERFORMAT, XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, XML_TYPE_NUMBER|MID_FLAG_SPECIAL_ITEM|XML_TYPE_PROP_TABLE_COLUMN,
+ CTF_DB_NUMBERFORMAT, SvtSaveOptions::ODFSVER_010, false },
+ { nullptr, 0, XML_TOKEN_INVALID, 0 , 0, SvtSaveOptions::ODFSVER_010, false}
+ };
+ rtl::Reference < XMLPropertyHandlerFactory> xFac = new OPropertyHandlerFactory();
+ return new XMLPropertySetMapper(s_aColumnStylesProperties, xFac, bForExport);
+}
+
+rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetCellStylesPropertySetMapper( bool bForExport )
+{
+ static const XMLPropertyMapEntry s_aCellStylesProperties[] =
+ {
+ { PROPERTY_ALIGN, XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_TYPE_TEXT_ALIGN|XML_TYPE_PROP_PARAGRAPH, CTF_DB_COLUMN_TEXT_ALIGN, SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTNAME, XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_TYPE_STRING|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_TEXTCOLOR, XML_NAMESPACE_FO, XML_COLOR, XML_TYPE_COLOR|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_TEXTLINECOLOR, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR,
+ XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_TEXTRELIEF, XML_NAMESPACE_STYLE, XML_FONT_RELIEF,
+ XML_TYPE_TEXT_FONT_RELIEF|MID_FLAG_MULTI_PROPERTY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_TEXTEMPHASIS, XML_NAMESPACE_STYLE, XML_TEXT_EMPHASIZE, XML_TYPE_CONTROL_TEXT_EMPHASIZE|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTCHARWIDTH, XML_NAMESPACE_STYLE, XML_FONT_CHAR_WIDTH, XML_TYPE_NUMBER16|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTCHARSET, XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTFAMILY, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_TYPE_TEXT_FONTFAMILY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTHEIGHT, XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_MEASURE16|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTKERNING, XML_NAMESPACE_STYLE, XML_LETTER_KERNING, XML_TYPE_BOOL|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTORIENTATION, XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_TYPE_ROTATION_ANGLE|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTPITCH, XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_TYPE_TEXT_FONTPITCH|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTSLANT, XML_NAMESPACE_FO, XML_FONT_STYLE, XML_TYPE_TEXT_POSTURE|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE,
+ XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_010, false },
+ { "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE,
+ XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_010, false },
+ { "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH,
+ XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_010, false },
+ { "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT,
+ XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTSTYLENAME, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_TYPE_STRING|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { "CharUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE,
+ XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { "CharUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE,
+ XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { "CharUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH,
+ XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { "CharUnderlineColor", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR,
+ XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { "CharUnderlineHasColor", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTWEIGHT, XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTWIDTH, XML_NAMESPACE_STYLE, XML_FONT_WIDTH, XML_TYPE_FONT_WIDTH|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { PROPERTY_FONTWORDLINEMODE, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_MODE,
+ XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY|XML_TYPE_PROP_TEXT, 0 , SvtSaveOptions::ODFSVER_010, false },
+ { nullptr, 0, XML_TOKEN_INVALID, 0 , 0, SvtSaveOptions::ODFSVER_010, false}
+ };
+ rtl::Reference < XMLPropertyHandlerFactory> xFac = new /*OPropertyHandlerFactory*/::xmloff::OControlPropertyHandlerFactory();
+ return new XMLPropertySetMapper(s_aCellStylesProperties, xFac, bForExport);
+}
+
+rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetRowStylesPropertySetMapper()
+{
+ static const XMLPropertyMapEntry s_aStylesProperties[] =
+ {
+ { PROPERTY_ROW_HEIGHT, XML_NAMESPACE_STYLE, XML_ROW_HEIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TABLE_ROW, 0, SvtSaveOptions::ODFSVER_010, false },
+ { nullptr, 0, XML_TOKEN_INVALID, 0 , 0, SvtSaveOptions::ODFSVER_010, false}
+ };
+ rtl::Reference < XMLPropertyHandlerFactory> xFac = new OPropertyHandlerFactory();
+ return new XMLPropertySetMapper(s_aStylesProperties, xFac, true/*bForExport*/);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlHelper.hxx b/dbaccess/source/filter/xml/xmlHelper.hxx
new file mode 100644
index 000000000..a65cef9b3
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlHelper.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlprmap.hxx>
+#include <xmloff/contextid.hxx>
+#include <xmloff/controlpropertyhdl.hxx>
+
+#include <memory>
+
+#define CTF_DB_ROWHEIGHT (XML_DB_CTF_START + 1)
+#define CTF_DB_ISVISIBLE (XML_DB_CTF_START + 2)
+#define CTF_DB_MASTERPAGENAME (XML_DB_CTF_START + 3)
+#define CTF_DB_NUMBERFORMAT (XML_DB_CTF_START + 4)
+#define CTF_DB_COLUMN_TEXT_ALIGN (XML_DB_CTF_START + 5)
+
+#define XML_DB_TYPE_EQUAL (XML_DB_TYPES_START + 1)
+
+namespace dbaxml
+{
+ class OPropertyHandlerFactory final : public ::xmloff::OControlPropertyHandlerFactory
+ {
+ mutable std::unique_ptr<XMLConstantsPropertyHandler> m_pDisplayHandler;
+ public:
+ OPropertyHandlerFactory();
+ virtual ~OPropertyHandlerFactory() override;
+
+ virtual const XMLPropertyHandler* GetPropertyHandler(sal_Int32 _nType) const override;
+ };
+
+ class OXMLHelper
+ {
+ public:
+ static rtl::Reference < XMLPropertySetMapper > GetTableStylesPropertySetMapper( bool bForExport );
+ static rtl::Reference < XMLPropertySetMapper > GetColumnStylesPropertySetMapper( bool bForExport );
+ static rtl::Reference < XMLPropertySetMapper > GetCellStylesPropertySetMapper( bool bForExport );
+ static rtl::Reference < XMLPropertySetMapper > GetRowStylesPropertySetMapper();
+ };
+} // dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlHierarchyCollection.cxx b/dbaccess/source/filter/xml/xmlHierarchyCollection.cxx
new file mode 100644
index 000000000..8528f11c8
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlHierarchyCollection.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlHierarchyCollection.hxx"
+#include "xmlComponent.hxx"
+#include "xmlColumn.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLHierarchyCollection::OXMLHierarchyCollection( ODBFilter& rImport
+ ,const Reference< XFastAttributeList > & _xAttrList
+ ,const Reference< XNameAccess >& _xParentContainer
+ ,const OUString& _sCollectionServiceName
+ ,const OUString& _sComponentServiceName) :
+ SvXMLImportContext( rImport )
+ ,m_sCollectionServiceName(_sCollectionServiceName)
+ ,m_sComponentServiceName(_sComponentServiceName)
+{
+ OUString sName;
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_NAME:
+ sName = aIter.toString();
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+ if ( sName.isEmpty() || !_xParentContainer.is() )
+ return;
+
+ try
+ {
+ Reference<XMultiServiceFactory> xORB(_xParentContainer,UNO_QUERY);
+ if ( xORB.is() )
+ {
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"Name", Any(sName)}, // set as folder
+ {"Parent", Any(_xParentContainer)},
+ }));
+ m_xContainer.set(xORB->createInstanceWithArguments(_sCollectionServiceName,aArguments),UNO_QUERY);
+ Reference<XNameContainer> xNameContainer(_xParentContainer,UNO_QUERY);
+ if ( xNameContainer.is() && !xNameContainer->hasByName(sName) )
+ xNameContainer->insertByName(sName,Any(m_xContainer));
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "OXMLHierarchyCollection::OXMLHierarchyCollection");
+ }
+}
+
+OXMLHierarchyCollection::OXMLHierarchyCollection( ODBFilter& rImport
+ ,const Reference< XNameAccess >& _xContainer
+ ,const Reference< XPropertySet >& _xTable
+ ) :
+ SvXMLImportContext( rImport )
+ ,m_xContainer(_xContainer)
+ ,m_xTable(_xTable)
+{
+}
+
+OXMLHierarchyCollection::~OXMLHierarchyCollection()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLHierarchyCollection::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_COMPONENT:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLComponent( GetOwnImport(), xAttrList,m_xContainer,m_sComponentServiceName );
+ break;
+ case XML_COLUMN:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLColumn( GetOwnImport(), xAttrList,m_xContainer,m_xTable);
+ break;
+ case XML_COMPONENT_COLLECTION:
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new OXMLHierarchyCollection( GetOwnImport(), xAttrList,m_xContainer,m_sCollectionServiceName,m_sComponentServiceName);
+ break;
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLHierarchyCollection::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlHierarchyCollection.hxx b/dbaccess/source/filter/xml/xmlHierarchyCollection.hxx
new file mode 100644
index 000000000..689434822
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlHierarchyCollection.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLHierarchyCollection : public SvXMLImportContext
+ {
+ css::uno::Reference< css::container::XNameAccess > m_xContainer;
+ css::uno::Reference< css::beans::XPropertySet > m_xTable;
+ OUString m_sCollectionServiceName;
+ OUString m_sComponentServiceName;
+
+ ODBFilter& GetOwnImport();
+ public:
+
+ OXMLHierarchyCollection( ODBFilter& rImport
+ ,const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList
+ ,const css::uno::Reference< css::container::XNameAccess >& _xParentContainer
+ ,const OUString& _sCollectionServiceName
+ ,const OUString& _sComponentServiceName
+ );
+ OXMLHierarchyCollection( ODBFilter& rImport
+ ,const css::uno::Reference< css::container::XNameAccess >& _xContainer
+ ,const css::uno::Reference< css::beans::XPropertySet >& _xTable
+ );
+ virtual ~OXMLHierarchyCollection() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlLogin.cxx b/dbaccess/source/filter/xml/xmlLogin.cxx
new file mode 100644
index 000000000..fb4bb9eb8
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlLogin.cxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlLogin.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <strings.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLLogin::OXMLLogin( ODBFilter& rImport,
+ const Reference< XFastAttributeList > & _xAttrList ) :
+ SvXMLImportContext( rImport )
+{
+ Reference<XPropertySet> xDataSource(rImport.getDataSource());
+
+ bool bUserFound = false;
+ if (!xDataSource.is())
+ return;
+
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ try
+ {
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_USER_NAME:
+ if ( !bUserFound )
+ {
+ bUserFound = true;
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_USER,Any(aIter.toString()));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ break;
+ case XML_IS_PASSWORD_REQUIRED:
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_ISPASSWORDREQUIRED,Any(IsXMLToken(aIter, XML_TRUE)));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ break;
+ case XML_USE_SYSTEM_USER:
+ if ( !bUserFound )
+ {
+ bUserFound = true;
+ PropertyValue aProperty;
+ aProperty.Name = "UseSystemUser";
+ aProperty.Value <<= IsXMLToken(aIter, XML_TRUE);
+ rImport.addInfo(aProperty);
+ }
+ break;
+ case XML_LOGIN_TIMEOUT:
+ try
+ {
+ Reference< XDataSource>(xDataSource,UNO_QUERY_THROW)->setLoginTimeout(aIter.toInt32());
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+OXMLLogin::~OXMLLogin()
+{
+
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlLogin.hxx b/dbaccess/source/filter/xml/xmlLogin.hxx
new file mode 100644
index 000000000..adb25c739
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlLogin.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLLogin : public SvXMLImportContext
+ {
+ public:
+
+ OXMLLogin( ODBFilter& rImport,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList );
+ virtual ~OXMLLogin() override;
+
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlQuery.cxx b/dbaccess/source/filter/xml/xmlQuery.cxx
new file mode 100644
index 000000000..18ba034da
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlQuery.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlQuery.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+#include <strings.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::xml::sax;
+
+
+OXMLQuery::OXMLQuery( ODBFilter& rImport
+ ,const Reference< XFastAttributeList > & _xAttrList
+ ,const css::uno::Reference< css::container::XNameAccess >& _xParentContainer
+ ) :
+ OXMLTable( rImport, _xAttrList,_xParentContainer, "com.sun.star.sdb.CommandDefinition" )
+ ,m_bEscapeProcessing(true)
+{
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_COMMAND:
+ m_sCommand = aIter.toString();
+ break;
+ case XML_ESCAPE_PROCESSING:
+ m_bEscapeProcessing = aIter.toView() == "true";
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+}
+
+OXMLQuery::~OXMLQuery()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLQuery::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ css::uno::Reference< css::xml::sax::XFastContextHandler > xContext = OXMLTable::createFastChildContext(nElement,xAttrList );
+ if (!xContext)
+ {
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_UPDATE_TABLE:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ OUString s1;
+ fillAttributes(xAttrList,s1,m_sTable,m_sSchema,m_sCatalog);
+ break;
+ }
+ }
+ }
+
+ return xContext;
+}
+
+void OXMLQuery::setProperties(Reference< XPropertySet > & _xProp )
+{
+ try
+ {
+ if ( _xProp.is() )
+ {
+ OXMLTable::setProperties(_xProp);
+
+ _xProp->setPropertyValue(PROPERTY_COMMAND,Any(m_sCommand));
+ _xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,Any(m_bEscapeProcessing));
+
+ if ( !m_sTable.isEmpty() )
+ _xProp->setPropertyValue(PROPERTY_UPDATE_TABLENAME,Any(m_sTable));
+ if ( !m_sCatalog.isEmpty() )
+ _xProp->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,Any(m_sCatalog));
+ if ( !m_sSchema.isEmpty() )
+ _xProp->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,Any(m_sSchema));
+
+ const ODBFilter::TPropertyNameMap& rSettings = GetOwnImport().getQuerySettings();
+ ODBFilter::TPropertyNameMap::const_iterator aFind = rSettings.find(m_sName);
+ if ( aFind != rSettings.end() )
+ _xProp->setPropertyValue(PROPERTY_LAYOUTINFORMATION,Any(aFind->second));
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "OXMLTable::EndElement");
+ }
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlQuery.hxx b/dbaccess/source/filter/xml/xmlQuery.hxx
new file mode 100644
index 000000000..d3e01193c
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlQuery.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "xmlTable.hxx"
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLQuery : public OXMLTable
+ {
+ OUString m_sCommand;
+ OUString m_sTable;
+ bool m_bEscapeProcessing;
+ protected:
+ virtual void setProperties(css::uno::Reference< css::beans::XPropertySet > & _xProp) override;
+ public:
+
+ OXMLQuery( ODBFilter& rImport
+ ,const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList
+ ,const css::uno::Reference< css::container::XNameAccess >& _xParentContainer
+ );
+ virtual ~OXMLQuery() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlServerDatabase.cxx b/dbaccess/source/filter/xml/xmlServerDatabase.cxx
new file mode 100644
index 000000000..ff41590f0
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlServerDatabase.cxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlServerDatabase.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <strings.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLServerDatabase::OXMLServerDatabase( ODBFilter& rImport,
+ const Reference< XFastAttributeList > & _xAttrList) :
+ SvXMLImportContext( rImport )
+{
+ Reference<XPropertySet> xDataSource = rImport.getDataSource();
+
+ PropertyValue aProperty;
+
+ OUString sType,sHostName,sPortNumber,sDatabaseName;
+ if (xDataSource.is())
+ {
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ OUString sValue = aIter.toString();
+
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_TYPE:
+ sType = sValue;
+ break;
+ case XML_HOSTNAME:
+ sHostName = sValue;
+ break;
+ case XML_PORT:
+ sPortNumber = sValue;
+ break;
+ case XML_LOCAL_SOCKET:
+ aProperty.Name = "LocalSocket";
+ aProperty.Value <<= sValue;
+ rImport.addInfo(aProperty);
+ break;
+ case XML_DATABASE_NAME:
+ sDatabaseName = sValue;
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+ }
+ if ( sType.isEmpty() )
+ return;
+
+ OUStringBuffer sURL;
+ if ( sType == "sdbc:mysql:jdbc" || sType == "sdbc:mysqlc" || sType == "sdbc:mysql:mysqlc" )
+ {
+ sURL.append( sType + ":" + sHostName);
+ if ( !sPortNumber.isEmpty() )
+ {
+ sURL.append(":" + sPortNumber);
+ }
+ if ( !sDatabaseName.isEmpty() )
+ {
+ sURL.append("/" + sDatabaseName);
+ }
+ }
+ else if ( sType == "jdbc:oracle:thin" )
+ {
+ sURL.append("jdbc:oracle:thin:@" + sHostName);
+ if ( !sPortNumber.isEmpty() )
+ {
+ sURL.append(":" + sPortNumber);
+ }
+ if ( !sDatabaseName.isEmpty() )
+ {
+ sURL.append(":" + sDatabaseName);
+ }
+ }
+ else if ( sType == "sdbc:address:ldap" )
+ {
+ sURL.append("sdbc:address:ldap:" + sHostName);
+ if ( !sPortNumber.isEmpty() )
+ {
+ sURL.append(":" + sPortNumber);
+ }
+ }
+ else
+ {
+ sURL.append(sType + ":" + sHostName);
+ if ( !sPortNumber.isEmpty() )
+ {
+ sURL.append(":" + sPortNumber);
+ }
+ if ( !sDatabaseName.isEmpty() )
+ {
+ sURL.append(":" + sDatabaseName);
+ }
+ }
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_URL,Any(sURL.makeStringAndClear()));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OXMLServerDatabase::~OXMLServerDatabase()
+{
+
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlServerDatabase.hxx b/dbaccess/source/filter/xml/xmlServerDatabase.hxx
new file mode 100644
index 000000000..ec3401fff
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlServerDatabase.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLServerDatabase : public SvXMLImportContext
+ {
+ public:
+
+ OXMLServerDatabase( ODBFilter& rImport,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList );
+ virtual ~OXMLServerDatabase() override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlStyleImport.cxx b/dbaccess/source/filter/xml/xmlStyleImport.cxx
new file mode 100644
index 000000000..ddadc5e3b
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlStyleImport.cxx
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlStyleImport.hxx"
+
+#include <xmloff/maptype.hxx>
+#include <xmloff/xmlimppr.hxx>
+#include <xmloff/families.hxx>
+#include <xmloff/xmlnumfi.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <osl/diagnose.h>
+#include "xmlfilter.hxx"
+#include "xmlHelper.hxx"
+
+namespace dbaxml
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace xmloff::token;
+
+
+OTableStyleContext::OTableStyleContext( ODBFilter& rImport,
+ SvXMLStylesContext& rStyles, XmlStyleFamily nFamily )
+ :XMLPropStyleContext( rImport, rStyles, nFamily, false )
+ ,pStyles(&rStyles)
+ ,m_nNumberFormat(-1)
+{
+
+}
+
+OTableStyleContext::~OTableStyleContext()
+{
+
+}
+
+void OTableStyleContext::FillPropertySet(
+ const Reference< XPropertySet > & rPropSet )
+{
+ if ( !IsDefaultStyle() )
+ {
+ if ( GetFamily() == XmlStyleFamily::TABLE_TABLE )
+ {
+ if ( !sPageStyle.isEmpty() )
+ {
+ AddProperty(CTF_DB_MASTERPAGENAME, Any(sPageStyle));
+ }
+ }
+ else if ( GetFamily() == XmlStyleFamily::TABLE_COLUMN )
+ {
+ if ((m_nNumberFormat == -1) && !m_sDataStyleName.isEmpty())
+ {
+ SvXMLNumFormatContext* pStyle = const_cast<SvXMLNumFormatContext*>(dynamic_cast< const SvXMLNumFormatContext* >(pStyles->FindStyleChildContext(
+ XmlStyleFamily::DATA_STYLE, m_sDataStyleName, true)));
+ if ( !pStyle )
+ {
+ OTableStylesContext* pMyStyles = dynamic_cast<OTableStylesContext* >(GetOwnImport().GetAutoStyles());
+ if ( pMyStyles )
+ pStyle = const_cast<SvXMLNumFormatContext*>(dynamic_cast< const SvXMLNumFormatContext* >(pMyStyles->
+ FindStyleChildContext(XmlStyleFamily::DATA_STYLE, m_sDataStyleName, true)));
+ else {
+ OSL_FAIL("not possible to get style");
+ }
+ }
+ if ( pStyle )
+ {
+ uno::Any aNumberFormat;
+ m_nNumberFormat = pStyle->GetKey();
+ aNumberFormat <<= m_nNumberFormat;
+ AddProperty(CTF_DB_NUMBERFORMAT, aNumberFormat);
+ }
+ }
+ }
+ }
+ XMLPropStyleContext::FillPropertySet(rPropSet);
+}
+
+void OTableStyleContext::SetDefaults()
+{
+}
+
+void OTableStyleContext::AddProperty(const sal_Int16 nContextID, const uno::Any& rValue)
+{
+ sal_Int32 nIndex(static_cast<OTableStylesContext *>(pStyles)->GetIndex(nContextID));
+ OSL_ENSURE(nIndex != -1, "Property not found in Map");
+ XMLPropertyState aPropState(nIndex, rValue);
+ GetProperties().push_back(aPropState); // has to be inserted in a sort order later
+}
+
+void OTableStyleContext::SetAttribute( sal_Int32 nElement,
+ const OUString& rValue )
+{
+ switch(nElement & TOKEN_MASK)
+ {
+ case XML_DATA_STYLE_NAME:
+ m_sDataStyleName = rValue;
+ break;
+ case XML_MASTER_PAGE_NAME:
+ sPageStyle = rValue;
+ break;
+ default:
+ XMLPropStyleContext::SetAttribute( nElement, rValue );
+ }
+}
+
+ODBFilter& OTableStyleContext::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+
+OTableStylesContext::OTableStylesContext( SvXMLImport& rImport,
+ bool bTempAutoStyles )
+ : SvXMLStylesContext( rImport )
+ , m_nNumberFormatIndex(-1)
+ , m_nMasterPageNameIndex(-1)
+ , bAutoStyles(bTempAutoStyles)
+{
+
+}
+
+OTableStylesContext::~OTableStylesContext()
+{
+
+}
+
+void OTableStylesContext::endFastElement(sal_Int32 )
+{
+ if (bAutoStyles)
+ GetImport().GetTextImport()->SetAutoStyles( this );
+ else
+ GetImport().GetStyles()->CopyStylesToDoc(true);
+}
+
+rtl::Reference < SvXMLImportPropertyMapper >
+ OTableStylesContext::GetImportPropertyMapper(
+ XmlStyleFamily nFamily ) const
+{
+ rtl::Reference < SvXMLImportPropertyMapper > xMapper = SvXMLStylesContext::GetImportPropertyMapper(nFamily);
+
+ if (!xMapper.is())
+ {
+ switch( nFamily )
+ {
+ case XmlStyleFamily::TABLE_TABLE:
+ {
+ if ( !m_xTableImpPropMapper.is() )
+ m_xTableImpPropMapper = new SvXMLImportPropertyMapper( const_cast<OTableStylesContext*>(this)->GetOwnImport().GetTableStylesPropertySetMapper(), const_cast<SvXMLImport&>(GetImport()) );
+ xMapper = m_xTableImpPropMapper;
+ }
+ break;
+ case XmlStyleFamily::TABLE_COLUMN:
+ {
+ if ( !m_xColumnImpPropMapper.is() )
+ m_xColumnImpPropMapper = new SvXMLImportPropertyMapper( const_cast<OTableStylesContext*>(this)->GetOwnImport().GetColumnStylesPropertySetMapper(), const_cast<SvXMLImport&>(GetImport()) );
+ xMapper = m_xColumnImpPropMapper;
+ }
+ break;
+ case XmlStyleFamily::TABLE_CELL:
+ {
+ if ( !m_xCellImpPropMapper.is() )
+ m_xCellImpPropMapper = new SvXMLImportPropertyMapper( const_cast<OTableStylesContext*>(this)->GetOwnImport().GetCellStylesPropertySetMapper(), const_cast<SvXMLImport&>(GetImport()) );
+ xMapper = m_xCellImpPropMapper;
+ }
+ break;
+ default: break;
+ }
+ }
+
+ return xMapper;
+}
+
+SvXMLStyleContext *OTableStylesContext::CreateStyleStyleChildContext(
+ XmlStyleFamily nFamily, sal_Int32 nElement,
+ const Reference< xml::sax::XFastAttributeList > & xAttrList )
+{
+ SvXMLStyleContext *pStyle = SvXMLStylesContext::CreateStyleStyleChildContext( nFamily, nElement,
+ xAttrList );
+ if (pStyle)
+ return pStyle;
+
+ switch( nFamily )
+ {
+ case XmlStyleFamily::TABLE_TABLE:
+ case XmlStyleFamily::TABLE_COLUMN:
+ case XmlStyleFamily::TABLE_CELL:
+ return new OTableStyleContext( GetOwnImport(), *this, nFamily );
+ default: break;
+ }
+
+ return nullptr;
+}
+
+OUString OTableStylesContext::GetServiceName( XmlStyleFamily nFamily ) const
+{
+ OUString sServiceName = SvXMLStylesContext::GetServiceName(nFamily);
+ if (sServiceName.isEmpty())
+ {
+ switch( nFamily )
+ {
+ case XmlStyleFamily::TABLE_TABLE:
+ sServiceName = XML_STYLE_FAMILY_TABLE_TABLE_STYLES_NAME;
+ break;
+ case XmlStyleFamily::TABLE_COLUMN:
+ sServiceName = XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME;
+ break;
+ case XmlStyleFamily::TABLE_CELL:
+ sServiceName = XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME;
+ break;
+ default: break;
+ }
+ }
+ return sServiceName;
+}
+
+sal_Int32 OTableStylesContext::GetIndex(const sal_Int16 nContextID)
+{
+ if ( nContextID == CTF_DB_NUMBERFORMAT )
+ {
+ if (m_nNumberFormatIndex == -1)
+ m_nNumberFormatIndex =
+ GetImportPropertyMapper(XmlStyleFamily::TABLE_COLUMN)->getPropertySetMapper()->FindEntryIndex(nContextID);
+ return m_nNumberFormatIndex;
+ }
+ else if ( nContextID == CTF_DB_MASTERPAGENAME )
+ {
+ if (m_nMasterPageNameIndex == -1)
+ m_nMasterPageNameIndex =
+ GetImportPropertyMapper(XmlStyleFamily::TABLE_TABLE)->getPropertySetMapper()->FindEntryIndex(nContextID);
+ return m_nMasterPageNameIndex;
+ }
+ else
+ return -1;
+}
+
+ODBFilter& OTableStylesContext::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+} // dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlStyleImport.hxx b/dbaccess/source/filter/xml/xmlStyleImport.hxx
new file mode 100644
index 000000000..d3fc001b0
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlStyleImport.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/prstylei.hxx>
+#include <xmloff/xmlimppr.hxx>
+
+namespace dbaxml
+{
+ class ODBFilter;
+
+ class OTableStyleContext : public XMLPropStyleContext
+ {
+ OUString m_sDataStyleName;
+ OUString sPageStyle;
+ SvXMLStylesContext* pStyles;
+ sal_Int32 m_nNumberFormat;
+
+ ODBFilter& GetOwnImport();
+
+ protected:
+
+ virtual void SetAttribute( sal_Int32 nElement,
+ const OUString& rValue ) override;
+
+ public:
+
+
+ OTableStyleContext( ODBFilter& rImport,
+ SvXMLStylesContext& rStyles, XmlStyleFamily nFamily );
+
+ virtual ~OTableStyleContext() override;
+
+ virtual void FillPropertySet(const css::uno::Reference<
+ css::beans::XPropertySet > & rPropSet ) override;
+
+ virtual void SetDefaults() override;
+
+ void AddProperty(sal_Int16 nContextID, const css::uno::Any& aValue);
+ };
+
+ class OTableStylesContext : public SvXMLStylesContext
+ {
+ sal_Int32 m_nNumberFormatIndex;
+ sal_Int32 m_nMasterPageNameIndex;
+ bool bAutoStyles : 1;
+
+ mutable rtl::Reference < SvXMLImportPropertyMapper > m_xTableImpPropMapper;
+ mutable rtl::Reference < SvXMLImportPropertyMapper > m_xColumnImpPropMapper;
+ mutable rtl::Reference < SvXMLImportPropertyMapper > m_xCellImpPropMapper;
+
+ ODBFilter& GetOwnImport();
+
+ protected:
+
+ // Create a style context.
+ using SvXMLStylesContext::CreateStyleStyleChildContext;
+ virtual SvXMLStyleContext *CreateStyleStyleChildContext(
+ XmlStyleFamily nFamily,
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
+
+ public:
+
+
+ OTableStylesContext( SvXMLImport& rImport, bool bAutoStyles );
+ virtual ~OTableStylesContext() override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ virtual rtl::Reference < SvXMLImportPropertyMapper > GetImportPropertyMapper(
+ XmlStyleFamily nFamily ) const override;
+ virtual OUString GetServiceName( XmlStyleFamily nFamily ) const override;
+
+ sal_Int32 GetIndex(const sal_Int16 nContextID);
+ };
+} // dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlTable.cxx b/dbaccess/source/filter/xml/xmlTable.cxx
new file mode 100644
index 000000000..403486ee5
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlTable.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlTable.hxx"
+#include "xmlfilter.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include "xmlEnums.hxx"
+#include "xmlStyleImport.hxx"
+#include "xmlHierarchyCollection.hxx"
+#include <strings.hxx>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLTable::OXMLTable( ODBFilter& _rImport
+ ,const uno::Reference< XFastAttributeList > & _xAttrList
+ ,const uno::Reference< css::container::XNameAccess >& _xParentContainer
+ ,const OUString& _sServiceName
+ )
+ :SvXMLImportContext( _rImport )
+ ,m_xParentContainer(_xParentContainer)
+ ,m_bApplyFilter(false)
+ ,m_bApplyOrder(false)
+{
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ OUString sValue = aIter.toString();
+
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_NAME:
+ m_sName = sValue;
+ break;
+ case XML_CATALOG_NAME:
+ m_sCatalog = sValue;
+ break;
+ case XML_SCHEMA_NAME:
+ m_sSchema = sValue;
+ break;
+ case XML_STYLE_NAME:
+ m_sStyleName = sValue;
+ break;
+ case XML_APPLY_FILTER:
+ m_bApplyFilter = sValue == "true";
+ break;
+ case XML_APPLY_ORDER:
+ m_bApplyOrder = sValue == "true";
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+ uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"Name", uno::Any(m_sName)}, // set as folder
+ {"Parent", uno::Any(m_xParentContainer)}
+ }));
+ m_xTable.set(
+ GetOwnImport().GetComponentContext()->getServiceManager()->createInstanceWithArgumentsAndContext(_sServiceName,aArguments, GetOwnImport().GetComponentContext()),
+ UNO_QUERY);
+}
+
+OXMLTable::~OXMLTable()
+{
+
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLTable::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement & TOKEN_MASK )
+ {
+ case XML_FILTER_STATEMENT:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ OUString s1,s2,s3;
+ fillAttributes(xAttrList,m_sFilterStatement,s1,s2,s3);
+ }
+ break;
+ case XML_ORDER_STATEMENT:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ OUString s1,s2,s3;
+ fillAttributes(xAttrList,m_sOrderStatement,s1,s2,s3);
+ }
+ break;
+
+ case XML_COLUMNS:
+ {
+ GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ uno::Reference< XColumnsSupplier > xColumnsSup(m_xTable,UNO_QUERY);
+ uno::Reference< XNameAccess > xColumns;
+ if ( xColumnsSup.is() )
+ {
+ xColumns = xColumnsSup->getColumns();
+ }
+ pContext = new OXMLHierarchyCollection( GetOwnImport(), xColumns,m_xTable);
+ }
+ break;
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLTable::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+void OXMLTable::setProperties(uno::Reference< XPropertySet > & _xProp )
+{
+ try
+ {
+ if ( _xProp.is() )
+ {
+ _xProp->setPropertyValue(PROPERTY_APPLYFILTER,Any(m_bApplyFilter));
+ _xProp->setPropertyValue(PROPERTY_FILTER,Any(m_sFilterStatement));
+
+ if ( _xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_APPLYORDER) )
+ _xProp->setPropertyValue(PROPERTY_APPLYORDER,Any(m_bApplyOrder));
+ _xProp->setPropertyValue(PROPERTY_ORDER,Any(m_sOrderStatement));
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "OXMLTable::EndElement -> exception caught");
+ }
+}
+
+void OXMLTable::endFastElement(sal_Int32 )
+{
+ uno::Reference<XNameContainer> xNameContainer(m_xParentContainer,UNO_QUERY);
+ if ( !xNameContainer.is() )
+ return;
+
+ try
+ {
+ if ( m_xTable.is() )
+ {
+ setProperties(m_xTable);
+
+ if ( !m_sStyleName.isEmpty() )
+ {
+ const SvXMLStylesContext* pAutoStyles = GetOwnImport().GetAutoStyles();
+ if ( pAutoStyles )
+ {
+ OTableStyleContext* pAutoStyle = const_cast<OTableStyleContext*>(dynamic_cast< const OTableStyleContext* >(pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_TABLE,m_sStyleName)));
+ if ( pAutoStyle )
+ {
+ pAutoStyle->FillPropertySet(m_xTable);
+ }
+ }
+ }
+
+ xNameContainer->insertByName(m_sName,Any(m_xTable));
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "OXMLQuery::EndElement");
+ }
+
+}
+
+void OXMLTable::fillAttributes(const uno::Reference< XFastAttributeList > & _xAttrList
+ ,OUString& _rsCommand
+ ,OUString& _rsTableName
+ ,OUString& _rsTableSchema
+ ,OUString& _rsTableCatalog
+ )
+{
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList ))
+ {
+ OUString sValue = aIter.toString();
+
+ switch( aIter.getToken() & TOKEN_MASK )
+ {
+ case XML_COMMAND:
+ _rsCommand = sValue;
+ break;
+ case XML_CATALOG_NAME:
+ _rsTableCatalog = sValue;
+ break;
+ case XML_SCHEMA_NAME:
+ _rsTableSchema = sValue;
+ break;
+ case XML_QUERY_NAME:
+ _rsTableName = sValue;
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("dbaccess", aIter);
+ }
+ }
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlTable.hxx b/dbaccess/source/filter/xml/xmlTable.hxx
new file mode 100644
index 000000000..cee19ef19
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlTable.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLTable : public SvXMLImportContext
+ {
+ protected:
+ css::uno::Reference< css::container::XNameAccess > m_xParentContainer;
+ css::uno::Reference< css::beans::XPropertySet > m_xTable;
+ OUString m_sFilterStatement;
+ OUString m_sOrderStatement;
+ OUString m_sName;
+ OUString m_sSchema;
+ OUString m_sCatalog;
+ OUString m_sStyleName;
+ bool m_bApplyFilter;
+ bool m_bApplyOrder;
+
+ ODBFilter& GetOwnImport();
+
+ static void fillAttributes( const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList
+ ,OUString& _rsCommand
+ ,OUString& _rsTableName
+ ,OUString& _rsTableSchema
+ ,OUString& _rsTableCatalog
+ );
+
+ virtual void setProperties(css::uno::Reference< css::beans::XPropertySet > & _xProp);
+ public:
+
+ OXMLTable( ODBFilter& rImport
+ ,const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList
+ ,const css::uno::Reference< css::container::XNameAccess >& _xParentContainer
+ ,const OUString& _sServiceName
+ );
+ virtual ~OXMLTable() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlTableFilterList.cxx b/dbaccess/source/filter/xml/xmlTableFilterList.cxx
new file mode 100644
index 000000000..a6541684a
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlTableFilterList.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlTableFilterList.hxx"
+#include "xmlTableFilterPattern.hxx"
+#include "xmlEnums.hxx"
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/ProgressBarHelper.hxx>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/sequence.hxx>
+#include <xmloff/xmlimp.hxx>
+#include "xmlfilter.hxx"
+
+namespace dbaxml
+{
+ using namespace ::xmloff::token;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLTableFilterList::OXMLTableFilterList( SvXMLImport& rImport)
+ :SvXMLImportContext( rImport )
+{
+
+}
+
+OXMLTableFilterList::~OXMLTableFilterList()
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLTableFilterList::createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ if ( IsTokenInNamespace(nElement, XML_NAMESPACE_DB) ||
+ IsTokenInNamespace(nElement, XML_NAMESPACE_DB_OASIS) )
+ {
+ GetImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ switch (nElement & TOKEN_MASK)
+ {
+ case XML_TABLE_FILTER_PATTERN:
+ pContext = new OXMLTableFilterPattern( GetImport(), true,*this);
+ break;
+ case XML_TABLE_TYPE:
+ pContext = new OXMLTableFilterPattern( GetImport(), false,*this);
+ break;
+ case XML_TABLE_INCLUDE_FILTER:
+ pContext = new OXMLTableFilterList( GetImport() );
+ break;
+ default: break;
+ }
+ }
+
+ return pContext;
+}
+
+ODBFilter& OXMLTableFilterList::GetOwnImport()
+{
+ return static_cast<ODBFilter&>(GetImport());
+}
+
+void OXMLTableFilterList::endFastElement(sal_Int32 )
+{
+ Reference<XPropertySet> xDataSource(GetOwnImport().getDataSource());
+ if ( xDataSource.is() )
+ {
+ if ( !m_aPatterns.empty() )
+ xDataSource->setPropertyValue(PROPERTY_TABLEFILTER,Any(comphelper::containerToSequence(m_aPatterns)));
+ if ( !m_aTypes.empty() )
+ xDataSource->setPropertyValue(PROPERTY_TABLETYPEFILTER,Any(comphelper::containerToSequence(m_aTypes)));
+ }
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlTableFilterList.hxx b/dbaccess/source/filter/xml/xmlTableFilterList.hxx
new file mode 100644
index 000000000..1988bdd29
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlTableFilterList.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <xmloff/xmlictxt.hxx>
+#include <vector>
+
+namespace dbaxml
+{
+ class ODBFilter;
+ class OXMLTableFilterList : public SvXMLImportContext
+ {
+ std::vector< OUString> m_aPatterns;
+ std::vector< OUString> m_aTypes;
+
+ ODBFilter& GetOwnImport();
+ public:
+
+ OXMLTableFilterList( SvXMLImport& rImport );
+
+ virtual ~OXMLTableFilterList() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
+
+ /** pushes a new TableFilterPattern to the list of patterns
+ @param _sTableFilterPattern
+ The new filter pattern.
+ */
+ void pushTableFilterPattern(const OUString& _sTableFilterPattern)
+ {
+ m_aPatterns.push_back(_sTableFilterPattern);
+ }
+
+ /** pushes a new TableTypeFilter to the list of patterns
+ @param _sTypeFilter
+ The new type filter.
+ */
+ void pushTableTypeFilter(const OUString& _sTypeFilter)
+ {
+ m_aTypes.push_back(_sTypeFilter);
+ }
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlTableFilterPattern.cxx b/dbaccess/source/filter/xml/xmlTableFilterPattern.cxx
new file mode 100644
index 000000000..0c4b2892d
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlTableFilterPattern.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xmlTableFilterPattern.hxx"
+#include "xmlTableFilterList.hxx"
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+
+OXMLTableFilterPattern::OXMLTableFilterPattern( SvXMLImport& rImport
+ ,bool _bNameFilter
+ ,OXMLTableFilterList& _rParent)
+ :SvXMLImportContext( rImport )
+ ,m_rParent(_rParent)
+ ,m_bNameFilter(_bNameFilter)
+{
+
+}
+
+OXMLTableFilterPattern::~OXMLTableFilterPattern()
+{
+
+}
+
+void OXMLTableFilterPattern::characters( const OUString& rChars )
+{
+ maBuffer.append(rChars);
+}
+
+void OXMLTableFilterPattern::endFastElement( sal_Int32 )
+{
+ OUString sChars = maBuffer.makeStringAndClear();
+ if ( m_bNameFilter )
+ m_rParent.pushTableFilterPattern(sChars);
+ else
+ m_rParent.pushTableTypeFilter(sChars);
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlTableFilterPattern.hxx b/dbaccess/source/filter/xml/xmlTableFilterPattern.hxx
new file mode 100644
index 000000000..8f0b64f37
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlTableFilterPattern.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustrbuf.hxx>
+#include <xmloff/xmlictxt.hxx>
+
+namespace dbaxml
+{
+ class OXMLTableFilterList;
+ class OXMLTableFilterPattern : public SvXMLImportContext
+ {
+ OXMLTableFilterList& m_rParent;
+ bool m_bNameFilter;
+ OUStringBuffer maBuffer;
+ public:
+ OXMLTableFilterPattern( SvXMLImport& rImport
+ ,bool _bNameFilter
+ ,OXMLTableFilterList& _rParent);
+
+ virtual ~OXMLTableFilterPattern() override;
+
+ virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override;
+ virtual void SAL_CALL characters( const OUString& rChars ) override;
+ };
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlfilter.cxx b/dbaccess/source/filter/xml/xmlfilter.cxx
new file mode 100644
index 000000000..d089359c8
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlfilter.cxx
@@ -0,0 +1,617 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <vcl/errinf.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/packages/zip/ZipIOException.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include "xmlfilter.hxx"
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlscripti.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/SAXParseException.hpp>
+#include <xmloff/ProgressBarHelper.hxx>
+#include <sfx2/docfile.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include "xmlDatabase.hxx"
+#include "xmlEnums.hxx"
+#include <strings.hxx>
+#include <xmloff/DocumentSettingsContext.hxx>
+#include "xmlStyleImport.hxx"
+#include <xmloff/xmluconv.hxx>
+#include "xmlHelper.hxx"
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <svtools/sfxecode.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <connectivity/DriversConfig.hxx>
+#include <rtl/uri.hxx>
+
+using namespace ::com::sun::star;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sdb_DBFilter_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ::dbaxml::ODBFilter(context));
+}
+
+
+namespace dbaxml
+{
+ using namespace ::com::sun::star::util;
+ /// read a component (file + filter version)
+static ErrCode ReadThroughComponent(
+ const uno::Reference<XInputStream>& xInputStream,
+ const uno::Reference<XComponent>& xModelComponent,
+ const uno::Reference<XComponentContext> & rxContext,
+ ODBFilter& _rFilter )
+{
+ OSL_ENSURE(xInputStream.is(), "input stream missing");
+ OSL_ENSURE(xModelComponent.is(), "document missing");
+ OSL_ENSURE(rxContext.is(), "factory missing");
+
+ // prepare ParserInputSource
+ InputSource aParserInput;
+ aParserInput.aInputStream = xInputStream;
+
+ // connect model and filter
+ _rFilter.setTargetDocument( xModelComponent );
+
+ // finally, parser the stream
+ try
+ {
+ _rFilter.parseStream( aParserInput );
+ }
+ catch (const SAXParseException&)
+ {
+#if OSL_DEBUG_LEVEL > 0
+ TOOLS_WARN_EXCEPTION("dbaccess", "SAX parse exception caught while importing");
+#endif
+ return ErrCode(1);
+ }
+ catch (const SAXException&)
+ {
+ return ErrCode(1);
+ }
+ catch (const packages::zip::ZipIOException&)
+ {
+ return ERRCODE_IO_BROKENPACKAGE;
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // success!
+ return ERRCODE_NONE;
+}
+
+
+/// read a component (storage version)
+static ErrCode ReadThroughComponent(
+ const uno::Reference< embed::XStorage >& xStorage,
+ const uno::Reference<XComponent>& xModelComponent,
+ const char* pStreamName,
+ const uno::Reference<XComponentContext> & rxContext,
+ ODBFilter& _rFilter)
+{
+ OSL_ENSURE( xStorage.is(), "Need storage!");
+ OSL_ENSURE(nullptr != pStreamName, "Please, please, give me a name!");
+
+ if ( !xStorage )
+ // TODO/LATER: better error handling
+ return ErrCode(1);
+
+ uno::Reference< io::XStream > xDocStream;
+
+ try
+ {
+ // open stream (and set parser input)
+ OUString sStreamName = OUString::createFromAscii(pStreamName);
+ if ( !xStorage->hasByName( sStreamName ) || !xStorage->isStreamElement( sStreamName ) )
+ {
+ // stream name not found! return immediately with OK signal
+ return ERRCODE_NONE;
+ }
+
+ // get input stream
+ xDocStream = xStorage->openStreamElement( sStreamName, embed::ElementModes::READ );
+ }
+ catch (const packages::WrongPasswordException&)
+ {
+ return ERRCODE_SFX_WRONGPASSWORD;
+ }
+ catch (const uno::Exception&)
+ {
+ return ErrCode(1); // TODO/LATER: error handling
+ }
+
+ uno::Reference< XInputStream > xInputStream = xDocStream->getInputStream();
+ // read from the stream
+ return ReadThroughComponent( xInputStream
+ ,xModelComponent
+ ,rxContext
+ ,_rFilter );
+}
+
+
+ODBFilter::ODBFilter( const uno::Reference< XComponentContext >& _rxContext )
+ : SvXMLImport(_rxContext, getImplementationName_Static())
+ , m_bNewFormat(false)
+{
+
+ GetMM100UnitConverter().SetCoreMeasureUnit(util::MeasureUnit::MM_10TH);
+ GetMM100UnitConverter().SetXMLMeasureUnit(util::MeasureUnit::CM);
+ GetNamespaceMap().Add( "_db",
+ GetXMLToken(XML_N_DB),
+ XML_NAMESPACE_DB );
+
+ GetNamespaceMap().Add( "__db",
+ GetXMLToken(XML_N_DB_OASIS),
+ XML_NAMESPACE_DB );
+}
+
+
+ODBFilter::~ODBFilter() noexcept
+{
+
+}
+
+
+OUString ODBFilter::getImplementationName_Static()
+{
+ return "com.sun.star.comp.sdb.DBFilter";
+}
+
+
+namespace {
+class FocusWindowWaitGuard
+{
+public:
+ FocusWindowWaitGuard()
+ {
+ SolarMutexGuard aGuard;
+ mpWindow.set(Application::GetFocusWindow());
+ if (mpWindow)
+ mpWindow->EnterWait();
+ }
+ ~FocusWindowWaitGuard()
+ {
+ if (mpWindow)
+ {
+ SolarMutexGuard aGuard;
+ mpWindow->LeaveWait();
+ }
+ }
+private:
+ VclPtr<vcl::Window> mpWindow;
+};
+}
+
+sal_Bool SAL_CALL ODBFilter::filter( const Sequence< PropertyValue >& rDescriptor )
+{
+ FocusWindowWaitGuard aWindowFocusGuard;
+ bool bRet = false;
+
+ if ( GetModel().is() )
+ bRet = implImport( rDescriptor );
+
+ return bRet;
+}
+
+
+bool ODBFilter::implImport( const Sequence< PropertyValue >& rDescriptor )
+{
+ OUString sFileName;
+ ::comphelper::NamedValueCollection aMediaDescriptor( rDescriptor );
+
+ uno::Reference<embed::XStorage> xStorage = GetSourceStorage();
+
+ bool bRet = true;
+ if (!xStorage.is())
+ {
+ if (aMediaDescriptor.has("URL"))
+ sFileName = aMediaDescriptor.getOrDefault("URL", OUString());
+ if (sFileName.isEmpty() && aMediaDescriptor.has("FileName"))
+ sFileName = aMediaDescriptor.getOrDefault("FileName", sFileName);
+
+ OSL_ENSURE(!sFileName.isEmpty(), "ODBFilter::implImport: no URL given!");
+ bRet = !sFileName.isEmpty();
+ }
+
+ if ( bRet )
+ {
+
+ tools::SvRef<SfxMedium> pMedium;
+ if (!xStorage.is())
+ {
+ OUString sStreamRelPath;
+ if (sFileName.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:"))
+ {
+ // In this case the authority contains the real path, and the path is the embedded stream name.
+ auto const uri = css::uri::UriReferenceFactory::create(GetComponentContext())
+ ->parse(sFileName);
+ if (uri.is() && uri->isAbsolute()
+ && uri->hasAuthority() && !uri->hasQuery() && !uri->hasFragment())
+ {
+ auto const auth = uri->getAuthority();
+ auto const decAuth = rtl::Uri::decode(
+ auth, rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8);
+ auto path = uri->getPath();
+ if (!path.isEmpty()) {
+ assert(path[0] == '/');
+ path = path.copy(1);
+ }
+ auto const decPath = rtl::Uri::decode(
+ path, rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8);
+ //TODO: really decode path?
+ if (auth.isEmpty() == decAuth.isEmpty() && path.isEmpty() == decPath.isEmpty())
+ {
+ // Decoding of auth and path to UTF-8 succeeded:
+ sFileName = decAuth;
+ sStreamRelPath = decPath;
+ } else {
+ SAL_WARN(
+ "dbaccess",
+ "<" << sFileName << "> cannot be parse as vnd.sun.star.pkg URL");
+ }
+ } else {
+ SAL_WARN(
+ "dbaccess",
+ "<" << sFileName << "> cannot be parse as vnd.sun.star.pkg URL");
+ }
+ }
+
+ pMedium = new SfxMedium(sFileName, (StreamMode::READ | StreamMode::NOCREATE));
+ try
+ {
+ xStorage.set(pMedium->GetStorage(false), UNO_SET_THROW);
+
+ if (!sStreamRelPath.isEmpty())
+ xStorage = xStorage->openStorageElement(sStreamRelPath, embed::ElementModes::READ);
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception&)
+ {
+ Any aError = ::cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(OUString(), *this, aError);
+ }
+ }
+
+ uno::Reference<sdb::XOfficeDatabaseDocument> xOfficeDoc(GetModel(),UNO_QUERY_THROW);
+ m_xDataSource.set(xOfficeDoc->getDataSource(),UNO_QUERY_THROW);
+ uno::Reference< XNumberFormatsSupplier > xNum(m_xDataSource->getPropertyValue(PROPERTY_NUMBERFORMATSSUPPLIER),UNO_QUERY);
+ SetNumberFormatsSupplier(xNum);
+
+ uno::Reference<XComponent> xModel(GetModel());
+ ErrCode nRet = ReadThroughComponent( xStorage
+ ,xModel
+ ,"settings.xml"
+ ,GetComponentContext()
+ ,*this
+ );
+
+ if ( nRet == ERRCODE_NONE )
+ nRet = ReadThroughComponent( xStorage
+ ,xModel
+ ,"content.xml"
+ ,GetComponentContext()
+ ,*this
+ );
+
+ bRet = nRet == ERRCODE_NONE;
+
+ if ( bRet )
+ {
+ uno::Reference< XModifiable > xModi(GetModel(),UNO_QUERY);
+ if ( xModi.is() )
+ xModi->setModified(false);
+ }
+ else
+ {
+ if ( nRet == ERRCODE_IO_BROKENPACKAGE )
+ ;// TODO/LATER: no way to transport the error outside from the filter!
+ else
+ {
+ // TODO/LATER: this is completely wrong! Filter code should never call ErrorHandler directly! But for now this is the only way!
+ ErrorHandler::HandleError( nRet );
+ if( nRet.IsWarning() )
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+namespace {
+
+class DBXMLDocumentSettingsContext : public SvXMLImportContext
+{
+public:
+ DBXMLDocumentSettingsContext(SvXMLImport & rImport)
+ : SvXMLImportContext(rImport)
+ {
+ }
+
+ virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) override
+ {
+ if (nElement == XML_ELEMENT(OFFICE, XML_SETTINGS))
+ {
+ return new XMLDocumentSettingsContext(GetImport());
+ }
+ return nullptr;
+ }
+};
+
+class DBXMLDocumentStylesContext : public SvXMLImportContext
+{
+public:
+ DBXMLDocumentStylesContext(SvXMLImport & rImport)
+ : SvXMLImportContext(rImport)
+ {
+ }
+
+ virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) override
+ {
+ ODBFilter & rImport(static_cast<ODBFilter&>(GetImport()));
+ switch (nElement)
+ {
+ case XML_ELEMENT(OFFICE, XML_STYLES):
+ case XML_ELEMENT(OOO, XML_STYLES):
+ rImport.GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ return rImport.CreateStylesContext(false);
+ case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES):
+ case XML_ELEMENT(OOO, XML_AUTOMATIC_STYLES):
+ rImport.GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ return rImport.CreateStylesContext(true);
+ }
+ return nullptr;
+ }
+};
+
+class DBXMLDocumentBodyContext : public SvXMLImportContext
+{
+public:
+ DBXMLDocumentBodyContext(SvXMLImport & rImport)
+ : SvXMLImportContext(rImport)
+ {
+ }
+
+ virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) override
+ {
+ ODBFilter & rImport(static_cast<ODBFilter&>(GetImport()));
+ switch (nElement)
+ {
+ case XML_ELEMENT(OFFICE, XML_DATABASE):
+ case XML_ELEMENT(OOO, XML_DATABASE):
+ rImport.GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ return new OXMLDatabase(rImport);
+ default: break;
+ }
+ return nullptr;
+ }
+};
+
+class DBXMLDocumentContentContext : public SvXMLImportContext
+{
+public:
+ DBXMLDocumentContentContext(SvXMLImport & rImport)
+ : SvXMLImportContext(rImport)
+ {
+ }
+
+ virtual uno::Reference< xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
+ sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) override
+ {
+ ODBFilter & rImport(static_cast<ODBFilter&>(GetImport()));
+ switch (nElement)
+ {
+ case XML_ELEMENT(OFFICE, XML_BODY):
+ case XML_ELEMENT(OOO, XML_BODY):
+ return new DBXMLDocumentBodyContext(rImport);
+ case XML_ELEMENT(OFFICE, XML_SCRIPTS):
+ return new XMLScriptContext(GetImport(), rImport.GetModel());
+ case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES):
+ case XML_ELEMENT(OOO, XML_AUTOMATIC_STYLES):
+ rImport.GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ return rImport.CreateStylesContext(true);
+ default: break;
+ }
+ return nullptr;
+ }
+};
+
+}
+
+SvXMLImportContext* ODBFilter::CreateFastContext(sal_Int32 nElement,
+ const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ SvXMLImportContext *pContext = nullptr;
+
+ switch( nElement )
+ {
+ case XML_ELEMENT(OFFICE, XML_DOCUMENT_SETTINGS):
+ case XML_ELEMENT(OOO, XML_DOCUMENT_SETTINGS):
+ GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP );
+ pContext = new DBXMLDocumentSettingsContext(*this);
+ break;
+ case XML_ELEMENT(OFFICE, XML_DOCUMENT_STYLES):
+ case XML_ELEMENT(OOO, XML_DOCUMENT_STYLES):
+ pContext = new DBXMLDocumentStylesContext(*this);
+ break;
+ case XML_ELEMENT(OFFICE, XML_DOCUMENT_CONTENT):
+ case XML_ELEMENT(OOO, XML_DOCUMENT_CONTENT):
+ pContext = new DBXMLDocumentContentContext(*this);
+ break;
+ }
+
+ return pContext;
+}
+
+
+void ODBFilter::SetViewSettings(const Sequence<PropertyValue>& aViewProps)
+{
+ const PropertyValue *pIter = aViewProps.getConstArray();
+ const PropertyValue *pEnd = pIter + aViewProps.getLength();
+ for (; pIter != pEnd; ++pIter)
+ {
+ if ( pIter->Name == "Queries" )
+ {
+ fillPropertyMap(pIter->Value,m_aQuerySettings);
+ }
+ else if ( pIter->Name == "Tables" )
+ {
+ fillPropertyMap(pIter->Value,m_aTablesSettings);
+ }
+ }
+}
+
+
+void ODBFilter::SetConfigurationSettings(const Sequence<PropertyValue>& aConfigProps)
+{
+ const PropertyValue *pIter = aConfigProps.getConstArray();
+ const PropertyValue *pEnd = pIter + aConfigProps.getLength();
+ for (; pIter != pEnd; ++pIter)
+ {
+ if ( pIter->Name == "layout-settings" )
+ {
+ Sequence<PropertyValue> aWindows;
+ pIter->Value >>= aWindows;
+ uno::Reference<XPropertySet> xProp(getDataSource());
+ if ( xProp.is() )
+ xProp->setPropertyValue(PROPERTY_LAYOUTINFORMATION,Any(aWindows));
+ }
+ }
+}
+
+
+void ODBFilter::fillPropertyMap(const Any& _rValue,TPropertyNameMap& _rMap)
+{
+ Sequence<PropertyValue> aWindows;
+ _rValue >>= aWindows;
+ const PropertyValue *pIter = aWindows.getConstArray();
+ const PropertyValue *pEnd = pIter + aWindows.getLength();
+ for (; pIter != pEnd; ++pIter)
+ {
+ Sequence<PropertyValue> aValue;
+ pIter->Value >>= aValue;
+ _rMap.emplace( pIter->Name,aValue );
+ }
+
+}
+
+SvXMLImportContext* ODBFilter::CreateStylesContext( bool bIsAutoStyle )
+{
+ SvXMLImportContext *pContext = new OTableStylesContext(*this, bIsAutoStyle);
+ if (bIsAutoStyle)
+ SetAutoStyles(static_cast<SvXMLStylesContext*>(pContext));
+ else
+ SetStyles(static_cast<SvXMLStylesContext*>(pContext));
+
+ return pContext;
+}
+
+
+rtl::Reference < XMLPropertySetMapper > const & ODBFilter::GetTableStylesPropertySetMapper() const
+{
+ if ( !m_xTableStylesPropertySetMapper.is() )
+ {
+ m_xTableStylesPropertySetMapper = OXMLHelper::GetTableStylesPropertySetMapper( false);
+ }
+ return m_xTableStylesPropertySetMapper;
+}
+
+
+rtl::Reference < XMLPropertySetMapper > const & ODBFilter::GetColumnStylesPropertySetMapper() const
+{
+ if ( !m_xColumnStylesPropertySetMapper.is() )
+ {
+ m_xColumnStylesPropertySetMapper = OXMLHelper::GetColumnStylesPropertySetMapper( false);
+ }
+ return m_xColumnStylesPropertySetMapper;
+}
+
+
+rtl::Reference < XMLPropertySetMapper > const & ODBFilter::GetCellStylesPropertySetMapper() const
+{
+ if ( !m_xCellStylesPropertySetMapper.is() )
+ {
+ m_xCellStylesPropertySetMapper = OXMLHelper::GetCellStylesPropertySetMapper( false);
+ }
+ return m_xCellStylesPropertySetMapper;
+}
+
+
+void ODBFilter::setPropertyInfo()
+{
+ Reference<XPropertySet> xDataSource(getDataSource());
+ if ( !xDataSource.is() )
+ return;
+
+ ::connectivity::DriversConfig aDriverConfig(GetComponentContext());
+ const OUString sURL = ::comphelper::getString(xDataSource->getPropertyValue(PROPERTY_URL));
+ ::comphelper::NamedValueCollection aDataSourceSettings = aDriverConfig.getProperties( sURL );
+
+ Sequence<PropertyValue> aInfo;
+ if ( !m_aInfoSequence.empty() )
+ aInfo = comphelper::containerToSequence(m_aInfoSequence);
+ aDataSourceSettings.merge( ::comphelper::NamedValueCollection( aInfo ), true );
+
+ aDataSourceSettings >>= aInfo;
+ if ( aInfo.hasElements() )
+ {
+ try
+ {
+ xDataSource->setPropertyValue(PROPERTY_INFO,Any(aInfo));
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/filter/xml/xmlfilter.hxx b/dbaccess/source/filter/xml/xmlfilter.hxx
new file mode 100644
index 000000000..ec776cd75
--- /dev/null
+++ b/dbaccess/source/filter/xml/xmlfilter.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/io/XActiveDataSource.hpp>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/xmlprmap.hxx>
+
+#include <map>
+#include <memory>
+
+
+namespace dbaxml
+{
+
+using namespace ::xmloff::token;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::xml::sax;
+
+
+class ODBFilter : public SvXMLImport
+{
+public:
+ typedef std::map< OUString, Sequence<PropertyValue> > TPropertyNameMap;
+private:
+ TPropertyNameMap m_aQuerySettings;
+ TPropertyNameMap m_aTablesSettings;
+ std::vector< css::beans::PropertyValue> m_aInfoSequence;
+
+ mutable rtl::Reference < XMLPropertySetMapper > m_xTableStylesPropertySetMapper;
+ mutable rtl::Reference < XMLPropertySetMapper > m_xColumnStylesPropertySetMapper;
+ mutable rtl::Reference < XMLPropertySetMapper > m_xCellStylesPropertySetMapper;
+ Reference<XPropertySet> m_xDataSource;
+ bool m_bNewFormat;
+
+ /// @throws RuntimeException
+ bool implImport( const Sequence< PropertyValue >& rDescriptor );
+
+ /** fills the map with the Properties
+ @param _rValue
+ The Any where the sequence resists in.
+ @param _rMap
+ The map to fill.
+ */
+ static void fillPropertyMap(const Any& _rValue,TPropertyNameMap& _rMap);
+
+public:
+ SvXMLImportContext* CreateStylesContext( bool bIsAutoStyle );
+
+protected:
+ // SvXMLImport
+ virtual SvXMLImportContext *CreateFastContext(sal_Int32 Element,
+ const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override;
+
+ virtual ~ODBFilter() noexcept override;
+public:
+
+ explicit ODBFilter( const Reference< XComponentContext >& _rxContext );
+
+ // XFilter
+ virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& rDescriptor ) override;
+
+ /// @throws css::uno::RuntimeException
+ static OUString getImplementationName_Static();
+
+ // helper class
+ virtual void SetViewSettings(const css::uno::Sequence<css::beans::PropertyValue>& aViewProps) override;
+ virtual void SetConfigurationSettings(const css::uno::Sequence<css::beans::PropertyValue>& aConfigProps) override;
+
+ const Reference<XPropertySet>& getDataSource() const { return m_xDataSource; }
+
+ const TPropertyNameMap& getQuerySettings() const { return m_aQuerySettings;}
+
+ rtl::Reference < XMLPropertySetMapper > const & GetTableStylesPropertySetMapper() const;
+ rtl::Reference < XMLPropertySetMapper > const & GetColumnStylesPropertySetMapper() const;
+ rtl::Reference < XMLPropertySetMapper > const & GetCellStylesPropertySetMapper() const;
+
+ /** add an Info to the sequence which will be appended to the data source
+ @param _rInfo The property to append.
+ */
+ void addInfo(const css::beans::PropertyValue& _rInfo)
+ {
+ m_aInfoSequence.push_back(_rInfo);
+ }
+
+ void setPropertyInfo();
+
+ bool isNewFormat() const { return m_bNewFormat; }
+ void setNewFormat(bool _bNewFormat) { m_bNewFormat = _bNewFormat; }
+};
+
+} // namespace dbaxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/inc/OAuthenticationContinuation.hxx b/dbaccess/source/inc/OAuthenticationContinuation.hxx
new file mode 100644
index 000000000..d1eac7b54
--- /dev/null
+++ b/dbaccess/source/inc/OAuthenticationContinuation.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <dbadllapi.hxx>
+
+#include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
+#include <com/sun/star/ucb/RememberAuthentication.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <rtl/ustring.hxx>
+#include <comphelper/interaction.hxx>
+
+namespace dbaccess
+{
+
+class OOO_DLLPUBLIC_DBA OAuthenticationContinuation :
+ public comphelper::OInteraction< css::ucb::XInteractionSupplyAuthentication >
+{
+ bool m_bRememberPassword : 1; // remember the password for this session ?
+
+ bool m_bCanSetUserName;
+ OUString m_sUser; // the user
+ OUString m_sPassword; // the user's password
+
+public:
+ OAuthenticationContinuation();
+
+ sal_Bool SAL_CALL canSetRealm( ) override;
+ void SAL_CALL setRealm( const OUString& Realm ) override;
+ sal_Bool SAL_CALL canSetUserName( ) override;
+ void SAL_CALL setUserName( const OUString& UserName ) override;
+ sal_Bool SAL_CALL canSetPassword( ) override;
+ void SAL_CALL setPassword( const OUString& Password ) override;
+ css::uno::Sequence< css::ucb::RememberAuthentication > SAL_CALL getRememberPasswordModes( css::ucb::RememberAuthentication& Default ) override;
+ void SAL_CALL setRememberPassword( css::ucb::RememberAuthentication Remember ) override;
+ sal_Bool SAL_CALL canSetAccount( ) override;
+ void SAL_CALL setAccount( const OUString& Account ) override;
+ css::uno::Sequence< css::ucb::RememberAuthentication > SAL_CALL getRememberAccountModes( css::ucb::RememberAuthentication& Default ) override;
+ void SAL_CALL setRememberAccount( css::ucb::RememberAuthentication Remember ) override;
+
+ void setCanChangeUserName( bool bVal ) { m_bCanSetUserName = bVal; }
+ const OUString& getUser() const { return m_sUser; }
+ const OUString& getPassword() const { return m_sPassword; }
+ bool getRememberPassword() const { return m_bRememberPassword; }
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/inc/apitools.hxx b/dbaccess/source/inc/apitools.hxx
new file mode 100644
index 000000000..7438c0872
--- /dev/null
+++ b/dbaccess/source/inc/apitools.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cppuhelper/component.hxx>
+#include <osl/mutex.hxx>
+
+// OSubComponent - a component which holds a hard ref to its parent
+// and is been hold itself (by the parent) with a weak ref
+class OSubComponent : public ::cppu::OComponentHelper
+{
+protected:
+ // the parent must support the tunnel implementation
+ css::uno::Reference< css::uno::XInterface > m_xParent;
+ virtual ~OSubComponent() override;
+
+public:
+ OSubComponent(::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::uno::XInterface >& _xParent);
+
+// css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+// css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL release() noexcept override;
+
+ operator css::uno::Reference< css::uno::XInterface > () const
+ { return static_cast<css::uno::XWeak *>(const_cast<OSubComponent *>(this)); }
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/inc/dsntypes.hxx b/dbaccess/source/inc/dsntypes.hxx
new file mode 100644
index 000000000..875d781d1
--- /dev/null
+++ b/dbaccess/source/inc/dsntypes.hxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+#include <vector>
+
+#include <dbadllapi.hxx>
+#include <connectivity/DriversConfig.hxx>
+
+namespace dbaccess
+{
+
+// DATASOURCE_TYPE
+/// known datasource types
+enum DATASOURCE_TYPE
+{
+ DST_MSACCESS = 1,
+ DST_MYSQL_ODBC = 2,
+ DST_MYSQL_JDBC = 3,
+ DST_ORACLE_JDBC = 4,
+ //5 was DST_ADABAS
+ DST_CALC = 6,
+ DST_DBASE = 7,
+ DST_FLAT = 8,
+ DST_JDBC = 9,
+ DST_ODBC = 10,
+ DST_ADO = 11,
+ DST_MOZILLA = 12,
+ DST_THUNDERBIRD = 13,
+ DST_LDAP = 14,
+ DST_OUTLOOK = 15,
+ DST_OUTLOOKEXP = 16,
+ DST_EVOLUTION = 17,
+ DST_EVOLUTION_GROUPWISE = 18,
+ DST_EVOLUTION_LDAP = 19,
+ DST_KAB = 20,
+ DST_MACAB = 21,
+ DST_MSACCESS_2007 = 22,
+ DST_EMBEDDED_HSQLDB = 23,
+ DST_MYSQL_NATIVE = 24,
+ DST_MYSQL_NATIVE_DIRECT = 25,
+ DST_FIREBIRD = 26,
+ DST_EMBEDDED_FIREBIRD = 27,
+ DST_POSTGRES = 28,
+ DST_WRITER = 29,
+
+ DST_USERDEFINE1, /// first user defined driver
+ DST_USERDEFINE2,
+ DST_USERDEFINE3,
+ DST_USERDEFINE4,
+ DST_USERDEFINE5,
+ DST_USERDEFINE6,
+ DST_USERDEFINE7,
+ DST_USERDEFINE8,
+ DST_USERDEFINE9,
+ DST_USERDEFINE10,
+
+ DST_UNKNOWN /// unrecognized type
+};
+
+#define PAGE_DBSETUPWIZARD_INTRO 0
+#define PAGE_DBSETUPWIZARD_DBASE 1
+#define PAGE_DBSETUPWIZARD_TEXT 2
+#define PAGE_DBSETUPWIZARD_MSACCESS 3
+#define PAGE_DBSETUPWIZARD_LDAP 4
+//5 was PAGE_DBSETUPWIZARD_ADABAS
+#define PAGE_DBSETUPWIZARD_MYSQL_INTRO 6
+#define PAGE_DBSETUPWIZARD_MYSQL_JDBC 7
+#define PAGE_DBSETUPWIZARD_MYSQL_ODBC 8
+#define PAGE_DBSETUPWIZARD_ORACLE 9
+#define PAGE_DBSETUPWIZARD_JDBC 10
+#define PAGE_DBSETUPWIZARD_ADO 11
+#define PAGE_DBSETUPWIZARD_ODBC 12
+#define PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET 13
+#define PAGE_DBSETUPWIZARD_AUTHENTIFICATION 14
+#define PAGE_DBSETUPWIZARD_FINAL 16
+#define PAGE_DBSETUPWIZARD_USERDEFINED 17
+#define PAGE_DBSETUPWIZARD_MYSQL_NATIVE 18
+
+// ODsnTypeCollection
+class OOO_DLLPUBLIC_DBA ODsnTypeCollection final
+{
+
+ std::vector<OUString> m_aDsnTypesDisplayNames; /// user readable names for the datasource types
+ std::vector<OUString> m_aDsnPrefixes; /// DSN prefixes which determine the type of a datasource
+ ::connectivity::DriversConfig m_aDriverConfig;
+
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 m_nLivingIterators; /// just for debugging reasons, counts the living iterators
+#endif
+
+public:
+ class TypeIterator;
+ friend class ODsnTypeCollection::TypeIterator;
+
+ ODsnTypeCollection(const css::uno::Reference< css::uno::XComponentContext >& _xContext);
+ ~ODsnTypeCollection();
+
+ /// get the datasource type display name from a DSN string
+ OUString getTypeDisplayName(std::u16string_view _sURL) const;
+
+ /// on a given string, cut the type prefix and return the result
+ OUString cutPrefix(std::u16string_view _sURL) const;
+
+ /// on a given string, return the type prefix
+ OUString getPrefix(const OUString& _sURL) const;
+
+ /// determines whether there is a driver for the given URL prefix/pattern
+ bool hasDriver( const char* _pAsciiPattern ) const;
+
+ /// on a given string, return the Java Driver Class
+ OUString getJavaDriverClass(std::u16string_view _sURL) const;
+
+ /// returns the media type of a file based database
+ OUString getMediaType(std::u16string_view _sURL) const;
+
+ /// returns the dsn prefix for a given media type
+ OUString getDatasourcePrefixFromMediaType(std::u16string_view _sMediaType, std::u16string_view _sExtension );
+
+ void extractHostNamePort(const OUString& _rDsn,OUString& _sDatabaseName,OUString& _rHostname,sal_Int32& _nPortNumber) const;
+
+ /// check if the given data source allows creation of tables
+ bool supportsTableCreation(std::u16string_view _sURL) const;
+
+ /// check if the given data source allows to show column description.
+ bool supportsColumnDescription(std::u16string_view _sURL) const;
+
+ // check if a Browse button may be shown to insert connection url
+ bool supportsBrowsing(std::u16string_view _sURL) const;
+
+ // check if a Create New Database button may be shown to insert connection url
+ bool supportsDBCreation(std::u16string_view _sURL) const;
+
+ /// check if the given data source type is based on the file system - i.e. the URL is a prefix plus a file URL
+ bool isFileSystemBased(std::u16string_view _sURL) const;
+
+ bool isConnectionUrlRequired(std::u16string_view _sURL) const;
+
+ /// checks if the given data source type embeds its data into the database document
+ static bool isEmbeddedDatabase( std::u16string_view _sURL );
+
+ static OUString getEmbeddedDatabase();
+
+ // returns true when the properties dialog can be shown, otherwise false.
+ static bool isShowPropertiesEnabled( const OUString& _sURL );
+
+ /** returns default settings for newly created databases of the given type.
+ */
+ css::uno::Sequence< css::beans::PropertyValue>
+ getDefaultDBSettings( std::u16string_view _sURL ) const;
+
+ /// get access to the first element of the types collection
+ inline TypeIterator begin() const;
+ /// get access to the (last + 1st) element of the types collection
+ inline TypeIterator end() const;
+
+ void fillPageIds(std::u16string_view _sURL,std::vector<sal_Int16>& _rOutPathIds) const;
+
+ DATASOURCE_TYPE determineType(std::u16string_view _rDsn) const;
+
+ sal_Int32 getIndexOf(std::u16string_view _sURL) const;
+ sal_Int32 size() const;
+ OUString getType(std::u16string_view _sURL) const;
+};
+
+//- ODsnTypeCollection::TypeIterator
+class OOO_DLLPUBLIC_DBA ODsnTypeCollection::TypeIterator
+{
+ friend class ODsnTypeCollection;
+
+ friend bool OOO_DLLPUBLIC_DBA operator==(const TypeIterator& lhs, const TypeIterator& rhs);
+ friend bool OOO_DLLPUBLIC_DBA operator!=(const TypeIterator& lhs, const TypeIterator& rhs) { return !(lhs == rhs); }
+
+protected:
+ const ODsnTypeCollection* m_pContainer;
+ sal_Int32 m_nPosition;
+
+public:
+ TypeIterator(const TypeIterator& _rSource);
+ ~TypeIterator();
+
+ OUString const & getURLPrefix() const;
+ OUString const & getDisplayName() const;
+
+ /// prefix increment
+ const TypeIterator& operator++();
+
+protected:
+ TypeIterator(const ODsnTypeCollection* _pContainer, sal_Int32 _nInitialPos);
+};
+
+
+inline ODsnTypeCollection::TypeIterator ODsnTypeCollection::begin() const { return ODsnTypeCollection::TypeIterator(this, 0);}
+inline ODsnTypeCollection::TypeIterator ODsnTypeCollection::end() const { return ODsnTypeCollection::TypeIterator(this, m_aDsnTypesDisplayNames.size());}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/inc/stringconstants.hxx b/dbaccess/source/inc/stringconstants.hxx
new file mode 100644
index 000000000..1f20962a7
--- /dev/null
+++ b/dbaccess/source/inc/stringconstants.hxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// property ids
+
+#define PROPERTY_ID_TITLE 1
+#define PROPERTY_ID_URL 2
+#define PROPERTY_ID_INFO 4
+#define PROPERTY_ID_ISPASSWORDREQUIRED 5
+#define PROPERTY_ID_TABLEFILTER 6
+#define PROPERTY_ID_NAME 7
+#define PROPERTY_ID_SCHEMANAME 8
+#define PROPERTY_ID_CATALOGNAME 9
+#define PROPERTY_ID_PRIVILEGES 10
+#define PROPERTY_ID_ESCAPE_PROCESSING 11
+#define PROPERTY_ID_COMMAND 12
+#define PROPERTY_ID_TYPE 13
+#define PROPERTY_ID_TYPENAME 14
+#define PROPERTY_ID_PRECISION 15
+#define PROPERTY_ID_SCALE 16
+#define PROPERTY_ID_ISNULLABLE 17
+#define PROPERTY_ID_ISAUTOINCREMENT 18
+#define PROPERTY_ID_ISROWVERSION 19
+#define PROPERTY_ID_DESCRIPTION 20
+#define PROPERTY_ID_DEFAULTVALUE 21
+#define PROPERTY_ID_NUMBERFORMAT 22
+#define PROPERTY_ID_QUERYTIMEOUT 23
+#define PROPERTY_ID_MAXFIELDSIZE 24
+#define PROPERTY_ID_MAXROWS 25
+#define PROPERTY_ID_CURSORNAME 26
+#define PROPERTY_ID_RESULTSETCONCURRENCY 27
+#define PROPERTY_ID_RESULTSETTYPE 28
+#define PROPERTY_ID_FETCHDIRECTION 29
+#define PROPERTY_ID_FETCHSIZE 30
+#define PROPERTY_ID_USEBOOKMARKS 31
+#define PROPERTY_ID_ISSEARCHABLE 32
+#define PROPERTY_ID_ISCURRENCY 33
+#define PROPERTY_ID_ISSIGNED 34
+#define PROPERTY_ID_DISPLAYSIZE 35
+#define PROPERTY_ID_LABEL 36
+#define PROPERTY_ID_ISREADONLY 37
+#define PROPERTY_ID_ISWRITABLE 38
+#define PROPERTY_ID_ISDEFINITELYWRITABLE 39
+#define PROPERTY_ID_VALUE 40
+#define PROPERTY_ID_TABLENAME 41
+#define PROPERTY_ID_ISCASESENSITIVE 42
+#define PROPERTY_ID_SERVICENAME 43
+#define PROPERTY_ID_ISBOOKMARKABLE 44
+#define PROPERTY_ID_CANUPDATEINSERTEDROWS 45
+#define PROPERTY_ID_ISSET 46
+#define PROPERTY_ID_ISOUTPARAMETER 47
+#define PROPERTY_ID_NUMBERFORMATSSUPPLIER 48
+#define PROPERTY_ID_ISCALCULATED 49
+#define PROPERTY_ID_DATASOURCENAME 50
+#define PROPERTY_ID_TRANSACTIONISOLATION 51
+#define PROPERTY_ID_TYPEMAP 52
+#define PROPERTY_ID_USER 53
+#define PROPERTY_ID_PASSWORD 54
+#define PROPERTY_ID_COMMAND_TYPE 55
+#define PROPERTY_ID_ACTIVECOMMAND 56
+#define PROPERTY_ID_ACTIVE_CONNECTION 57
+#define PROPERTY_ID_FILTER 58
+#define PROPERTY_ID_APPLYFILTER 59
+#define PROPERTY_ID_ORDER 60
+#define PROPERTY_ID_ISMODIFIED 61
+#define PROPERTY_ID_ISNEW 62
+#define PROPERTY_ID_ROWCOUNT 63
+#define PROPERTY_ID_ISROWCOUNTFINAL 64
+#define PROPERTY_ID_HELPFILENAME 65
+#define PROPERTY_ID_REALNAME 66
+#define PROPERTY_ID_HIDDEN 67
+#define PROPERTY_ID_ALIGN 68
+#define PROPERTY_ID_WIDTH 69
+#define PROPERTY_ID_TABLETYPEFILTER 70
+#define PROPERTY_ID_DATABASE_LOCATION 71
+#define PROPERTY_ID_FONT 72
+#define PROPERTY_ID_ROW_HEIGHT 73
+#define PROPERTY_ID_TEXTCOLOR 74
+#define PROPERTY_ID_UPDATE_TABLENAME 75
+#define PROPERTY_ID_UPDATE_SCHEMANAME 76
+#define PROPERTY_ID_UPDATE_CATALOGNAME 77
+#define PROPERTY_ID_CONTROLMODEL 78
+#define PROPERTY_ID_RELATIVEPOSITION 79
+#define PROPERTY_ID_ISASCENDING 80
+#define PROPERTY_ID_RELATEDCOLUMN 81
+#define PROPERTY_ID_ISUNIQUE 82
+#define PROPERTY_ID_ISPRIMARYKEYINDEX 83
+#define PROPERTY_ID_IGNORERESULT 84
+#define PROPERTY_ID_DELETERULE 85
+#define PROPERTY_ID_UPDATERULE 86
+#define PROPERTY_ID_REFERENCEDTABLE 87
+#define PROPERTY_ID_REFERENCEDCOLUMN 88
+#define PROPERTY_ID_PARENTWINDOW 89
+#define PROPERTY_ID_SQLEXCEPTION 90
+#define PROPERTY_ID_ISHIDDEN 91
+#define PROPERTY_ID_SUPPRESSVERSIONCL 92
+#define PROPERTY_ID_LAYOUTINFORMATION 93
+#define PROPERTY_ID_TEXTLINECOLOR 94
+#define PROPERTY_ID_TEXTEMPHASIS 95
+#define PROPERTY_ID_TEXTRELIEF 96
+#define PROPERTY_ID_HELPTEXT 97
+#define PROPERTY_ID_CONTROLDEFAULT 98
+#define PROPERTY_ID_AUTOINCREMENTCREATION 99
+#define PROPERTY_ID_SPECIAL_OPTIONS 100
+#define PROPERTY_ID_FONTCHARWIDTH 101
+#define PROPERTY_ID_FONTCHARSET 102
+#define PROPERTY_ID_FONTFAMILY 103
+#define PROPERTY_ID_FONTHEIGHT 104
+#define PROPERTY_ID_FONTKERNING 105
+#define PROPERTY_ID_FONTNAME 106
+#define PROPERTY_ID_FONTORIENTATION 107
+#define PROPERTY_ID_FONTPITCH 108
+#define PROPERTY_ID_FONTSLANT 109
+#define PROPERTY_ID_FONTSTRIKEOUT 110
+#define PROPERTY_ID_FONTSTYLENAME 111
+#define PROPERTY_ID_FONTUNDERLINE 112
+#define PROPERTY_ID_FONTWEIGHT 113
+#define PROPERTY_ID_FONTWIDTH 114
+#define PROPERTY_ID_FONTWORDLINEMODE 115
+#define PROPERTY_ID_FONTTYPE 116
+#define PROPERTY_ID_PERSISTENT_NAME 117
+#define PROPERTY_ID_ORIGINAL 118
+#define PROPERTY_ID_TABSTOP 119
+#define PROPERTY_ID_DEFAULTCONTROL 120
+#define PROPERTY_ID_ENABLED 121
+#define PROPERTY_ID_BORDER 122
+#define PROPERTY_ID_COLUMN 123
+#define PROPERTY_ID_AS_TEMPLATE 124
+#define PROPERTY_ID_IS_FORM 125
+#define PROPERTY_ID_HAVING_CLAUSE 126
+#define PROPERTY_ID_GROUP_BY 127
+#define PROPERTY_ID_EDIT_WIDTH 128
+#define PROPERTY_ID_SETTINGS 129
+#define PROPERTY_ID_CONNECTION_RESOURCE 130
+#define PROPERTY_ID_RESULT_SET 131
+#define PROPERTY_ID_SELECTION 132
+#define PROPERTY_ID_BOOKMARK_SELECTION 133
+#define PROPERTY_ID_COLUMN_NAME 134
+#define PROPERTY_ID_CONNECTION_INFO 135
+#define PROPERTY_ID_HEADER_LINE 136
+#define PROPERTY_ID_FIELD_DELIMITER 137
+#define PROPERTY_ID_STRING_DELIMITER 138
+#define PROPERTY_ID_DECIMAL_DELIMITER 139
+#define PROPERTY_ID_THOUSAND_DELIMITER 140
+#define PROPERTY_ID_ENCODING 141
+#define PROPERTY_ID_HELP_URL 142
+#define PROPERTY_ID_PERSISTENT_PATH 143
+#define PROPERTY_ID_CURRENT_QUERY_DESIGN 144
+#define PROPERTY_ID_SINGLESELECTQUERYCOMPOSER 145
+#define PROPERTY_ID_PROPCHANGE_NOTIFY 146
+#define PROPERTY_ID_AUTOGROW 147
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/connection/connectiontools.cxx b/dbaccess/source/sdbtools/connection/connectiontools.cxx
new file mode 100644
index 000000000..5dd408bac
--- /dev/null
+++ b/dbaccess/source/sdbtools/connection/connectiontools.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectiontools.hxx>
+#include "tablename.hxx"
+#include "objectnames.hxx"
+#include "datasourcemetadata.hxx"
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/statementcomposer.hxx>
+
+namespace sdbtools
+{
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdb::tools::XTableName;
+ using ::com::sun::star::sdb::tools::XObjectNames;
+ using ::com::sun::star::sdb::tools::XDataSourceMetaData;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::XComponentContext;
+
+ // ConnectionTools
+ ConnectionTools::ConnectionTools( const Reference<XComponentContext>& _rContext )
+ :ConnectionDependentComponent( _rContext )
+ {
+ }
+
+ ConnectionTools::~ConnectionTools()
+ {
+ }
+
+ Reference< XTableName > SAL_CALL ConnectionTools::createTableName()
+ {
+ EntryGuard aGuard( *this );
+ return new TableName( getContext(), getConnection() );
+ }
+
+ Reference< XObjectNames > SAL_CALL ConnectionTools::getObjectNames()
+ {
+ EntryGuard aGuard( *this );
+ return new ObjectNames( getContext(), getConnection() );
+ }
+
+ Reference< XDataSourceMetaData > SAL_CALL ConnectionTools::getDataSourceMetaData()
+ {
+ EntryGuard aGuard( *this );
+ return new DataSourceMetaData( getContext(), getConnection() );
+ }
+ Reference< container::XNameAccess > SAL_CALL ConnectionTools::getFieldsByCommandDescriptor( ::sal_Int32 commandType, const OUString& command, Reference< lang::XComponent >& keepFieldsAlive )
+ {
+ EntryGuard aGuard( *this );
+ ::dbtools::SQLExceptionInfo aErrorInfo;
+ Reference< container::XNameAccess > xRet = ::dbtools::getFieldsByCommandDescriptor(getConnection(),commandType,command,keepFieldsAlive,&aErrorInfo);
+ if ( aErrorInfo.isValid() )
+ aErrorInfo.doThrow();
+ return xRet;
+ }
+ Reference< sdb::XSingleSelectQueryComposer > SAL_CALL ConnectionTools::getComposer( ::sal_Int32 commandType, const OUString& command )
+ {
+ EntryGuard aGuard( *this );
+ dbtools::StatementComposer aComposer(getConnection(), command, commandType, true );
+ aComposer.setDisposeComposer(false);
+ return aComposer.getComposer();
+ }
+
+ OUString SAL_CALL ConnectionTools::getImplementationName()
+ {
+ return "com.sun.star.comp.dbaccess.ConnectionTools";
+ }
+
+ sal_Bool SAL_CALL ConnectionTools::supportsService(const OUString & ServiceName)
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL ConnectionTools::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.tools.ConnectionTools" };
+ }
+
+ void SAL_CALL ConnectionTools::initialize(const Sequence< Any > & _rArguments)
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XConnection > xConnection;
+ if (_rArguments.getLength()==1 && (_rArguments[0] >>= xConnection))
+ {
+ }
+ else
+ {
+ ::comphelper::NamedValueCollection aArguments( _rArguments );
+ aArguments.get( "Connection" ) >>= xConnection;
+ }
+ if ( !xConnection.is() )
+ throw IllegalArgumentException();
+
+ setWeakConnection( xConnection );
+ }
+
+} // namespace sdbtools
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbaccess_ConnectionTools_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new sdbtools::ConnectionTools(context));
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/connection/datasourcemetadata.cxx b/dbaccess/source/sdbtools/connection/datasourcemetadata.cxx
new file mode 100644
index 000000000..a446885b8
--- /dev/null
+++ b/dbaccess/source/sdbtools/connection/datasourcemetadata.cxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "datasourcemetadata.hxx"
+
+#include <connectivity/dbmetadata.hxx>
+
+namespace sdbtools
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::uno::XComponentContext;
+
+ // DataSourceMetaData
+ DataSourceMetaData::DataSourceMetaData( const Reference<XComponentContext>& _rContext, const Reference< XConnection >& _rxConnection )
+ :ConnectionDependentComponent( _rContext )
+ {
+ setWeakConnection( _rxConnection );
+ }
+
+ DataSourceMetaData::~DataSourceMetaData()
+ {
+ }
+
+ sal_Bool SAL_CALL DataSourceMetaData::supportsQueriesInFrom( )
+ {
+ EntryGuard aGuard( *this );
+ ::dbtools::DatabaseMetaData aMeta( getConnection() );
+ return aMeta.supportsSubqueriesInFrom();
+ }
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/connection/datasourcemetadata.hxx b/dbaccess/source/sdbtools/connection/datasourcemetadata.hxx
new file mode 100644
index 000000000..232f97f60
--- /dev/null
+++ b/dbaccess/source/sdbtools/connection/datasourcemetadata.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectiondependent.hxx>
+
+#include <com/sun/star/sdb/tools/XDataSourceMetaData.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace sdbtools
+{
+
+ // DataSourceMetaData
+ typedef ::cppu::WeakImplHelper< css::sdb::tools::XDataSourceMetaData
+ > DataSourceMetaData_Base;
+ /** default implementation for XDataSourceMetaData
+ */
+ class DataSourceMetaData :public DataSourceMetaData_Base
+ ,public ConnectionDependentComponent
+ {
+
+ public:
+ /** constructs the instance
+ @param _rContext
+ the component's context
+ @param _rxConnection
+ the connection to work with. Will be held weak. Must not be <NULL/>.
+ @throws css::lang::NullPointerException
+ if _rxConnection is <NULL/>
+ */
+ DataSourceMetaData(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+
+ // XDataSourceMetaData
+ virtual sal_Bool SAL_CALL supportsQueriesInFrom() override;
+
+ protected:
+ virtual ~DataSourceMetaData() override;
+
+ private:
+ DataSourceMetaData( const DataSourceMetaData& ) = delete;
+ DataSourceMetaData& operator=( const DataSourceMetaData& ) = delete;
+ };
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/connection/objectnames.cxx b/dbaccess/source/sdbtools/connection/objectnames.cxx
new file mode 100644
index 000000000..66dd03787
--- /dev/null
+++ b/dbaccess/source/sdbtools/connection/objectnames.cxx
@@ -0,0 +1,420 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "objectnames.hxx"
+#include <core_resource.hxx>
+
+#include <strings.hrc>
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <osl/diagnose.h>
+
+#include <memory>
+
+namespace sdbtools
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::sdbc::XDatabaseMetaData;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::sdbcx::XTablesSupplier;
+ using ::com::sun::star::sdb::XQueriesSupplier;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XComponentContext;
+
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+ namespace ErrorCondition = ::com::sun::star::sdb::ErrorCondition;
+
+ namespace {
+
+ // INameValidation
+ class INameValidation
+ {
+ public:
+ virtual bool validateName( const OUString& _rName ) = 0;
+ virtual void validateName_throw( const OUString& _rName ) = 0;
+
+ virtual ~INameValidation() { }
+ };
+
+ }
+
+ typedef std::shared_ptr< INameValidation > PNameValidation;
+
+ namespace {
+
+ // PlainExistenceCheck
+ class PlainExistenceCheck : public INameValidation
+ {
+ private:
+ Reference< XConnection > m_xConnection;
+ Reference< XNameAccess > m_xContainer;
+
+ public:
+ PlainExistenceCheck( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxContainer )
+ :m_xConnection( _rxConnection )
+ ,m_xContainer( _rxContainer )
+ {
+ OSL_ENSURE( m_xContainer.is(), "PlainExistenceCheck::PlainExistenceCheck: this will crash!" );
+ }
+
+ // INameValidation
+ virtual bool validateName( const OUString& _rName ) override
+ {
+ return !m_xContainer->hasByName( _rName );
+ }
+
+ virtual void validateName_throw( const OUString& _rName ) override
+ {
+ if ( validateName( _rName ) )
+ return;
+
+ ::connectivity::SQLError aErrors;
+ SQLException aError( aErrors.getSQLException( ErrorCondition::DB_OBJECT_NAME_IS_USED, m_xConnection, _rName ) );
+
+ ::dbtools::DatabaseMetaData aMeta( m_xConnection );
+ if ( aMeta.supportsSubqueriesInFrom() )
+ {
+ OUString sNeedDistinctNames( DBA_RES( STR_QUERY_AND_TABLE_DISTINCT_NAMES ) );
+ aError.NextException <<= SQLException( sNeedDistinctNames, m_xConnection, OUString(), 0, Any() );
+ }
+
+ throw aError;
+ }
+ };
+
+ // TableValidityCheck
+ class TableValidityCheck : public INameValidation
+ {
+ const Reference< XConnection > m_xConnection;
+
+ public:
+ TableValidityCheck( const Reference< XConnection >& _rxConnection )
+ :m_xConnection( _rxConnection )
+ {
+ }
+
+ virtual bool validateName( const OUString& _rName ) override
+ {
+ ::dbtools::DatabaseMetaData aMeta( m_xConnection );
+ if ( !aMeta.restrictIdentifiersToSQL92() )
+ return true;
+
+ OUString sCatalog, sSchema, sName;
+ ::dbtools::qualifiedNameComponents(
+ m_xConnection->getMetaData(), _rName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InTableDefinitions );
+
+ OUString sExtraNameCharacters( m_xConnection->getMetaData()->getExtraNameCharacters() );
+ return !( ( !sCatalog.isEmpty() && !::dbtools::isValidSQLName( sCatalog, sExtraNameCharacters ) )
+ || ( !sSchema.isEmpty() && !::dbtools::isValidSQLName( sSchema, sExtraNameCharacters ) )
+ || ( !sName.isEmpty() && !::dbtools::isValidSQLName( sName, sExtraNameCharacters ) ));
+ }
+
+ virtual void validateName_throw( const OUString& _rName ) override
+ {
+ if ( validateName( _rName ) )
+ return;
+
+ ::connectivity::SQLError aErrors;
+ aErrors.raiseException( ErrorCondition::DB_INVALID_SQL_NAME, m_xConnection, _rName );
+ }
+ };
+
+ // QueryValidityCheck
+ class QueryValidityCheck : public INameValidation
+ {
+ const Reference< XConnection > m_xConnection;
+
+ public:
+ QueryValidityCheck( const Reference< XConnection >& _rxConnection )
+ :m_xConnection( _rxConnection )
+ {
+ }
+
+ static ::connectivity::ErrorCondition validateName_getErrorCondition( std::u16string_view _rName )
+ {
+ if ( ( _rName.find( u'"' ) != std::u16string_view::npos )
+ || ( _rName.find( u'\'' ) != std::u16string_view::npos )
+ || ( _rName.find( u'`' ) != std::u16string_view::npos )
+ || ( _rName.find( u'\x0091' ) != std::u16string_view::npos )
+ || ( _rName.find( u'\x0092' ) != std::u16string_view::npos )
+ || ( _rName.find( u'\x00B4' ) != std::u16string_view::npos ) // removed unparsable chars
+ )
+ return ErrorCondition::DB_QUERY_NAME_WITH_QUOTES;
+
+ if ( _rName.find( '/') != std::u16string_view::npos )
+ return ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES;
+
+ return 0;
+ }
+
+ virtual bool validateName( const OUString& _rName ) override
+ {
+ return validateName_getErrorCondition( _rName ) == 0;
+ }
+
+ virtual void validateName_throw( const OUString& _rName ) override
+ {
+ ::connectivity::ErrorCondition nErrorCondition = validateName_getErrorCondition( _rName );
+ if ( nErrorCondition != 0 )
+ {
+ ::connectivity::SQLError aErrors;
+ aErrors.raiseException( nErrorCondition, m_xConnection );
+ }
+ }
+ };
+
+ // CombinedNameCheck
+ class CombinedNameCheck : public INameValidation
+ {
+ private:
+ PNameValidation m_pPrimary;
+ PNameValidation m_pSecondary;
+
+ public:
+ CombinedNameCheck(const PNameValidation& _pPrimary, const PNameValidation& _pSecondary)
+ :m_pPrimary( _pPrimary )
+ ,m_pSecondary( _pSecondary )
+ {
+ OSL_ENSURE( m_pPrimary && m_pSecondary, "CombinedNameCheck::CombinedNameCheck: this will crash!" );
+ }
+
+ // INameValidation
+ virtual bool validateName( const OUString& _rName ) override
+ {
+ return m_pPrimary->validateName( _rName ) && m_pSecondary->validateName( _rName );
+ }
+
+ virtual void validateName_throw( const OUString& _rName ) override
+ {
+ m_pPrimary->validateName_throw( _rName );
+ m_pSecondary->validateName_throw( _rName );
+ }
+ };
+
+ // NameCheckFactory
+ class NameCheckFactory
+ {
+ public:
+ NameCheckFactory(const NameCheckFactory&) = delete;
+ const NameCheckFactory& operator=(const NameCheckFactory&) = delete;
+ /** creates an INameValidation instance which can be used to check the existence of query or table names
+
+ @param _nCommandType
+ the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be checked for existence
+
+ @param _rxConnection
+ the connection relative to which the names are to be checked. Must be an SDB-level connection
+
+ @throws IllegalArgumentException
+ if the given connection is no SDB-level connection
+
+ @throws IllegalArgumentException
+ if the given command type is neither CommandType::TABLE or CommandType::QUERY
+ */
+ static PNameValidation createExistenceCheck(
+ sal_Int32 _nCommandType,
+ const Reference< XConnection >& _rxConnection
+ );
+
+ /** creates an INameValidation instance which can be used to check the validity of a query or table name
+
+ @param _nCommandType
+ the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be validated
+
+ @param _rxConnection
+ the connection relative to which the names are to be checked. Must be an SDB-level connection
+
+ @throws IllegalArgumentException
+ if the given connection is no SDB-level connection
+
+ @throws IllegalArgumentException
+ if the given command type is neither CommandType::TABLE or CommandType::QUERY
+ */
+ static PNameValidation createValidityCheck(
+ const sal_Int32 _nCommandType,
+ const Reference< XConnection >& _rxConnection
+ );
+
+ private:
+ static void verifyCommandType( sal_Int32 _nCommandType );
+ };
+
+ }
+
+ void NameCheckFactory::verifyCommandType( sal_Int32 _nCommandType )
+ {
+ if ( ( _nCommandType != CommandType::TABLE )
+ && ( _nCommandType != CommandType::QUERY )
+ )
+ throw IllegalArgumentException(
+ DBA_RES( STR_INVALID_COMMAND_TYPE ),
+ nullptr,
+ 0
+ );
+ }
+
+ PNameValidation NameCheckFactory::createExistenceCheck( sal_Int32 _nCommandType, const Reference< XConnection >& _rxConnection )
+ {
+ verifyCommandType( _nCommandType );
+
+ ::dbtools::DatabaseMetaData aMeta( _rxConnection );
+
+ Reference< XNameAccess > xTables, xQueries;
+ try
+ {
+ Reference< XTablesSupplier > xSuppTables( _rxConnection, UNO_QUERY_THROW );
+ Reference< XQueriesSupplier > xQueriesSupplier( _rxConnection, UNO_QUERY_THROW );
+ xTables.set( xSuppTables->getTables(), css::uno::UNO_SET_THROW );
+ xQueries.set( xQueriesSupplier->getQueries(), css::uno::UNO_SET_THROW );
+ }
+ catch( const Exception& )
+ {
+ throw IllegalArgumentException(
+ DBA_RES( STR_CONN_WITHOUT_QUERIES_OR_TABLES ),
+ nullptr,
+ 0
+ );
+ }
+
+ PNameValidation pTableCheck = std::make_shared<PlainExistenceCheck>( _rxConnection, xTables );
+ PNameValidation pQueryCheck = std::make_shared<PlainExistenceCheck>( _rxConnection, xQueries );
+ PNameValidation pReturn;
+
+ if ( aMeta.supportsSubqueriesInFrom() )
+ pReturn = std::make_shared<CombinedNameCheck>( pTableCheck, pQueryCheck );
+ else if ( _nCommandType == CommandType::TABLE )
+ pReturn = pTableCheck;
+ else
+ pReturn = pQueryCheck;
+ return pReturn;
+ }
+
+ PNameValidation NameCheckFactory::createValidityCheck( sal_Int32 _nCommandType, const Reference< XConnection >& _rxConnection )
+ {
+ verifyCommandType( _nCommandType );
+
+ Reference< XDatabaseMetaData > xMeta;
+ try
+ {
+ xMeta.set( _rxConnection->getMetaData(), css::uno::UNO_SET_THROW );
+ }
+ catch( const Exception& )
+ {
+ throw IllegalArgumentException(
+ "The connection could not provide its database's meta data.",
+ nullptr,
+ 0
+ );
+ }
+
+ if ( _nCommandType == CommandType::TABLE )
+ return std::make_shared<TableValidityCheck>( _rxConnection );
+ return std::make_shared<QueryValidityCheck>( _rxConnection );
+ }
+
+ // ObjectNames
+ ObjectNames::ObjectNames( const Reference<XComponentContext>& _rContext, const Reference< XConnection >& _rxConnection )
+ :ConnectionDependentComponent( _rContext )
+ {
+ setWeakConnection( _rxConnection );
+ }
+
+ ObjectNames::~ObjectNames()
+ {
+ }
+
+ OUString SAL_CALL ObjectNames::suggestName( ::sal_Int32 CommandType, const OUString& BaseName )
+ {
+ EntryGuard aGuard( *this );
+
+ PNameValidation pNameCheck( NameCheckFactory::createExistenceCheck( CommandType, getConnection() ) );
+
+ OUString sBaseName( BaseName );
+ if ( sBaseName.isEmpty() )
+ {
+ if ( CommandType == CommandType::TABLE )
+ sBaseName = DBA_RES(STR_BASENAME_TABLE);
+ else
+ sBaseName = DBA_RES(STR_BASENAME_QUERY);
+ }
+ else if( CommandType == CommandType::QUERY )
+ {
+ sBaseName=sBaseName.replace('/', '_');
+ }
+
+ OUString sName( sBaseName );
+ sal_Int32 i = 1;
+ while ( !pNameCheck->validateName( sName ) )
+ {
+ sName = sBaseName + " " + OUString::number(++i);
+ }
+
+ return sName;
+ }
+
+ OUString SAL_CALL ObjectNames::convertToSQLName( const OUString& Name )
+ {
+ EntryGuard aGuard( *this );
+ Reference< XDatabaseMetaData > xMeta( getConnection()->getMetaData(), css::uno::UNO_SET_THROW );
+ return ::dbtools::convertName2SQLName( Name, xMeta->getExtraNameCharacters() );
+ }
+
+ sal_Bool SAL_CALL ObjectNames::isNameUsed( ::sal_Int32 CommandType, const OUString& Name )
+ {
+ EntryGuard aGuard( *this );
+
+ PNameValidation pNameCheck( NameCheckFactory::createExistenceCheck( CommandType, getConnection()) );
+ return !pNameCheck->validateName( Name );
+ }
+
+ sal_Bool SAL_CALL ObjectNames::isNameValid( ::sal_Int32 CommandType, const OUString& Name )
+ {
+ EntryGuard aGuard( *this );
+
+ PNameValidation pNameCheck( NameCheckFactory::createValidityCheck( CommandType, getConnection()) );
+ return pNameCheck->validateName( Name );
+ }
+
+ void SAL_CALL ObjectNames::checkNameForCreate( ::sal_Int32 CommandType, const OUString& Name )
+ {
+ EntryGuard aGuard( *this );
+
+ PNameValidation pNameCheck( NameCheckFactory::createExistenceCheck( CommandType, getConnection() ) );
+ pNameCheck->validateName_throw( Name );
+
+ pNameCheck = NameCheckFactory::createValidityCheck( CommandType, getConnection() );
+ pNameCheck->validateName_throw( Name );
+ }
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/connection/objectnames.hxx b/dbaccess/source/sdbtools/connection/objectnames.hxx
new file mode 100644
index 000000000..439db0967
--- /dev/null
+++ b/dbaccess/source/sdbtools/connection/objectnames.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectiondependent.hxx>
+
+#include <com/sun/star/sdb/tools/XObjectNames.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace sdbtools
+{
+
+ // ObjectNames
+ typedef ::cppu::WeakImplHelper< css::sdb::tools::XObjectNames
+ > ObjectNames_Base;
+ /** default implementation for XObjectNames
+ */
+ class ObjectNames :public ObjectNames_Base
+ ,public ConnectionDependentComponent
+ {
+ public:
+ /** constructs the instance
+
+ @param _rContext
+ the component's context
+ @param _rxConnection
+ the connection to work with. Will be held weak. Must not be <NULL/>.
+
+ @throws css::lang::NullPointerException
+ if _rxConnection is <NULL/>
+ */
+ ObjectNames(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+
+ // XObjectNames
+ virtual OUString SAL_CALL suggestName( ::sal_Int32 CommandType, const OUString& BaseName ) override;
+ virtual OUString SAL_CALL convertToSQLName( const OUString& Name ) override;
+ virtual sal_Bool SAL_CALL isNameUsed( ::sal_Int32 CommandType, const OUString& Name ) override;
+ virtual sal_Bool SAL_CALL isNameValid( ::sal_Int32 CommandType, const OUString& Name ) override;
+ virtual void SAL_CALL checkNameForCreate( ::sal_Int32 CommandType, const OUString& Name ) override;
+
+ protected:
+ virtual ~ObjectNames() override;
+
+ private:
+ ObjectNames( const ObjectNames& ) = delete;
+ ObjectNames& operator=( const ObjectNames& ) = delete;
+ };
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/connection/tablename.cxx b/dbaccess/source/sdbtools/connection/tablename.cxx
new file mode 100644
index 000000000..132484a24
--- /dev/null
+++ b/dbaccess/source/sdbtools/connection/tablename.cxx
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "tablename.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <com/sun/star/sdb/tools/CompositionType.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace sdbtools
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::sdbcx::XTablesSupplier;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::lang::WrappedTargetException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::uno::XComponentContext;
+
+ namespace CompositionType = ::com::sun::star::sdb::tools::CompositionType;
+
+ using namespace ::dbtools;
+
+ // TableName
+ struct TableName_Impl
+ {
+ OUString sCatalog;
+ OUString sSchema;
+ OUString sName;
+ };
+
+ // TableName
+ TableName::TableName( const Reference<XComponentContext>& _rContext, const Reference< XConnection >& _rxConnection )
+ :ConnectionDependentComponent( _rContext )
+ ,m_pImpl( new TableName_Impl )
+ {
+ setWeakConnection( _rxConnection );
+ }
+
+ TableName::~TableName()
+ {
+ }
+
+ OUString SAL_CALL TableName::getCatalogName()
+ {
+ EntryGuard aGuard( *this );
+ return m_pImpl->sCatalog;
+ }
+
+ void SAL_CALL TableName::setCatalogName( const OUString& _catalogName )
+ {
+ EntryGuard aGuard( *this );
+ m_pImpl->sCatalog = _catalogName;
+ }
+
+ OUString SAL_CALL TableName::getSchemaName()
+ {
+ EntryGuard aGuard( *this );
+ return m_pImpl->sSchema;
+ }
+
+ void SAL_CALL TableName::setSchemaName( const OUString& _schemaName )
+ {
+ EntryGuard aGuard( *this );
+ m_pImpl->sSchema = _schemaName;
+ }
+
+ OUString SAL_CALL TableName::getTableName()
+ {
+ EntryGuard aGuard( *this );
+ return m_pImpl->sName;
+ }
+
+ void SAL_CALL TableName::setTableName( const OUString& _tableName )
+ {
+ EntryGuard aGuard( *this );
+ m_pImpl->sName = _tableName;
+ }
+
+ OUString SAL_CALL TableName::getNameForSelect()
+ {
+ EntryGuard aGuard( *this );
+ return composeTableNameForSelect( getConnection(), m_pImpl->sCatalog, m_pImpl->sSchema, m_pImpl->sName );
+ }
+
+ Reference< XPropertySet > SAL_CALL TableName::getTable()
+ {
+ EntryGuard aGuard( *this );
+
+ Reference< XTablesSupplier > xSuppTables( getConnection(), UNO_QUERY_THROW );
+ Reference< XNameAccess > xTables( xSuppTables->getTables(), css::uno::UNO_SET_THROW );
+
+ Reference< XPropertySet > xTable;
+ try
+ {
+ xTable.set( xTables->getByName( getComposedName( CompositionType::Complete, false ) ), UNO_QUERY_THROW );
+ }
+ catch( const WrappedTargetException& )
+ {
+ throw NoSuchElementException();
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const NoSuchElementException& ) { throw; }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ throw NoSuchElementException();
+ }
+
+ return xTable;
+ }
+
+ void SAL_CALL TableName::setTable( const Reference< XPropertySet >& _table )
+ {
+ EntryGuard aGuard( *this );
+
+ Reference< XPropertySetInfo > xPSI( _table, UNO_QUERY );
+ if ( !xPSI.is()
+ || !xPSI->hasPropertyByName( PROPERTY_CATALOGNAME )
+ || !xPSI->hasPropertyByName( PROPERTY_SCHEMANAME )
+ || !xPSI->hasPropertyByName( PROPERTY_NAME )
+ )
+ throw IllegalArgumentException(
+ DBA_RES( STR_NO_TABLE_OBJECT ),
+ *this,
+ 0
+ );
+
+ try
+ {
+ OSL_VERIFY( _table->getPropertyValue( PROPERTY_CATALOGNAME ) >>= m_pImpl->sCatalog );
+ OSL_VERIFY( _table->getPropertyValue( PROPERTY_SCHEMANAME ) >>= m_pImpl->sSchema );
+ OSL_VERIFY( _table->getPropertyValue( PROPERTY_NAME ) >>= m_pImpl->sName );
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& e )
+ {
+ throw IllegalArgumentException( e.Message, e.Context, 0 );
+ }
+ }
+
+ namespace
+ {
+ /** translates a CompositionType into an EComposeRule
+ @throws IllegalArgumentException
+ if the given value does not denote a valid CompositionType
+ */
+ EComposeRule lcl_translateCompositionType_throw( sal_Int32 _nType )
+ {
+ static const struct
+ {
+ sal_Int32 nCompositionType;
+ EComposeRule eComposeRule;
+ } TypeTable[] =
+ {
+ { CompositionType::ForTableDefinitions, EComposeRule::InTableDefinitions },
+ { CompositionType::ForIndexDefinitions, EComposeRule::InIndexDefinitions },
+ { CompositionType::ForDataManipulation, EComposeRule::InDataManipulation },
+ { CompositionType::ForProcedureCalls, EComposeRule::InProcedureCalls },
+ { CompositionType::ForPrivilegeDefinitions, EComposeRule::InPrivilegeDefinitions },
+ { CompositionType::Complete, EComposeRule::Complete }
+ };
+
+ bool found = false;
+ size_t i = 0;
+ for ( ; i < SAL_N_ELEMENTS( TypeTable ) && !found; ++i )
+ if ( TypeTable[i].nCompositionType == _nType )
+ found = true;
+ if ( !found )
+ throw IllegalArgumentException(
+ DBA_RES( STR_INVALID_COMPOSITION_TYPE ),
+ nullptr,
+ 0
+ );
+
+ return TypeTable[i].eComposeRule;
+ }
+ }
+
+ OUString SAL_CALL TableName::getComposedName( ::sal_Int32 Type, sal_Bool Quote )
+ {
+ EntryGuard aGuard( *this );
+
+ return composeTableName(
+ getConnection()->getMetaData(),
+ m_pImpl->sCatalog, m_pImpl->sSchema, m_pImpl->sName, Quote,
+ lcl_translateCompositionType_throw( Type ) );
+ }
+
+ void SAL_CALL TableName::setComposedName( const OUString& ComposedName, ::sal_Int32 Type )
+ {
+ EntryGuard aGuard( *this );
+
+ qualifiedNameComponents(
+ getConnection()->getMetaData(),
+ ComposedName,
+ m_pImpl->sCatalog, m_pImpl->sSchema, m_pImpl->sName,
+ lcl_translateCompositionType_throw( Type ) );
+ }
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/connection/tablename.hxx b/dbaccess/source/sdbtools/connection/tablename.hxx
new file mode 100644
index 000000000..3a7ece21a
--- /dev/null
+++ b/dbaccess/source/sdbtools/connection/tablename.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectiondependent.hxx>
+
+#include <com/sun/star/sdb/tools/XTableName.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace sdbtools
+{
+
+ // TableName
+ typedef ::cppu::WeakImplHelper< css::sdb::tools::XTableName
+ > TableName_Base;
+ struct TableName_Impl;
+ /** default implementation for XTableName
+ */
+ class TableName :public TableName_Base
+ ,public ConnectionDependentComponent
+ {
+ private:
+ std::unique_ptr< TableName_Impl > m_pImpl;
+
+ public:
+ /** constructs the instance
+
+ @param _rContext
+ the component's context
+ @param _rxConnection
+ the connection to work with. Will be held weak. Must not be <NULL/>.
+
+ @throws css::lang::NullPointerException
+ if _rxConnection is <NULL/>
+ */
+ TableName(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+
+ // XTableName
+ virtual OUString SAL_CALL getCatalogName() override;
+ virtual void SAL_CALL setCatalogName( const OUString& _catalogname ) override;
+ virtual OUString SAL_CALL getSchemaName() override;
+ virtual void SAL_CALL setSchemaName( const OUString& _schemaname ) override;
+ virtual OUString SAL_CALL getTableName() override;
+ virtual void SAL_CALL setTableName( const OUString& _tablename ) override;
+ virtual OUString SAL_CALL getNameForSelect() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getTable() override;
+ virtual void SAL_CALL setTable( const css::uno::Reference< css::beans::XPropertySet >& _table ) override;
+ virtual OUString SAL_CALL getComposedName( ::sal_Int32 Type, sal_Bool Quote ) override;
+ virtual void SAL_CALL setComposedName( const OUString& ComposedName, ::sal_Int32 Type ) override;
+
+ protected:
+ virtual ~TableName() override;
+
+ private:
+ TableName( const TableName& ) = delete;
+ TableName& operator=( const TableName& ) = delete;
+ };
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/inc/connectiondependent.hxx b/dbaccess/source/sdbtools/inc/connectiondependent.hxx
new file mode 100644
index 000000000..d315d7018
--- /dev/null
+++ b/dbaccess/source/sdbtools/inc/connectiondependent.hxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/weakref.hxx>
+#include <osl/mutex.hxx>
+
+namespace sdbtools
+{
+
+ // ConnectionDependentComponent
+ class ConnectionDependentComponent
+ {
+ private:
+ mutable ::osl::Mutex m_aMutex;
+ css::uno::WeakReference< css::sdbc::XConnection >
+ m_aConnection;
+ css::uno::Reference< css::uno::XComponentContext >
+ m_aContext;
+
+ /** a hard reference to the connection we're working for
+
+ This member is only valid as long as a EntryGuard is on the stack.
+ The guard will, in its constructor, set the member, and reset it in its destructor.
+ This ensures that the connection is only held hard when it's needed, and weak otherwise.
+ */
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xConnection;
+
+ protected:
+ ::osl::Mutex& getMutex() const { return m_aMutex; }
+
+ const css::uno::Reference< css::uno::XComponentContext >&
+ getContext() const { return m_aContext; }
+
+ protected:
+ class EntryGuard;
+
+ protected:
+ explicit ConnectionDependentComponent( const css::uno::Reference< css::uno::XComponentContext > & _rContext )
+ :m_aContext( _rContext )
+ {
+ }
+
+ /** sets the connection we depend on.
+
+ To be called exactly once.
+
+ @param _rxConnection
+ the connection to set
+ */
+ void setWeakConnection( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection )
+ {
+ m_aConnection = _rxConnection;
+ }
+
+ const css::uno::Reference< css::sdbc::XConnection >&
+ getConnection() const { return m_xConnection; }
+
+ public:
+ struct GuardAccess;
+ friend struct GuardAccess;
+ /** helper for granting exclusive access to various other methods
+ */
+ struct GuardAccess { friend class EntryGuard; private: GuardAccess() { } };
+
+ ::osl::Mutex& getMutex( GuardAccess ) const { return m_aMutex; }
+
+ bool acquireConnection( GuardAccess )
+ {
+ m_xConnection.set(m_aConnection);
+ return m_xConnection.is();
+ }
+ void releaseConnection( GuardAccess )
+ {
+ m_xConnection.clear();
+ }
+ };
+
+ // ConnectionDependentComponent::EntryGuard
+ /** a class for guarding methods of a connection-dependent component
+
+ This class serves multiple purposes:
+ <ul><li>It ensures multi-threading safety by guarding the component's mutex
+ as long as it lives.</li>
+ <li>It ensures that the component's connection is alive. The constructor
+ throws a DisposedException if no hard reference to the connection can
+ be obtained.</li>
+ </ul>
+ */
+ class ConnectionDependentComponent::EntryGuard
+ {
+ private:
+ ::osl::MutexGuard m_aMutexGuard;
+ ConnectionDependentComponent& m_rComponent;
+
+ public:
+ explicit EntryGuard( ConnectionDependentComponent& _rComponent )
+ :m_aMutexGuard( _rComponent.getMutex( ConnectionDependentComponent::GuardAccess() ) )
+ ,m_rComponent( _rComponent )
+ {
+ if ( !m_rComponent.acquireConnection( ConnectionDependentComponent::GuardAccess() ) )
+ throw css::lang::DisposedException();
+ }
+
+ ~EntryGuard()
+ {
+ m_rComponent.releaseConnection( ConnectionDependentComponent::GuardAccess() );
+ }
+ };
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/sdbtools/inc/connectiontools.hxx b/dbaccess/source/sdbtools/inc/connectiontools.hxx
new file mode 100644
index 000000000..876f713af
--- /dev/null
+++ b/dbaccess/source/sdbtools/inc/connectiontools.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "connectiondependent.hxx"
+
+#include <com/sun/star/sdb/tools/XConnectionTools.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace sdbtools
+{
+
+ // ConnectionTools
+ typedef ::cppu::WeakImplHelper< css::sdb::tools::XConnectionTools
+ , css::lang::XServiceInfo
+ , css::lang::XInitialization
+ > ConnectionTools_Base;
+ /** implements the css::sdb::tools::XConnectionTools functionality
+ */
+ class ConnectionTools :public ConnectionTools_Base
+ ,public ConnectionDependentComponent
+ {
+ public:
+ /** constructs a ConnectionTools instance
+
+ @param _rxContext
+ the context of the component
+ */
+ explicit ConnectionTools( const css::uno::Reference< css::uno::XComponentContext >& _rContext );
+
+ // XConnectionTools
+ virtual css::uno::Reference< css::sdb::tools::XTableName > SAL_CALL createTableName() override;
+ virtual css::uno::Reference< css::sdb::tools::XObjectNames > SAL_CALL getObjectNames() override;
+ virtual css::uno::Reference< css::sdb::tools::XDataSourceMetaData > SAL_CALL getDataSourceMetaData() override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getFieldsByCommandDescriptor( ::sal_Int32 commandType, const OUString& command, css::uno::Reference< css::lang::XComponent >& keepFieldsAlive ) override;
+ virtual css::uno::Reference< css::sdb::XSingleSelectQueryComposer > SAL_CALL getComposer( ::sal_Int32 commandType, const OUString& command ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString & ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override;
+
+ protected:
+ virtual ~ConnectionTools() override;
+
+ private:
+ ConnectionTools( const ConnectionTools& ) = delete;
+ ConnectionTools& operator=( const ConnectionTools& ) = delete;
+ };
+
+} // namespace sdbtools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppController.cxx b/dbaccess/source/ui/app/AppController.cxx
new file mode 100644
index 000000000..06508d5c2
--- /dev/null
+++ b/dbaccess/source/ui/app/AppController.cxx
@@ -0,0 +1,2834 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "AppController.hxx"
+#include <core_resource.hxx>
+#include <dbexchange.hxx>
+#include <strings.hxx>
+#include <advancedsettingsdlg.hxx>
+#include "subcomponentmanager.hxx"
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/ErrorMessageDialog.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+#include <svl/filenotation.hxx>
+#include <vcl/transfer.hxx>
+#include <svtools/cliplistener.hxx>
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/interaction.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <unotools/closeveto.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/historyoptions.hxx>
+
+#include <sfx2/mailmodelapi.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/QuerySaveDocument.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <svx/dbaexchange.hxx>
+#include <svx/dbaobjectex.hxx>
+#include <svx/svxdlg.hxx>
+
+#include <osl/mutex.hxx>
+#include "AppView.hxx"
+#include <browserids.hxx>
+#include <strings.hrc>
+#include <defaultobjectnamecheck.hxx>
+#include <databaseobjectview.hxx>
+#include <dbtreelistbox.hxx>
+#include "AppDetailView.hxx"
+#include <linkeddocuments.hxx>
+#include <UITools.hxx>
+#include <dsntypes.hxx>
+#include <dlgsave.hxx>
+#include <dbaccess_slotid.hrc>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OApplicationController_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OApplicationController(context));
+}
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::svx;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::task;
+using ::com::sun::star::document::XEmbeddedScripts;
+using ::com::sun::star::document::XDocumentEventBroadcaster;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject;
+namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer;
+
+OUString SAL_CALL OApplicationController::getImplementationName()
+{
+ return SERVICE_SDB_APPLICATIONCONTROLLER;
+}
+
+Sequence< OUString> SAL_CALL OApplicationController::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.application.DefaultViewController" };
+}
+
+namespace {
+
+class SelectionGuard;
+
+}
+
+// OApplicationController
+class SelectionNotifier
+{
+private:
+ ::comphelper::OInterfaceContainerHelper3<XSelectionChangeListener> m_aSelectionListeners;
+ ::cppu::OWeakObject& m_rContext;
+ sal_Int32 m_nSelectionNestingLevel;
+
+public:
+ SelectionNotifier( ::osl::Mutex& _rMutex, ::cppu::OWeakObject& _rContext )
+ :m_aSelectionListeners( _rMutex )
+ ,m_rContext( _rContext )
+ ,m_nSelectionNestingLevel( 0 )
+ {
+ }
+
+ SelectionNotifier(const SelectionNotifier&) = delete;
+ const SelectionNotifier& operator=(const SelectionNotifier&) = delete;
+
+ void addListener( const Reference< XSelectionChangeListener >& Listener )
+ {
+ m_aSelectionListeners.addInterface( Listener );
+ }
+
+ void removeListener( const Reference< XSelectionChangeListener >& Listener )
+ {
+ m_aSelectionListeners.removeInterface( Listener );
+ }
+
+ void disposing()
+ {
+ EventObject aEvent( m_rContext );
+ m_aSelectionListeners.disposeAndClear( aEvent );
+ }
+
+ struct SelectionGuardAccess { friend SelectionGuard; private: SelectionGuardAccess() { } };
+
+ /** enters a block which modifies the selection of our owner.
+
+ Can be called multiple times, the only important thing is to call leaveSelection
+ equally often.
+ */
+ void enterSelection( SelectionGuardAccess )
+ {
+ ++m_nSelectionNestingLevel;
+ }
+
+ /** leaves a block which modifies the selection of our owner
+
+ Must be paired with enterSelection calls.
+
+ When the last block is left, i.e. the last leaveSelection call is made on the current stack,
+ then our SelectionChangeListeners are notified
+ */
+ void leaveSelection( SelectionGuardAccess )
+ {
+ if ( --m_nSelectionNestingLevel == 0 )
+ {
+ EventObject aEvent( m_rContext );
+ m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent );
+ }
+ }
+};
+
+namespace {
+
+class SelectionGuard
+{
+public:
+ explicit SelectionGuard( SelectionNotifier& _rNotifier )
+ :m_rNotifier( _rNotifier )
+ {
+ m_rNotifier.enterSelection( SelectionNotifier::SelectionGuardAccess() );
+ }
+
+ ~SelectionGuard()
+ {
+ m_rNotifier.leaveSelection( SelectionNotifier::SelectionGuardAccess() );
+ }
+
+ SelectionGuard(const SelectionGuard&) = delete;
+ const SelectionGuard& operator=(const SelectionGuard&) = delete;
+
+private:
+ SelectionNotifier& m_rNotifier;
+};
+
+}
+
+// OApplicationController
+OApplicationController::OApplicationController(const Reference< XComponentContext >& _rxORB)
+ :OGenericUnoController( _rxORB )
+ ,m_aContextMenuInterceptors( getMutex() )
+ ,m_pSubComponentManager( new SubComponentManager( *this, getSharedMutex() ) )
+ ,m_aTypeCollection( _rxORB )
+ ,m_aTableCopyHelper(this)
+ ,m_nAsyncDrop(nullptr)
+ ,m_aSelectContainerEvent( LINK( this, OApplicationController, OnSelectContainer ) )
+ ,m_ePreviewMode(E_PREVIEWNONE)
+ ,m_eCurrentType(E_NONE)
+ ,m_bNeedToReconnect(false)
+ ,m_bSuspended( false )
+ ,m_pSelectionNotifier( new SelectionNotifier( getMutex(), *this ) )
+{
+}
+
+OApplicationController::~OApplicationController()
+{
+ if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
+ {
+ OSL_FAIL("Please check who doesn't dispose this component!");
+ // increment ref count to prevent double call of Dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+ clearView();
+}
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2(OApplicationController,OGenericUnoController,OApplicationController_Base)
+IMPLEMENT_FORWARD_XINTERFACE2(OApplicationController,OGenericUnoController,OApplicationController_Base)
+void OApplicationController::disconnect()
+{
+ if ( m_xDataSourceConnection.is() )
+ stopConnectionListening( m_xDataSourceConnection );
+
+ try
+ {
+ // temporary (hopefully!) hack for #i55274#
+ Reference< XFlushable > xFlush( m_xDataSourceConnection, UNO_QUERY );
+ if ( xFlush.is() && m_xMetaData.is() && !m_xMetaData->isReadOnly() )
+ xFlush->flush();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xDataSourceConnection.clear();
+ m_xMetaData.clear();
+
+ InvalidateAll();
+}
+
+void SAL_CALL OApplicationController::disposing()
+{
+ for( const auto& rContainerListener : m_aCurrentContainers )
+ {
+ if( rContainerListener.is() )
+ {
+ rContainerListener->removeContainerListener( this );
+ }
+ }
+
+ m_aCurrentContainers.clear();
+ m_pSubComponentManager->disposing();
+ m_pSelectionNotifier->disposing();
+
+ if ( getView() )
+ {
+ getContainer()->showPreview(nullptr);
+ m_pClipboardNotifier->ClearCallbackLink();
+ m_pClipboardNotifier->RemoveListener( getView() );
+ m_pClipboardNotifier.clear();
+ }
+
+ disconnect();
+ try
+ {
+ Reference < XFrame > xFrame;
+ attachFrame( xFrame );
+
+ if ( m_xDataSource.is() )
+ {
+ m_xDataSource->removePropertyChangeListener(OUString(), this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_INFO, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_URL, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_ISPASSWORDREQUIRED, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_LAYOUTINFORMATION, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_SUPPRESSVERSIONCL, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_TABLEFILTER, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_TABLETYPEFILTER, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_USER, this);
+ m_xDataSource = nullptr;
+ }
+
+ Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ xBroadcaster->removeModifyListener(static_cast<XModifyListener*>(this));
+
+ if ( m_xModel.is() )
+ {
+ OUString sUrl = m_xModel->getURL();
+ if ( !sUrl.isEmpty() )
+ {
+ if ( ::comphelper::NamedValueCollection::getOrDefault( m_xModel->getArgs(), u"PickListEntry", true ) )
+ {
+ OUString aFilter;
+ INetURLObject aURL( m_xModel->getURL() );
+ std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter();
+ if ( pFilter )
+ aFilter = pFilter->GetFilterName();
+
+ // add to svtool history options
+ SvtHistoryOptions::AppendItem( EHistoryType::PickList,
+ aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
+ aFilter,
+ getStrippedDatabaseName(),
+ std::nullopt, std::nullopt);
+
+ // add to recent document list
+ if ( aURL.GetProtocol() == INetProtocol::File )
+ Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
+ pFilter ? pFilter->GetMimeType() : OUString(),
+ pFilter ? pFilter->GetServiceName() : OUString() );
+ }
+ }
+
+ m_xModel->disconnectController( this );
+
+ m_xModel.clear();
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ clearView();
+ OGenericUnoController::disposing(); // here the m_refCount must be equal 5
+}
+
+bool OApplicationController::Construct(vcl::Window* _pParent)
+{
+ setView( VclPtr<OApplicationView>::Create( _pParent, getORB(), *this, m_ePreviewMode ) );
+
+ // late construction
+ bool bSuccess = false;
+ try
+ {
+ getContainer()->Construct();
+ bSuccess = true;
+ }
+ catch(const SQLException&)
+ {
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("OApplicationController::Construct : the construction of UnoDataBrowserView failed !");
+ }
+
+ if ( !bSuccess )
+ {
+ clearView();
+ return false;
+ }
+
+ // now that we have a view we can create the clipboard listener
+ m_aSystemClipboard = TransferableDataHelper::CreateFromSystemClipboard( getView() );
+ m_aSystemClipboard.StartClipboardListening( );
+
+ m_pClipboardNotifier = new TransferableClipboardListener( LINK( this, OApplicationController, OnClipboardChanged ) );
+ m_pClipboardNotifier->AddListener( getView() );
+
+ OGenericUnoController::Construct( _pParent );
+ getView()->Show();
+
+ return true;
+}
+
+void SAL_CALL OApplicationController::disposing(const EventObject& _rSource)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ Reference<XConnection> xCon(_rSource.Source, UNO_QUERY);
+ if ( xCon.is() )
+ {
+ OSL_ENSURE( m_xDataSourceConnection == xCon,
+ "OApplicationController::disposing: which connection does this come from?" );
+
+ if ( getContainer() && getContainer()->getElementType() == E_TABLE )
+ getContainer()->clearPages();
+ if ( m_xDataSourceConnection == xCon )
+ {
+ m_xMetaData.clear();
+ m_xDataSourceConnection.clear();
+ }
+ }
+ else if ( _rSource.Source == m_xModel )
+ {
+ m_xModel.clear();
+ }
+ else if ( _rSource.Source == m_xDataSource )
+ {
+ m_xDataSource = nullptr;
+ }
+ else
+ {
+ Reference<XContainer> xContainer( _rSource.Source, UNO_QUERY );
+ if ( xContainer.is() )
+ {
+ TContainerVector::iterator aFind = std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer);
+ if ( aFind != m_aCurrentContainers.end() )
+ m_aCurrentContainers.erase(aFind);
+ }
+ OGenericUnoController::disposing( _rSource );
+ }
+}
+
+sal_Bool SAL_CALL OApplicationController::suspend(sal_Bool bSuspend)
+{
+ // notify the OnPrepareViewClosing event (before locking any mutex)
+ Reference< XDocumentEventBroadcaster > xBroadcaster( m_xModel, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->notifyDocumentEvent(
+ "OnPrepareViewClosing",
+ this,
+ Any()
+ );
+ }
+
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( getView() && getView()->IsInModalMode() )
+ return false;
+
+ bool bCanSuspend = true;
+
+ if ( m_bSuspended != bool(bSuspend) )
+ {
+ if ( bSuspend && !closeSubComponents() )
+ return false;
+
+ Reference<XModifiable> xModi(m_xModel,UNO_QUERY);
+ Reference<XStorable> xStor(getModel(),UNO_QUERY);
+
+ if ( bSuspend
+ && xStor.is()
+ && !xStor->isReadonly()
+ && ( xModi.is()
+ && xModi->isModified()
+ )
+ )
+ {
+ switch (ExecuteQuerySaveDocument(getFrameWeld(), getStrippedDatabaseName()))
+ {
+ case RET_YES:
+ Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
+ bCanSuspend = !xModi->isModified();
+ // when we save the document this must be false else some press cancel
+ break;
+ case RET_CANCEL:
+ bCanSuspend = false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if ( bCanSuspend )
+ m_bSuspended = bSuspend;
+
+ return bCanSuspend;
+}
+
+FeatureState OApplicationController::GetState(sal_uInt16 _nId) const
+{
+ FeatureState aReturn;
+ aReturn.bEnabled = false;
+ // check this first
+ if ( !getContainer() || m_bReadOnly )
+ return aReturn;
+
+ try
+ {
+ switch (_nId)
+ {
+ case SID_NEWDOCDIRECT:
+ aReturn.bEnabled = true;
+ aReturn.sTitle = "private:factory/sdatabase";
+ break;
+ case SID_OPENURL:
+ aReturn.bEnabled = true;
+ if ( m_xModel.is() )
+ aReturn.sTitle = m_xModel->getURL();
+ break;
+ case ID_BROWSER_COPY:
+ {
+ sal_Int32 nCount = getContainer()->getSelectionCount();
+ aReturn.bEnabled = nCount >= 1;
+ if ( aReturn.bEnabled && nCount == 1 && getContainer()->getElementType() == E_TABLE )
+ aReturn.bEnabled = getContainer()->isALeafSelected();
+ }
+ break;
+ case ID_BROWSER_CUT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() >= 1;
+ aReturn.bEnabled = aReturn.bEnabled && (getContainer()->getElementType() != E_TABLE || getContainer()->isCutAllowed());
+ break;
+ case ID_BROWSER_PASTE:
+ switch( getContainer()->getElementType() )
+ {
+ case E_TABLE:
+ aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly() && isTableFormat();
+ break;
+ case E_QUERY:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getViewClipboard().HasFormat(SotClipboardFormatId::DBACCESS_QUERY);
+ break;
+ default:
+ aReturn.bEnabled = !isDataSourceReadOnly() && OComponentTransferable::canExtractComponentDescriptor(getViewClipboard().GetDataFlavorExVector(),getContainer()->getElementType() == E_FORM);
+ }
+ break;
+ case SID_DB_APP_PASTE_SPECIAL:
+ aReturn.bEnabled = getContainer()->getElementType() == E_TABLE && !isDataSourceReadOnly() && !isConnectionReadOnly() && isTableFormat();
+ break;
+ case SID_OPENDOC:
+ aReturn.bEnabled = true;
+ break;
+ case ID_BROWSER_SAVEDOC:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ break;
+ case ID_BROWSER_SAVEASDOC:
+ aReturn.bEnabled = true;
+ break;
+ case ID_BROWSER_SORTUP:
+ aReturn.bEnabled = getContainer()->isFilled() && getContainer()->getElementCount();
+ aReturn.bChecked = aReturn.bEnabled && getContainer()->isSortUp();
+ break;
+ case ID_BROWSER_SORTDOWN:
+ aReturn.bEnabled = getContainer()->isFilled() && getContainer()->getElementCount();
+ aReturn.bChecked = aReturn.bEnabled && !getContainer()->isSortUp();
+ break;
+
+ case SID_NEWDOC:
+ case SID_APP_NEW_FORM:
+ case ID_DOCUMENT_CREATE_REPWIZ:
+ aReturn.bEnabled = !isDataSourceReadOnly() && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER);
+ break;
+ case SID_APP_NEW_REPORT:
+ aReturn.bEnabled = !isDataSourceReadOnly()
+ && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER);
+ if ( aReturn.bEnabled )
+ {
+ Reference< XContentEnumerationAccess > xEnumAccess(m_xContext->getServiceManager(), UNO_QUERY);
+ aReturn.bEnabled = xEnumAccess.is();
+ if ( aReturn.bEnabled )
+ {
+ const OUString sReportEngineServiceName = ::dbtools::getDefaultReportEngineServiceName(m_xContext);
+ aReturn.bEnabled = !sReportEngineServiceName.isEmpty();
+ if ( aReturn.bEnabled )
+ {
+ const Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(sReportEngineServiceName);
+ aReturn.bEnabled = xEnumDrivers.is() && xEnumDrivers->hasMoreElements();
+ }
+ }
+ }
+ break;
+ case SID_DB_APP_VIEW_TABLES:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_TABLE;
+ break;
+ case SID_DB_APP_VIEW_QUERIES:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_QUERY;
+ break;
+ case SID_DB_APP_VIEW_FORMS:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_FORM;
+ break;
+ case SID_DB_APP_VIEW_REPORTS:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_REPORT;
+ break;
+ case ID_NEW_QUERY_DESIGN:
+ case ID_NEW_QUERY_SQL:
+ case ID_APP_NEW_QUERY_AUTO_PILOT:
+ case SID_DB_FORM_NEW_PILOT:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ break;
+ case ID_NEW_VIEW_DESIGN:
+ case SID_DB_NEW_VIEW_SQL:
+ case ID_NEW_VIEW_DESIGN_AUTO_PILOT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly();
+ if ( aReturn.bEnabled )
+ {
+ Reference<XViewsSupplier> xViewsSup( getConnection(), UNO_QUERY );
+ aReturn.bEnabled = xViewsSup.is();
+ }
+ break;
+ case ID_NEW_TABLE_DESIGN:
+ case ID_NEW_TABLE_DESIGN_AUTO_PILOT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly();
+ break;
+ case ID_DIRECT_SQL:
+ aReturn.bEnabled = true;
+ break;
+ case SID_APP_NEW_FOLDER:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() <= 1;
+ if ( aReturn.bEnabled )
+ {
+ const ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = eType == E_REPORT || eType == E_FORM;
+ }
+ break;
+ case SID_FORM_CREATE_REPWIZ_PRE_SEL:
+ case SID_REPORT_CREATE_REPWIZ_PRE_SEL:
+ case SID_APP_NEW_REPORT_PRE_SEL:
+ aReturn.bEnabled = !isDataSourceReadOnly()
+ && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER)
+ && getContainer()->isALeafSelected();
+ if ( aReturn.bEnabled )
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = eType == E_QUERY || eType == E_TABLE;
+ if ( aReturn.bEnabled && SID_APP_NEW_REPORT_PRE_SEL == _nId )
+ {
+ Reference< XContentEnumerationAccess > xEnumAccess(m_xContext->getServiceManager(), UNO_QUERY);
+ aReturn.bEnabled = xEnumAccess.is();
+ if ( aReturn.bEnabled )
+ {
+ static constexpr OUStringLiteral s_sReportDesign = u"org.libreoffice.report.pentaho.SOReportJobFactory";
+ Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(s_sReportDesign);
+ aReturn.bEnabled = xEnumDrivers.is() && xEnumDrivers->hasMoreElements();
+ }
+ }
+ }
+ break;
+ case SID_DB_APP_DELETE:
+ case SID_DB_APP_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(getContainer()->getElementType(), _nId == SID_DB_APP_DELETE);
+ break;
+ case SID_DB_APP_TABLE_DELETE:
+ case SID_DB_APP_TABLE_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_TABLE, _nId == SID_DB_APP_TABLE_DELETE);
+ break;
+ case SID_DB_APP_QUERY_DELETE:
+ case SID_DB_APP_QUERY_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_QUERY, _nId == SID_DB_APP_QUERY_DELETE);
+ break;
+ case SID_DB_APP_FORM_DELETE:
+ case SID_DB_APP_FORM_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_FORM, _nId == SID_DB_APP_FORM_DELETE);
+ break;
+ case SID_DB_APP_REPORT_DELETE:
+ case SID_DB_APP_REPORT_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_REPORT, _nId == SID_DB_APP_REPORT_DELETE);
+ break;
+
+ case SID_SELECTALL:
+ aReturn.bEnabled = getContainer()->getElementCount() > 0 && getContainer()->getSelectionCount() != getContainer()->getElementCount();
+ break;
+ case SID_DB_APP_EDIT:
+ case SID_DB_APP_TABLE_EDIT:
+ case SID_DB_APP_QUERY_EDIT:
+ case SID_DB_APP_FORM_EDIT:
+ case SID_DB_APP_REPORT_EDIT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() > 0
+ && getContainer()->isALeafSelected();
+ break;
+ case SID_DB_APP_EDIT_SQL_VIEW:
+ if ( isDataSourceReadOnly() )
+ aReturn.bEnabled = false;
+ else
+ {
+ switch ( getContainer()->getElementType() )
+ {
+ case E_QUERY:
+ aReturn.bEnabled = ( getContainer()->getSelectionCount() > 0 )
+ && ( getContainer()->isALeafSelected() );
+ break;
+ case E_TABLE:
+ aReturn.bEnabled = false;
+ // there's one exception: views which support altering their underlying
+ // command can be edited in SQL view, too
+ if ( ( getContainer()->getSelectionCount() > 0 )
+ && ( getContainer()->isALeafSelected() )
+ )
+ {
+ std::vector< OUString > aSelected;
+ getSelectionElementNames( aSelected );
+ bool bAlterableViews = true;
+ for (auto const& selectedName : aSelected)
+ {
+ bAlterableViews &= impl_isAlterableView_nothrow(selectedName);
+ if (!bAlterableViews)
+ break;
+ }
+ aReturn.bEnabled = bAlterableViews;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case SID_DB_APP_OPEN:
+ case SID_DB_APP_TABLE_OPEN:
+ case SID_DB_APP_QUERY_OPEN:
+ case SID_DB_APP_FORM_OPEN:
+ case SID_DB_APP_REPORT_OPEN:
+ aReturn.bEnabled = getContainer()->getSelectionCount() > 0 && getContainer()->isALeafSelected();
+ break;
+ case SID_DB_APP_DSUSERADMIN:
+ aReturn.bEnabled = !dbaccess::ODsnTypeCollection::isEmbeddedDatabase(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL)));
+ break;
+ case SID_DB_APP_DSRELDESIGN:
+ aReturn.bEnabled = true;
+ break;
+ case SID_DB_APP_TABLEFILTER:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ break;
+ case SID_DB_APP_REFRESH_TABLES:
+ aReturn.bEnabled = getContainer()->getElementType() == E_TABLE && isConnected();
+ break;
+ case SID_DB_APP_DSPROPS:
+ aReturn.bEnabled = m_xDataSource.is() && dbaccess::ODsnTypeCollection::isShowPropertiesEnabled(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL)));
+ break;
+ case SID_DB_APP_DSCONNECTION_TYPE:
+ aReturn.bEnabled = !isDataSourceReadOnly() && m_xDataSource.is() && !dbaccess::ODsnTypeCollection::isEmbeddedDatabase(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL)));
+ break;
+ case SID_DB_APP_DSADVANCED_SETTINGS:
+ aReturn.bEnabled = m_xDataSource.is() && AdvancedSettingsDialog::doesHaveAnyAdvancedSettings( m_aTypeCollection.getType(::comphelper::getString( m_xDataSource->getPropertyValue( PROPERTY_URL ) )) );
+ break;
+ case SID_DB_APP_CONVERTTOVIEW:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ if ( aReturn.bEnabled )
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = eType == E_QUERY && getContainer()->getSelectionCount() > 0;
+ if ( aReturn.bEnabled )
+ {
+ Reference<XViewsSupplier> xViewSup( getConnection(), UNO_QUERY );
+ aReturn.bEnabled = xViewSup.is() && Reference<XAppend>(xViewSup->getViews(),UNO_QUERY).is();
+ }
+ }
+ break;
+ case SID_DB_APP_DISABLE_PREVIEW:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getPreviewMode() == E_PREVIEWNONE;
+ break;
+ case SID_DB_APP_VIEW_DOCINFO_PREVIEW:
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = (E_REPORT == eType || E_FORM == eType);
+ aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENTINFO;
+ }
+ break;
+ case SID_DB_APP_VIEW_DOC_PREVIEW:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENT;
+ break;
+ case ID_BROWSER_UNDO:
+ aReturn.bEnabled = false;
+ break;
+ case SID_MAIL_SENDDOC:
+ aReturn.bEnabled = true;
+ break;
+ case SID_DB_APP_SENDREPORTASMAIL:
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = E_REPORT == eType && getContainer()->getSelectionCount() > 0 && getContainer()->isALeafSelected();
+ }
+ break;
+ case SID_DB_APP_SENDREPORTTOWRITER:
+ case SID_DB_APP_DBADMIN:
+ aReturn.bEnabled = false;
+ break;
+ case SID_DB_APP_STATUS_TYPE:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ {
+ OUString sURL;
+ m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL;
+ OUString sDSTypeName;
+ if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase( sURL ) )
+ {
+ sDSTypeName = DBA_RES(RID_STR_EMBEDDED_DATABASE);
+ }
+ else
+ {
+ sDSTypeName = m_aTypeCollection.getTypeDisplayName(sURL);
+ }
+ aReturn.sTitle = sDSTypeName;
+ }
+ break;
+ case SID_DB_APP_STATUS_DBNAME:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ {
+ OUString sURL;
+ m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL;
+ OUString sDatabaseName;
+ OUString sHostName;
+ sal_Int32 nPortNumber( -1 );
+
+ m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber );
+
+ if ( sDatabaseName.isEmpty() )
+ sDatabaseName = m_aTypeCollection.cutPrefix( sURL );
+ if ( m_aTypeCollection.isFileSystemBased(sURL) )
+ {
+ sDatabaseName = SvtPathOptions().SubstituteVariable( sDatabaseName );
+ if ( !sDatabaseName.isEmpty() )
+ {
+ ::svt::OFileNotation aFileNotation(sDatabaseName);
+ // set this decoded URL as text
+ sDatabaseName = aFileNotation.get(::svt::OFileNotation::N_SYSTEM);
+ }
+ }
+
+ if ( sDatabaseName.isEmpty() )
+ sDatabaseName = m_aTypeCollection.getTypeDisplayName( sURL );
+
+ aReturn.sTitle = sDatabaseName;
+ }
+ break;
+ case SID_DB_APP_STATUS_USERNAME:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ m_xDataSource->getPropertyValue( PROPERTY_USER ) >>= aReturn.sTitle;
+ break;
+ case SID_DB_APP_STATUS_HOSTNAME:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ {
+ OUString sURL;
+ m_xDataSource->getPropertyValue( PROPERTY_URL ) >>= sURL;
+
+ OUString sHostName, sDatabaseName;
+ sal_Int32 nPortNumber = -1;
+ m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber );
+ aReturn.sTitle = sHostName;
+ }
+ break;
+ default:
+ aReturn = OGenericUnoController::GetState(_nId);
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return aReturn;
+}
+
+namespace
+{
+ bool lcl_handleException_nothrow( const Reference< XModel >& _rxDocument, const Any& _rException )
+ {
+ bool bHandled = false;
+
+ // try handling the error with an interaction handler
+ Reference< XInteractionHandler > xHandler = ::comphelper::NamedValueCollection::getOrDefault( _rxDocument->getArgs(), u"InteractionHandler", Reference< XInteractionHandler >() );
+ if ( xHandler.is() )
+ {
+ rtl::Reference pRequest( new ::comphelper::OInteractionRequest( _rException ) );
+ rtl::Reference pApprove( new ::comphelper::OInteractionApprove );
+ pRequest->addContinuation( pApprove );
+
+ try
+ {
+ xHandler->handle( pRequest );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ bHandled = pApprove->wasSelected();
+ }
+ return bHandled;
+ }
+}
+
+void OApplicationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( isUserDefinedFeature( _nId ) )
+ {
+ OGenericUnoController::Execute( _nId, aArgs );
+ return;
+ }
+
+ if ( !getContainer() || m_bReadOnly )
+ return; // return without execution
+
+ try
+ {
+ switch(_nId)
+ {
+ case ID_BROWSER_CUT:
+ getContainer()->cut();
+ break;
+ case ID_BROWSER_COPY:
+ {
+ rtl::Reference<TransferableHelper> pTransfer = copyObject();
+ if ( pTransfer )
+ pTransfer->CopyToClipboard(getView());
+ }
+ break;
+ case ID_BROWSER_PASTE:
+ {
+ const TransferableDataHelper& rTransferData( getViewClipboard() );
+ ElementType eType = getContainer()->getElementType();
+
+ switch( eType )
+ {
+ case E_TABLE:
+ {
+ // get the selected tablename
+ std::vector< OUString > aList;
+ getSelectionElementNames( aList );
+ if ( !aList.empty() )
+ m_aTableCopyHelper.SetTableNameForAppend( *aList.begin() );
+ else
+ m_aTableCopyHelper.ResetTableNameForAppend();
+
+ m_aTableCopyHelper.pasteTable( rTransferData , getDatabaseName(), ensureConnection() );
+ }
+ break;
+
+ case E_QUERY:
+ if ( rTransferData.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) )
+ paste( E_QUERY, ODataAccessObjectTransferable::extractObjectDescriptor( rTransferData ) );
+ break;
+ default:
+ {
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ OUString sFolderNameToInsertInto;
+ if ( !aList.empty() )
+ {
+ Reference< XHierarchicalNameAccess > xContainer(getElements(eType),UNO_QUERY);
+ if ( xContainer.is()
+ && xContainer->hasByHierarchicalName(*aList.begin())
+ && (xContainer->getByHierarchicalName(*aList.begin()) >>= xContainer)
+ && xContainer.is()
+ )
+ sFolderNameToInsertInto = *aList.begin();
+ }
+ paste( eType, OComponentTransferable::extractComponentDescriptor( rTransferData ),
+ sFolderNameToInsertInto );
+ }
+ break;
+ }
+ }
+ break;
+ case SID_DB_APP_PASTE_SPECIAL:
+ {
+ if ( !aArgs.hasElements() )
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(getFrameWeld()));
+ std::vector<SotClipboardFormatId> aFormatIds;
+ getSupportedFormats(getContainer()->getElementType(),aFormatIds);
+ for (auto const& formatId : aFormatIds)
+ pDlg->Insert(formatId,"");
+
+ const TransferableDataHelper& rClipboard = getViewClipboard();
+ pasteFormat(pDlg->GetFormat(rClipboard.GetTransferable()));
+ }
+ else
+ {
+ const PropertyValue* pIter = aArgs.getConstArray();
+ const PropertyValue* pEnd = pIter + aArgs.getLength();
+ for( ; pIter != pEnd ; ++pIter)
+ {
+ if ( pIter->Name == "FormatStringId" )
+ {
+ sal_uLong nTmp;
+ if ( pIter->Value >>= nTmp )
+ pasteFormat(static_cast<SotClipboardFormatId>(nTmp));
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case SID_NEWDOCDIRECT:
+ case SID_OPENDOC:
+ {
+ Reference < XDispatchProvider > xProv( getFrame(), UNO_QUERY );
+ if ( xProv.is() )
+ {
+ URL aURL;
+ OUString aTarget;
+ if ( _nId == SID_NEWDOCDIRECT )
+ {
+ aURL.Complete = "private:factory/sdatabase?Interactive";
+ aTarget = "_default";
+ }
+ else
+ aURL.Complete = ".uno:Open";
+
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aURL );
+ Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, aTarget, 0 );
+ if ( xDisp.is() )
+ xDisp->dispatch( aURL, Sequence < PropertyValue >() );
+ }
+ }
+ break;
+ case ID_BROWSER_SAVEDOC:
+ {
+ Reference< XStorable > xStore( m_xModel, UNO_QUERY_THROW );
+ try
+ {
+ xStore->store();
+ }
+ catch( const Exception& )
+ {
+ lcl_handleException_nothrow( m_xModel, ::cppu::getCaughtException() );
+ }
+ }
+ break;
+
+ case ID_BROWSER_SAVEASDOC:
+ {
+ OUString sUrl;
+ if ( m_xModel.is() )
+ sUrl = m_xModel->getURL();
+
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE, getFrameWeld());
+ aFileDlg.SetContext(sfx2::FileDialogHelper::BaseSaveAs);
+ if (!sUrl.isEmpty())
+ aFileDlg.SetDisplayDirectory( sUrl );
+
+ std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter();
+ if ( pFilter )
+ {
+ aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension());
+ aFileDlg.SetCurrentFilter(pFilter->GetUIName());
+ }
+
+ if ( aFileDlg.Execute() != ERRCODE_NONE )
+ break;
+
+ Reference<XStorable> xStore( m_xModel, UNO_QUERY_THROW );
+ INetURLObject aURL( aFileDlg.GetPath() );
+ try
+ {
+ xStore->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Sequence< PropertyValue >() );
+ }
+ catch( const Exception& )
+ {
+ lcl_handleException_nothrow( m_xModel, ::cppu::getCaughtException() );
+ }
+
+ /*updateTitle();*/
+ m_bCurrentlyModified = false;
+ InvalidateFeature(ID_BROWSER_SAVEDOC);
+ if ( getContainer()->getElementType() == E_NONE )
+ {
+ getContainer()->selectContainer(E_NONE);
+ getContainer()->selectContainer(E_TABLE);
+ // #i95524#
+ getContainer()->Invalidate();
+ refreshTables();
+ }
+
+ }
+ break;
+ case ID_BROWSER_SORTUP:
+ getContainer()->sortUp();
+ InvalidateFeature(ID_BROWSER_SORTDOWN);
+ break;
+ case ID_BROWSER_SORTDOWN:
+ getContainer()->sortDown();
+ InvalidateFeature(ID_BROWSER_SORTUP);
+ break;
+
+ case ID_NEW_TABLE_DESIGN_AUTO_PILOT:
+ case ID_NEW_VIEW_DESIGN_AUTO_PILOT:
+ case ID_APP_NEW_QUERY_AUTO_PILOT:
+ case SID_DB_FORM_NEW_PILOT:
+ case SID_REPORT_CREATE_REPWIZ_PRE_SEL:
+ case SID_APP_NEW_REPORT_PRE_SEL:
+ case SID_FORM_CREATE_REPWIZ_PRE_SEL:
+ case ID_DOCUMENT_CREATE_REPWIZ:
+ case SID_APP_NEW_FORM:
+ case SID_APP_NEW_REPORT:
+ case ID_NEW_QUERY_SQL:
+ case ID_NEW_QUERY_DESIGN:
+ case ID_NEW_TABLE_DESIGN:
+ {
+ ElementType eType = E_TABLE;
+ bool bAutoPilot = false;
+ ::comphelper::NamedValueCollection aCreationArgs;
+
+ switch( _nId )
+ {
+ case SID_DB_FORM_NEW_PILOT:
+ case SID_FORM_CREATE_REPWIZ_PRE_SEL:
+ bAutoPilot = true;
+ [[fallthrough]];
+ case SID_APP_NEW_FORM:
+ eType = E_FORM;
+ break;
+ case ID_DOCUMENT_CREATE_REPWIZ:
+ case SID_REPORT_CREATE_REPWIZ_PRE_SEL:
+ bAutoPilot = true;
+ [[fallthrough]];
+ case SID_APP_NEW_REPORT:
+ case SID_APP_NEW_REPORT_PRE_SEL:
+ eType = E_REPORT;
+ break;
+ case ID_APP_NEW_QUERY_AUTO_PILOT:
+ bAutoPilot = true;
+ eType = E_QUERY;
+ break;
+ case ID_NEW_QUERY_DESIGN:
+ aCreationArgs.put( PROPERTY_GRAPHICAL_DESIGN, true );
+ [[fallthrough]];
+ case ID_NEW_QUERY_SQL:
+ eType = E_QUERY;
+ break;
+ case ID_NEW_TABLE_DESIGN_AUTO_PILOT:
+ bAutoPilot = true;
+ [[fallthrough]];
+ case ID_NEW_TABLE_DESIGN:
+ break;
+ default:
+ OSL_FAIL("illegal switch call!");
+ }
+ if ( bAutoPilot )
+ getContainer()->PostUserEvent( LINK( this, OApplicationController, OnCreateWithPilot ), reinterpret_cast< void* >( eType ) );
+ else
+ {
+ Reference< XComponent > xDocDefinition;
+ newElement( eType, aCreationArgs, xDocDefinition );
+ }
+ }
+ break;
+ case SID_APP_NEW_FOLDER:
+ {
+ ElementType eType = getContainer()->getElementType();
+ OUString sName = getContainer()->getQualifiedName( nullptr );
+ insertHierarchyElement(eType,sName);
+ }
+ break;
+ case ID_NEW_VIEW_DESIGN:
+ case SID_DB_NEW_VIEW_SQL:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ {
+ QueryDesigner aDesigner( getORB(), this, getFrame(), true );
+
+ ::comphelper::NamedValueCollection aCreationArgs;
+ aCreationArgs.put( PROPERTY_GRAPHICAL_DESIGN, ID_NEW_VIEW_DESIGN == _nId );
+
+ const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource, aCreationArgs );
+ onDocumentOpened( OUString(), E_QUERY, E_OPEN_DESIGN, xComponent, nullptr );
+ }
+ }
+ break;
+ case SID_DB_APP_DELETE:
+ case SID_DB_APP_TABLE_DELETE:
+ case SID_DB_APP_QUERY_DELETE:
+ case SID_DB_APP_FORM_DELETE:
+ case SID_DB_APP_REPORT_DELETE:
+ deleteEntries();
+ break;
+ case SID_DB_APP_RENAME:
+ case SID_DB_APP_TABLE_RENAME:
+ case SID_DB_APP_QUERY_RENAME:
+ case SID_DB_APP_FORM_RENAME:
+ case SID_DB_APP_REPORT_RENAME:
+ renameEntry();
+ break;
+ case SID_DB_APP_EDIT:
+ case SID_DB_APP_EDIT_SQL_VIEW:
+ case SID_DB_APP_TABLE_EDIT:
+ case SID_DB_APP_QUERY_EDIT:
+ case SID_DB_APP_FORM_EDIT:
+ case SID_DB_APP_REPORT_EDIT:
+ doAction( _nId, E_OPEN_DESIGN );
+ break;
+ case SID_DB_APP_OPEN:
+ case SID_DB_APP_TABLE_OPEN:
+ case SID_DB_APP_QUERY_OPEN:
+ case SID_DB_APP_FORM_OPEN:
+ case SID_DB_APP_REPORT_OPEN:
+ doAction( _nId, E_OPEN_NORMAL );
+ break;
+ case SID_DB_APP_CONVERTTOVIEW:
+ doAction( _nId, E_OPEN_NORMAL );
+ break;
+ case SID_SELECTALL:
+ getContainer()->selectAll();
+ InvalidateAll();
+ break;
+ case SID_DB_APP_DSRELDESIGN:
+ {
+ Reference< XComponent > xRelationDesigner;
+ if ( !m_pSubComponentManager->activateSubFrame( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xRelationDesigner ) )
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ {
+ RelationDesigner aDesigner( getORB(), this, m_aCurrentFrame.getFrame() );
+
+ const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource );
+ onDocumentOpened( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xComponent, nullptr );
+ }
+ }
+ }
+ break;
+ case SID_DB_APP_DSUSERADMIN:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ openDialog("com.sun.star.sdb.UserAdministrationDialog");
+ }
+ break;
+ case SID_DB_APP_TABLEFILTER:
+ // opens the table filter dialog for the selected data source
+ openDialog( "com.sun.star.sdb.TableFilterDialog" );
+ askToReconnect();
+ break;
+ case SID_DB_APP_REFRESH_TABLES:
+ refreshTables();
+ break;
+ case SID_DB_APP_DSPROPS:
+ // opens the administration dialog for the selected data source
+ openDialog( "com.sun.star.sdb.DatasourceAdministrationDialog" );
+ askToReconnect();
+ break;
+ case SID_DB_APP_DSADVANCED_SETTINGS:
+ openDialog("com.sun.star.sdb.AdvancedDatabaseSettingsDialog");
+ askToReconnect();
+ break;
+ case SID_DB_APP_DSCONNECTION_TYPE:
+ openDialog("com.sun.star.sdb.DataSourceTypeChangeDialog");
+ askToReconnect();
+ break;
+ case ID_DIRECT_SQL:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ // opens the DirectSQLDialog to execute hand made sql statements.
+ openDialog( SERVICE_SDB_DIRECTSQLDIALOG );
+ }
+ break;
+ case SID_DB_APP_VIEW_TABLES:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_TABLE ) );
+ break;
+ case SID_DB_APP_VIEW_QUERIES:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_QUERY ) );
+ break;
+ case SID_DB_APP_VIEW_FORMS:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_FORM ) );
+ break;
+ case SID_DB_APP_VIEW_REPORTS:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_REPORT ) );
+ break;
+ case SID_DB_APP_DISABLE_PREVIEW:
+ m_ePreviewMode = E_PREVIEWNONE;
+ getContainer()->switchPreview(m_ePreviewMode);
+ break;
+ case SID_DB_APP_VIEW_DOCINFO_PREVIEW:
+ m_ePreviewMode = E_DOCUMENTINFO;
+ getContainer()->switchPreview(m_ePreviewMode);
+ break;
+ case SID_DB_APP_VIEW_DOC_PREVIEW:
+ m_ePreviewMode = E_DOCUMENT;
+ getContainer()->switchPreview(m_ePreviewMode);
+ break;
+ case SID_MAIL_SENDDOC:
+ {
+ SfxMailModel aSendMail;
+ if ( aSendMail.AttachDocument(getModel(), OUString()) == SfxMailModel::SEND_MAIL_OK )
+ aSendMail.Send( getFrame() );
+ }
+ break;
+ case SID_DB_APP_SENDREPORTASMAIL:
+ doAction( _nId, E_OPEN_FOR_MAIL );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ InvalidateFeature(_nId);
+}
+
+void OApplicationController::describeSupportedFeatures()
+{
+ OGenericUnoController::describeSupportedFeatures();
+
+ implDescribeSupportedFeature( ".uno:AddDirect", SID_NEWDOCDIRECT, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:SendMail", SID_MAIL_SENDDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBSendReportAsMail",SID_DB_APP_SENDREPORTASMAIL,
+ CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBSendReportToWriter",SID_DB_APP_SENDREPORTTOWRITER,
+ CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBNewForm", SID_APP_NEW_FORM, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewFolder", SID_APP_NEW_FOLDER, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewFormAutoPilot", SID_DB_FORM_NEW_PILOT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewFormAutoPilotWithPreSelection",
+ SID_FORM_CREATE_REPWIZ_PRE_SEL,
+ CommandGroup::APPLICATION );
+
+ implDescribeSupportedFeature( ".uno:DBNewReport", SID_APP_NEW_REPORT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewReportAutoPilot",
+ ID_DOCUMENT_CREATE_REPWIZ, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewReportAutoPilotWithPreSelection",
+ SID_REPORT_CREATE_REPWIZ_PRE_SEL,
+ CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBNewQuery", ID_NEW_QUERY_DESIGN, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewQuerySql", ID_NEW_QUERY_SQL, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewQueryAutoPilot",ID_APP_NEW_QUERY_AUTO_PILOT,
+ CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewTable", ID_NEW_TABLE_DESIGN, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewTableAutoPilot",ID_NEW_TABLE_DESIGN_AUTO_PILOT,
+ CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewView", ID_NEW_VIEW_DESIGN, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewViewSQL", SID_DB_NEW_VIEW_SQL, CommandGroup::INSERT );
+
+ implDescribeSupportedFeature( ".uno:DBDelete", SID_DB_APP_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Delete", SID_DB_APP_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBRename", SID_DB_APP_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBEdit", SID_DB_APP_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBEditSqlView", SID_DB_APP_EDIT_SQL_VIEW, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBOpen", SID_DB_APP_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBTableDelete", SID_DB_APP_TABLE_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBTableRename", SID_DB_APP_TABLE_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBTableEdit", SID_DB_APP_TABLE_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBTableOpen", SID_DB_APP_TABLE_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBQueryDelete", SID_DB_APP_QUERY_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBQueryRename", SID_DB_APP_QUERY_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBQueryEdit", SID_DB_APP_QUERY_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBQueryOpen", SID_DB_APP_QUERY_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBFormDelete", SID_DB_APP_FORM_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBFormRename", SID_DB_APP_FORM_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBFormEdit", SID_DB_APP_FORM_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBFormOpen", SID_DB_APP_FORM_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBReportDelete", SID_DB_APP_REPORT_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBReportRename", SID_DB_APP_REPORT_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBReportEdit", SID_DB_APP_REPORT_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBReportOpen", SID_DB_APP_REPORT_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:SelectAll", SID_SELECTALL, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:Sortup", ID_BROWSER_SORTUP, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:SortDown", ID_BROWSER_SORTDOWN, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBRelationDesign", SID_DB_APP_DSRELDESIGN, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBUserAdmin", SID_DB_APP_DSUSERADMIN, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBTableFilter", SID_DB_APP_TABLEFILTER, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBDSProperties", SID_DB_APP_DSPROPS, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBDSConnectionType", SID_DB_APP_DSCONNECTION_TYPE,
+ CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBDSAdvancedSettings",
+ SID_DB_APP_DSADVANCED_SETTINGS,
+ CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:PasteSpecial", SID_DB_APP_PASTE_SPECIAL, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBConvertToView", SID_DB_APP_CONVERTTOVIEW, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBRefreshTables", SID_DB_APP_REFRESH_TABLES, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBDirectSQL", ID_DIRECT_SQL, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBViewTables", SID_DB_APP_VIEW_TABLES, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewQueries", SID_DB_APP_VIEW_QUERIES, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewForms", SID_DB_APP_VIEW_FORMS, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewReports", SID_DB_APP_VIEW_REPORTS, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBDisablePreview", SID_DB_APP_DISABLE_PREVIEW,CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBShowDocInfoPreview",
+ SID_DB_APP_VIEW_DOCINFO_PREVIEW,
+ CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBShowDocPreview", SID_DB_APP_VIEW_DOC_PREVIEW,
+ CommandGroup::VIEW );
+
+ implDescribeSupportedFeature( ".uno:OpenUrl", SID_OPENURL, CommandGroup::APPLICATION );
+
+ // this one should not appear under Tools->Customize->Keyboard
+ implDescribeSupportedFeature( ".uno:DBNewReportWithPreSelection",
+ SID_APP_NEW_REPORT_PRE_SEL );
+ implDescribeSupportedFeature( ".uno:DBDSImport", SID_DB_APP_DSIMPORT);
+ implDescribeSupportedFeature( ".uno:DBDSExport", SID_DB_APP_DSEXPORT);
+ implDescribeSupportedFeature( ".uno:DBDBAdmin", SID_DB_APP_DBADMIN);
+
+ // status info
+ implDescribeSupportedFeature( ".uno:DBStatusType", SID_DB_APP_STATUS_TYPE);
+ implDescribeSupportedFeature( ".uno:DBStatusDBName", SID_DB_APP_STATUS_DBNAME);
+ implDescribeSupportedFeature( ".uno:DBStatusUserName", SID_DB_APP_STATUS_USERNAME);
+ implDescribeSupportedFeature( ".uno:DBStatusHostName", SID_DB_APP_STATUS_HOSTNAME);
+}
+
+OApplicationView* OApplicationController::getContainer() const
+{
+ return static_cast< OApplicationView* >( getView() );
+}
+
+// css::container::XContainerListener
+void SAL_CALL OApplicationController::elementInserted( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY);
+ if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() )
+ return;
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ if ( !getContainer() )
+ return;
+
+ OUString sName;
+ _rEvent.Accessor >>= sName;
+ ElementType eType = getElementType(xContainer);
+
+ switch( eType )
+ {
+ case E_TABLE:
+ ensureConnection();
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference< XContainer > xSubContainer(_rEvent.Element,UNO_QUERY);
+ if ( xSubContainer.is() )
+ containerFound(xSubContainer);
+ }
+ break;
+ default:
+ break;
+ }
+ getContainer()->elementAdded(eType,sName,_rEvent.Element);
+}
+
+void SAL_CALL OApplicationController::elementRemoved( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY);
+ if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() )
+ return;
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ OUString sName;
+ _rEvent.Accessor >>= sName;
+ ElementType eType = getElementType(xContainer);
+ switch( eType )
+ {
+ case E_TABLE:
+ ensureConnection();
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference<XContent> xContent(xContainer,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ sName = xContent->getIdentifier()->getContentIdentifier() + "/" + sName;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ getContainer()->elementRemoved(eType,sName);
+}
+
+void SAL_CALL OApplicationController::elementReplaced( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY);
+ if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() )
+ return;
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ OUString sName;
+ try
+ {
+ _rEvent.Accessor >>= sName;
+ Reference<XPropertySet> xProp(_rEvent.Element,UNO_QUERY);
+
+ ElementType eType = getElementType(xContainer);
+ switch( eType )
+ {
+ case E_TABLE:
+ {
+ ensureConnection();
+ if ( xProp.is() && m_xMetaData.is() )
+ //TODO: tdf#133497 "OApplicationController::elementReplaced effectively does
+ // nothing":
+ (void) ::dbaui::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InDataManipulation, false );
+ }
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference<XContent> xContent(xContainer,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ sName = xContent->getIdentifier()->getContentIdentifier() + "/" + sName;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ // getContainer()->elementReplaced(getContainer()->getElementType(),sName,sNewName);
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+namespace
+{
+ OUString lcl_getToolBarResource(ElementType _eType)
+ {
+ OUString sToolbar;
+ switch(_eType)
+ {
+ case E_TABLE:
+ sToolbar = "private:resource/toolbar/tableobjectbar";
+ break;
+ case E_QUERY:
+ sToolbar = "private:resource/toolbar/queryobjectbar";
+ break;
+ case E_FORM:
+ sToolbar = "private:resource/toolbar/formobjectbar";
+ break;
+ case E_REPORT:
+ sToolbar = "private:resource/toolbar/reportobjectbar";
+ break;
+ case E_NONE:
+ break;
+ default:
+ OSL_FAIL("Invalid ElementType!");
+ break;
+ }
+ return sToolbar;
+ }
+}
+
+bool OApplicationController::onContainerSelect(ElementType _eType)
+{
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+
+ if ( m_eCurrentType != _eType && _eType != E_NONE )
+ {
+ SelectionGuard aSelGuard( *m_pSelectionNotifier );
+
+ if ( _eType == E_TABLE )
+ {
+ try
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() && getContainer()->getDetailView() )
+ {
+ getContainer()->getDetailView()->createTablesPage(xConnection);
+ Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY);
+ if ( xTabSup.is() )
+ addContainerListener(xTabSup->getTables());
+ }
+ else
+ {
+ return false;
+ }
+ }
+ catch( const Exception& )
+ {
+ return false;
+ }
+ }
+ else if ( _eType == E_QUERY )
+ {
+ // tdf#126578: retrieve connection to be able to call "Create as View"
+ ensureConnection();
+ }
+ Reference< XLayoutManager > xLayoutManager = getLayoutManager( getFrame() );
+ if ( xLayoutManager.is() )
+ {
+ OUString sToolbar = lcl_getToolBarResource(_eType);
+ OUString sDestroyToolbar = lcl_getToolBarResource(m_eCurrentType);
+
+ xLayoutManager->lock();
+ xLayoutManager->destroyElement( sDestroyToolbar );
+ if ( !sToolbar.isEmpty() )
+ {
+ xLayoutManager->createElement( sToolbar );
+ xLayoutManager->requestElement( sToolbar );
+ }
+ xLayoutManager->unlock();
+ xLayoutManager->doLayout();
+ }
+
+ if ( _eType != E_TABLE && getContainer()->getDetailView() )
+ {
+ Reference< XNameAccess > xContainer = getElements(_eType);
+ addContainerListener(xContainer);
+ getContainer()->getDetailView()->createPage(_eType,xContainer);
+ }
+
+ SelectionByElementType::const_iterator pendingSelection = m_aPendingSelection.find( _eType );
+ if ( pendingSelection != m_aPendingSelection.end() )
+ {
+ getContainer()->selectElements( comphelper::containerToSequence(pendingSelection->second) );
+
+ m_aPendingSelection.erase( pendingSelection );
+ }
+
+ InvalidateAll();
+ }
+ m_eCurrentType = _eType;
+
+ return true;
+}
+
+bool OApplicationController::onEntryDoubleClick(const weld::TreeView& rTreeView)
+{
+ OApplicationView* pContainer = getContainer();
+ if (!pContainer)
+ return false; // not handled
+
+ std::unique_ptr<weld::TreeIter> xHdlEntry = rTreeView.make_iterator();
+ if (!rTreeView.get_cursor(xHdlEntry.get()))
+ return false;
+
+ if (!pContainer->isLeaf(rTreeView, *xHdlEntry))
+ return false; // not handled
+
+ try
+ {
+ // opens a new frame with either the table or the query or report or form or view
+ openElementWithArguments(
+ getContainer()->getQualifiedName(xHdlEntry.get()),
+ getContainer()->getElementType(),
+ E_OPEN_NORMAL,
+ 0,
+ ::comphelper::NamedValueCollection() );
+ return true; // handled
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return false; // not handled
+}
+
+bool OApplicationController::impl_isAlterableView_nothrow( const OUString& _rTableOrViewName ) const
+{
+ OSL_PRECOND( m_xDataSourceConnection.is(), "OApplicationController::impl_isAlterableView_nothrow: no connection!" );
+
+ bool bIsAlterableView( false );
+ try
+ {
+ Reference< XViewsSupplier > xViewsSupp( m_xDataSourceConnection, UNO_QUERY );
+ Reference< XNameAccess > xViews;
+ if ( xViewsSupp.is() )
+ xViews = xViewsSupp->getViews();
+
+ Reference< XAlterView > xAsAlterableView;
+ if ( xViews.is() && xViews->hasByName( _rTableOrViewName ) )
+ xAsAlterableView.set( xViews->getByName( _rTableOrViewName ), UNO_QUERY );
+
+ bIsAlterableView = xAsAlterableView.is();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bIsAlterableView;
+}
+
+Reference< XComponent > OApplicationController::openElementWithArguments( const OUString& _sName, ElementType _eType,
+ ElementOpenMode _eOpenMode, sal_uInt16 _nInstigatorCommand, const ::comphelper::NamedValueCollection& _rAdditionalArguments )
+{
+ OSL_PRECOND( getContainer(), "OApplicationController::openElementWithArguments: no view!" );
+ if ( !getContainer() )
+ return nullptr;
+
+ Reference< XComponent > xRet;
+ if ( _eOpenMode == E_OPEN_DESIGN )
+ {
+ // https://bz.apache.org/ooo/show_bug.cgi?id=30382
+ getContainer()->showPreview(nullptr);
+ }
+
+ bool isStandaloneDocument = false;
+ switch ( _eType )
+ {
+ case E_REPORT:
+ if ( _eOpenMode != E_OPEN_DESIGN )
+ {
+ // reports which are opened in a mode other than design are no sub components of our application
+ // component, but standalone documents.
+ isStandaloneDocument = true;
+ }
+ [[fallthrough]];
+ case E_FORM:
+ {
+ if ( isStandaloneDocument || !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) )
+ {
+ std::unique_ptr< OLinkedDocumentsAccess > aHelper = getDocumentsAccess( _eType );
+ if ( !aHelper->isConnected() )
+ break;
+
+ Reference< XComponent > xDefinition;
+ xRet = aHelper->open( _sName, xDefinition, _eOpenMode, _rAdditionalArguments );
+
+ if ( !isStandaloneDocument )
+ onDocumentOpened( _sName, _eType, _eOpenMode, xRet, xDefinition );
+ }
+ }
+ break;
+
+ case E_QUERY:
+ case E_TABLE:
+ {
+ if ( !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) )
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( !xConnection.is() )
+ break;
+
+ std::unique_ptr< DatabaseObjectView > pDesigner;
+ ::comphelper::NamedValueCollection aArguments( _rAdditionalArguments );
+
+ Any aDataSource;
+ if ( _eOpenMode == E_OPEN_DESIGN )
+ {
+ bool bAddViewTypeArg = false;
+
+ if ( _eType == E_TABLE )
+ {
+ if ( impl_isAlterableView_nothrow( _sName ) )
+ {
+ pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), true ) );
+ bAddViewTypeArg = true;
+ }
+ else
+ {
+ pDesigner.reset( new TableDesigner( getORB(), this, m_aCurrentFrame.getFrame() ) );
+ }
+ }
+ else if ( _eType == E_QUERY )
+ {
+ pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), false ) );
+ bAddViewTypeArg = true;
+ }
+ aDataSource <<= m_xDataSource;
+
+ if ( bAddViewTypeArg )
+ {
+ const bool bQueryGraphicalMode =( _nInstigatorCommand != SID_DB_APP_EDIT_SQL_VIEW );
+ aArguments.put( PROPERTY_GRAPHICAL_DESIGN, bQueryGraphicalMode );
+ }
+
+ }
+ else
+ {
+ pDesigner.reset( new ResultSetBrowser( getORB(), this, m_aCurrentFrame.getFrame(), _eType == E_TABLE ) );
+
+ if ( !aArguments.has( PROPERTY_SHOWMENU ) )
+ aArguments.put( PROPERTY_SHOWMENU, Any( true ) );
+
+ aDataSource <<= getDatabaseName();
+ }
+
+ xRet.set( pDesigner->openExisting( aDataSource, _sName, aArguments ) );
+ onDocumentOpened( _sName, _eType, _eOpenMode, xRet, nullptr );
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "OApplicationController::openElement: illegal object type!" );
+ break;
+ }
+ return xRet;
+}
+
+IMPL_LINK( OApplicationController, OnSelectContainer, void*, _pType, void )
+{
+ ElementType eType = static_cast<ElementType>(reinterpret_cast< sal_IntPtr >( _pType ));
+ if (getContainer())
+ getContainer()->selectContainer(eType);
+}
+
+IMPL_LINK( OApplicationController, OnCreateWithPilot, void*, _pType, void )
+{
+ ElementType eType = static_cast<ElementType>(reinterpret_cast< sal_IntPtr >( _pType ));
+ newElementWithPilot( eType );
+}
+
+void OApplicationController::newElementWithPilot( ElementType _eType )
+{
+ utl::CloseVeto aKeepDoc( getFrame() );
+ // prevent the document being closed while the wizard is open
+
+ OSL_ENSURE( getContainer(), "OApplicationController::newElementWithPilot: without a view?" );
+
+ switch ( _eType )
+ {
+ case E_REPORT:
+ case E_FORM:
+ {
+ std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess(_eType);
+ if ( aHelper->isConnected() )
+ {
+ sal_Int32 nCommandType = -1;
+ const OUString sCurrentSelected( getCurrentlySelectedName( nCommandType ) );
+ if ( E_REPORT == _eType )
+ aHelper->newReportWithPilot( nCommandType, sCurrentSelected );
+ else
+ aHelper->newFormWithPilot( nCommandType, sCurrentSelected );
+ }
+ }
+ break;
+ case E_QUERY:
+ case E_TABLE:
+ {
+ std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess(_eType);
+ if ( aHelper->isConnected() )
+ {
+ if ( E_QUERY == _eType )
+ aHelper->newQueryWithPilot();
+ else
+ aHelper->newTableWithPilot();
+ }
+ }
+ break;
+ case E_NONE:
+ break;
+ }
+
+ // no need for onDocumentOpened, the table wizard opens the created table by using
+ // XDatabaseDocumentUI::loadComponent method.
+}
+
+Reference< XComponent > OApplicationController::newElement( ElementType _eType, const ::comphelper::NamedValueCollection& i_rAdditionalArguments,
+ Reference< XComponent >& o_rDocumentDefinition )
+{
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+
+ Reference< XComponent > xComponent;
+ o_rDocumentDefinition.clear();
+
+ switch ( _eType )
+ {
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess( _eType );
+ if ( !aHelper->isConnected() )
+ break;
+
+ xComponent = aHelper->newDocument( _eType == E_FORM ? ID_FORM_NEW_TEXT : ID_REPORT_NEW_TEXT, i_rAdditionalArguments, o_rDocumentDefinition );
+ }
+ break;
+
+ case E_QUERY:
+ case E_TABLE:
+ {
+ std::unique_ptr< DatabaseObjectView > pDesigner;
+ SharedConnection xConnection( ensureConnection() );
+ if ( !xConnection.is() )
+ break;
+
+ if ( _eType == E_TABLE )
+ {
+ pDesigner.reset( new TableDesigner( getORB(), this, getFrame() ) );
+ }
+ else if ( _eType == E_QUERY )
+ {
+ pDesigner.reset( new QueryDesigner( getORB(), this, getFrame(), false ) );
+ }
+
+ Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ xComponent = pDesigner->createNew( xDataSource, i_rAdditionalArguments );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "OApplicationController::newElement: illegal type!" );
+ break;
+ }
+
+ if ( xComponent.is() )
+ onDocumentOpened( OUString(), _eType, E_OPEN_DESIGN, xComponent, o_rDocumentDefinition );
+
+ return xComponent;
+}
+
+void OApplicationController::addContainerListener(const Reference<XNameAccess>& _xCollection)
+{
+ try
+ {
+ Reference< XContainer > xCont(_xCollection, UNO_QUERY);
+ if ( xCont.is() )
+ {
+ // add as listener to get notified if elements are inserted or removed
+ TContainerVector::const_iterator aFind = std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xCont);
+ if ( aFind == m_aCurrentContainers.end() )
+ {
+ xCont->addContainerListener(this);
+ m_aCurrentContainers.push_back(xCont);
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::renameEntry()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+
+ Reference< XNameAccess > xContainer = getElements(getContainer()->getElementType());
+ OSL_ENSURE(aList.size() == 1,"Invalid rename call here. More than one element!");
+ if ( aList.empty() )
+ return;
+
+ try
+ {
+ if ( xContainer.is() )
+ {
+ std::unique_ptr< IObjectNameCheck > pNameChecker;
+ std::unique_ptr<OSaveAsDlg> xDialog;
+
+ Reference<XRename> xRename;
+ const ElementType eType = getContainer()->getElementType();
+ switch( eType )
+ {
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference<XHierarchicalNameContainer> xHNames(xContainer, UNO_QUERY);
+ if ( xHNames.is() )
+ {
+ OUString sLabel;
+ if ( eType == E_FORM )
+ sLabel = DBA_RES(STR_FRM_LABEL);
+ else
+ sLabel = DBA_RES(STR_RPT_LABEL);
+
+ OUString sName = *aList.begin();
+ if ( xHNames->hasByHierarchicalName(sName) )
+ {
+ xRename.set(xHNames->getByHierarchicalName(sName),UNO_QUERY);
+ Reference<XChild> xChild(xRename,UNO_QUERY);
+ if ( xChild.is() )
+ {
+ Reference<XHierarchicalNameContainer> xParent(xChild->getParent(),UNO_QUERY);
+ if ( xParent.is() )
+ {
+ xHNames = xParent;
+ Reference<XPropertySet>(xRename,UNO_QUERY_THROW)->getPropertyValue(PROPERTY_NAME) >>= sName;
+ }
+ }
+ pNameChecker.reset( new HierarchicalNameCheck( xHNames, OUString() ) );
+ xDialog.reset(new OSaveAsDlg(
+ getFrameWeld(), getORB(), sName, sLabel, *pNameChecker, SADFlags::TitleRename));
+ }
+ }
+ }
+ break;
+ case E_TABLE:
+ ensureConnection();
+ if ( !getConnection().is() )
+ break;
+ [[fallthrough]];
+ case E_QUERY:
+ if ( xContainer->hasByName(*aList.begin()) )
+ {
+ xRename.set(xContainer->getByName(*aList.begin()),UNO_QUERY);
+ sal_Int32 nCommandType = eType == E_QUERY ? CommandType::QUERY : CommandType::TABLE;
+
+ ensureConnection();
+ pNameChecker.reset( new DynamicTableOrQueryNameCheck( getConnection(), nCommandType ) );
+ xDialog.reset(new OSaveAsDlg(getFrameWeld(), nCommandType, getORB(), getConnection(),
+ *aList.begin(), *pNameChecker, SADFlags::TitleRename));
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (xRename.is() && xDialog)
+ {
+
+ bool bTryAgain = true;
+ while( bTryAgain )
+ {
+ if (xDialog->run() == RET_OK)
+ {
+ try
+ {
+ OUString sNewName;
+ if ( eType == E_TABLE )
+ {
+ OUString sName = xDialog->getName();
+ OUString sCatalog = xDialog->getCatalog();
+ OUString sSchema = xDialog->getSchema();
+
+ sNewName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sName, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ else
+ sNewName = xDialog->getName();
+
+ OUString sOldName = *aList.begin();
+ if ( eType == E_FORM || eType == E_REPORT )
+ {
+ Reference<XContent> xContent(xRename,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ sOldName = xContent->getIdentifier()->getContentIdentifier();
+ }
+ }
+
+ xRename->rename(sNewName);
+
+ if ( eType == E_TABLE )
+ {
+ Reference<XPropertySet> xProp(xRename,UNO_QUERY);
+ sNewName = ::dbaui::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InDataManipulation, false );
+ }
+ getContainer()->elementReplaced( eType , sOldName, sNewName );
+
+ bTryAgain = false;
+ }
+ catch(const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+
+ }
+ catch(const ElementExistException& e)
+ {
+ OUString sMsg(DBA_RES(STR_NAME_ALREADY_EXISTS));
+ showError(SQLExceptionInfo(SQLException(sMsg.replaceAll("#", e.Message), e.Context, "S1000", 0, Any())));
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ else
+ bTryAgain = false;
+ }
+ }
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::onSelectionChanged()
+{
+ InvalidateAll();
+
+ SelectionGuard aSelGuard( *m_pSelectionNotifier );
+
+ OApplicationView* pView = getContainer();
+ if ( !pView )
+ return;
+
+ if ( pView->getSelectionCount() == 1 )
+ {
+ const ElementType eType = pView->getElementType();
+ if ( pView->isALeafSelected() )
+ {
+ const OUString sName = pView->getQualifiedName( nullptr /* means 'first selected' */ );
+ showPreviewFor( eType, sName );
+ }
+ }
+}
+
+void OApplicationController::showPreviewFor(const ElementType _eType,const OUString& _sName)
+{
+ if ( m_ePreviewMode == E_PREVIEWNONE )
+ return;
+
+ OApplicationView* pView = getContainer();
+ if ( !pView )
+ return;
+
+ try
+ {
+ switch( _eType )
+ {
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference< XHierarchicalNameAccess > xContainer( getElements( _eType ), UNO_QUERY_THROW );
+ Reference< XContent> xContent( xContainer->getByHierarchicalName( _sName ), UNO_QUERY_THROW );
+ pView->showPreview( xContent );
+ }
+ break;
+
+ case E_TABLE:
+ case E_QUERY:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ pView->showPreview( getDatabaseName(), xConnection, _sName, _eType == E_TABLE );
+ }
+ return;
+
+ default:
+ OSL_FAIL( "OApplicationController::showPreviewFor: unexpected element type!" );
+ break;
+ }
+ }
+ catch( const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+IMPL_LINK_NOARG(OApplicationController, OnClipboardChanged, TransferableDataHelper*, void)
+{
+ OnInvalidateClipboard();
+}
+
+void OApplicationController::OnInvalidateClipboard()
+{
+ InvalidateFeature(ID_BROWSER_CUT);
+ InvalidateFeature(ID_BROWSER_COPY);
+ InvalidateFeature(ID_BROWSER_PASTE);
+ InvalidateFeature(SID_DB_APP_PASTE_SPECIAL);
+}
+
+void OApplicationController::onCopyEntry()
+{
+ Execute(ID_BROWSER_COPY,Sequence<PropertyValue>());
+}
+
+void OApplicationController::onPasteEntry()
+{
+ Execute(ID_BROWSER_PASTE,Sequence<PropertyValue>());
+}
+
+void OApplicationController::onDeleteEntry()
+{
+ ElementType eType = getContainer()->getElementType();
+ sal_uInt16 nId = 0;
+ switch(eType)
+ {
+ case E_TABLE:
+ nId = SID_DB_APP_TABLE_DELETE;
+ break;
+ case E_QUERY:
+ nId = SID_DB_APP_QUERY_DELETE;
+ break;
+ case E_FORM:
+ nId = SID_DB_APP_FORM_DELETE;
+ break;
+ case E_REPORT:
+ nId = SID_DB_APP_REPORT_DELETE;
+ break;
+ default:
+ OSL_FAIL("Invalid ElementType!");
+ break;
+ }
+ executeChecked(nId,Sequence<PropertyValue>());
+}
+
+OUString OApplicationController::getContextMenuResourceName() const
+{
+ return "edit";
+}
+
+IController& OApplicationController::getCommandController()
+{
+ return *this;
+}
+
+::comphelper::OInterfaceContainerHelper2* OApplicationController::getContextMenuInterceptors()
+{
+ return &m_aContextMenuInterceptors;
+}
+
+Any OApplicationController::getCurrentSelection(weld::TreeView& rControl) const
+{
+ Sequence< NamedDatabaseObject > aSelection;
+ getContainer()->describeCurrentSelectionForControl(rControl, aSelection);
+ return Any( aSelection );
+}
+
+vcl::Window* OApplicationController::getMenuParent() const
+{
+ return getContainer()->getMenuParent();
+}
+
+void OApplicationController::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ getContainer()->adjustMenuPosition(rControl, rPos);
+}
+
+bool OApplicationController::requestQuickHelp(const void* /*pUserData*/, OUString& /*rText*/) const
+{
+ return false;
+}
+
+bool OApplicationController::requestDrag(const weld::TreeIter& /*rEntry*/)
+{
+ bool bSuccess = false;
+
+ OApplicationView* pContainer = getContainer();
+ if (pContainer && pContainer->getSelectionCount())
+ {
+ try
+ {
+ if (getContainer()->getDetailView())
+ {
+ TreeListBox* pTreeListBox = getContainer()->getDetailView()->getTreeWindow();
+
+ ElementType eType = getContainer()->getElementType();
+ if (eType == E_TABLE || eType == E_QUERY)
+ {
+ ODataClipboard& rExchange = static_cast<ODataClipboard&>(pTreeListBox->GetDataTransfer());
+ bSuccess = copySQLObject(rExchange);
+ }
+ else
+ {
+ svx::OComponentTransferable& rExchange = static_cast<svx::OComponentTransferable&>(pTreeListBox->GetDataTransfer());
+ bSuccess = copyDocObject(rExchange);
+ }
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ return bSuccess;
+}
+
+sal_Int8 OApplicationController::queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors )
+{
+ sal_Int8 nActionAskedFor = _rEvt.mnAction;
+ // check if we're a table or query container
+ OApplicationView* pView = getContainer();
+ if ( !pView || isDataSourceReadOnly() )
+ return DND_ACTION_NONE;
+
+ ElementType eType = pView->getElementType();
+ if ( eType == E_NONE || (eType == E_TABLE && isConnectionReadOnly()) )
+ return DND_ACTION_NONE;
+
+ // check for the concrete type
+ if(std::any_of(_rFlavors.begin(),_rFlavors.end(),TAppSupportedSotFunctor(eType)))
+ return DND_ACTION_COPY;
+
+ if ( eType != E_FORM && eType != E_REPORT )
+ return DND_ACTION_NONE;
+
+ sal_Int8 nAction = OComponentTransferable::canExtractComponentDescriptor(_rFlavors,eType == E_FORM) ? DND_ACTION_COPY : DND_ACTION_NONE;
+ if ( nAction == DND_ACTION_NONE )
+ return DND_ACTION_NONE;
+
+ auto xHitEntry = pView->getEntry(_rEvt.maPosPixel);
+ if (xHitEntry)
+ {
+ OUString sName = pView->getQualifiedName(xHitEntry.get());
+ if ( !sName.isEmpty() )
+ {
+ Reference< XHierarchicalNameAccess > xContainer(getElements(pView->getElementType()),UNO_QUERY);
+ if ( xContainer.is() && xContainer->hasByHierarchicalName(sName) )
+ {
+ Reference< XHierarchicalNameAccess > xHitObject(xContainer->getByHierarchicalName(sName),UNO_QUERY);
+ if ( xHitObject.is() )
+ nAction = nActionAskedFor & DND_ACTION_COPYMOVE;
+ }
+ else
+ nAction = DND_ACTION_NONE;
+ }
+ }
+ return nAction;
+}
+
+sal_Int8 OApplicationController::executeDrop( const ExecuteDropEvent& _rEvt )
+{
+ OApplicationView* pView = getContainer();
+ if ( !pView || pView->getElementType() == E_NONE )
+ {
+ OSL_FAIL("OApplicationController::executeDrop: what the hell did queryDrop do?");
+ // queryDrop should not have allowed us to reach this situation...
+ return DND_ACTION_NONE;
+ }
+
+ // a TransferableDataHelper for accessing the dropped data
+ TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable);
+
+ // reset the data of the previous async drop (if any)
+ if ( m_nAsyncDrop )
+ Application::RemoveUserEvent(m_nAsyncDrop);
+
+ m_nAsyncDrop = nullptr;
+ m_aAsyncDrop.aDroppedData.clear();
+ m_aAsyncDrop.nType = pView->getElementType();
+ m_aAsyncDrop.nAction = _rEvt.mnAction;
+ m_aAsyncDrop.bError = false;
+ m_aAsyncDrop.bHtml = false;
+ m_aAsyncDrop.aUrl.clear();
+
+ // loop through the available formats and see what we can do...
+ // first we have to check if it is our own format, if not we have to copy the stream :-(
+ if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(aDroppedData.GetDataFlavorExVector()) )
+ {
+ m_aAsyncDrop.aDroppedData = ODataAccessObjectTransferable::extractObjectDescriptor(aDroppedData);
+
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop));
+ return DND_ACTION_COPY;
+ }
+ else if ( OComponentTransferable::canExtractComponentDescriptor(aDroppedData.GetDataFlavorExVector(),m_aAsyncDrop.nType == E_FORM) )
+ {
+ m_aAsyncDrop.aDroppedData = OComponentTransferable::extractComponentDescriptor(aDroppedData);
+ auto xHitEntry = pView->getEntry(_rEvt.maPosPixel);
+ if ( xHitEntry )
+ m_aAsyncDrop.aUrl = pView->getQualifiedName(xHitEntry.get());
+
+ sal_Int8 nAction = _rEvt.mnAction;
+ Reference<XContent> xContent;
+ m_aAsyncDrop.aDroppedData[DataAccessDescriptorProperty::Component] >>= xContent;
+ if ( xContent.is() )
+ {
+ OUString sName = xContent->getIdentifier()->getContentIdentifier();
+ sName = sName.copy(sName.indexOf('/') + 1);
+ if ( m_aAsyncDrop.aUrl.getLength() >= sName.getLength() && m_aAsyncDrop.aUrl.startsWith(sName) )
+ {
+ m_aAsyncDrop.aDroppedData.clear();
+ return DND_ACTION_NONE;
+ }
+
+ // check if move is allowed, if another object with the same name exists only copy is allowed
+ Reference< XHierarchicalNameAccess > xContainer(getElements(m_aAsyncDrop.nType),UNO_QUERY);
+ Reference<XNameAccess> xNameAccess(xContainer,UNO_QUERY);
+
+ if ( !m_aAsyncDrop.aUrl.isEmpty() && xContainer.is() && xContainer->hasByHierarchicalName(m_aAsyncDrop.aUrl) )
+ xNameAccess.set(xContainer->getByHierarchicalName(m_aAsyncDrop.aUrl),UNO_QUERY);
+
+ if ( xNameAccess.is() )
+ {
+ Reference<XPropertySet> xProp(xContent,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
+ if ( xNameAccess.is() && xNameAccess->hasByName(sName) )
+ nAction &= ~DND_ACTION_MOVE;
+ }
+ else
+ nAction &= ~DND_ACTION_MOVE;
+ }
+ }
+ if ( nAction != DND_ACTION_NONE )
+ {
+ m_aAsyncDrop.nAction = nAction;
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop));
+ }
+ else
+ m_aAsyncDrop.aDroppedData.clear();
+ return nAction;
+ }
+ else
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() && m_aTableCopyHelper.copyTagTable( aDroppedData, m_aAsyncDrop, xConnection ) )
+ {
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop));
+ return DND_ACTION_COPY;
+ }
+ }
+
+ return DND_ACTION_NONE;
+}
+
+Reference< XModel > SAL_CALL OApplicationController::getModel()
+{
+ return m_xModel;
+}
+
+void OApplicationController::onAttachedFrame()
+{
+ sal_Int32 nConnectedControllers( 0 );
+ try
+ {
+ Reference< XModel2 > xModel( m_xModel, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumControllers( xModel->getControllers(), UNO_SET_THROW );
+ while ( xEnumControllers->hasMoreElements() )
+ {
+ Reference< XController > xController( xEnumControllers->nextElement(), UNO_QUERY_THROW );
+ ++nConnectedControllers;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( nConnectedControllers > 1 )
+ { // we are not the first connected controller, there were already others
+ return;
+ }
+
+ OnFirstControllerConnected();
+}
+
+void OApplicationController::OnFirstControllerConnected()
+{
+ if ( !m_xModel.is() )
+ {
+ OSL_FAIL( "OApplicationController::OnFirstControllerConnected: too late!" );
+ }
+
+ // if we have forms or reports which contain macros/scripts, then show a warning
+ // which suggests the user to migrate them to the database document
+ Reference< XEmbeddedScripts > xDocumentScripts( m_xModel, UNO_QUERY );
+ if ( xDocumentScripts.is() )
+ {
+ // no need to show this warning, obviously the document supports embedding scripts
+ // into itself, so there are no "old-style" forms/reports which have macros/scripts
+ // themselves
+ return;
+ }
+
+ try
+ {
+ // If the migration just happened, but was not successful, the document is reloaded.
+ // In this case, we should not show the warning, again.
+ if ( ::comphelper::NamedValueCollection::getOrDefault( m_xModel->getArgs(), u"SuppressMigrationWarning", false ) )
+ return;
+
+ // also, if the document is read-only, then no migration is possible, and the
+ // respective menu entry is hidden. So, don't show the warning in this case, too.
+ if ( Reference< XStorable >( m_xModel, UNO_QUERY_THROW )->isReadonly() )
+ return;
+
+ SQLWarning aWarning;
+ aWarning.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS);
+ SQLException aDetail;
+ aDetail.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS_DETAIL);
+ aWarning.NextException <<= aDetail;
+
+ Reference< XExecutableDialog > xDialog = ErrorMessageDialog::create( getORB(), "", nullptr, Any( aWarning ) );
+ xDialog->execute();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OApplicationController::attachFrame( const Reference< XFrame > & i_rxFrame )
+{
+ SolarMutexGuard aSolarGuard; // avoid deadlock in XModel calls
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ OGenericUnoController::attachFrame( i_rxFrame );
+ if ( getFrame().is() )
+ onAttachedFrame();
+}
+
+sal_Bool SAL_CALL OApplicationController::attachModel(const Reference< XModel > & _rxModel)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ const Reference< XOfficeDatabaseDocument > xOfficeDoc( _rxModel, UNO_QUERY );
+ const Reference< XModifiable > xDocModify( _rxModel, UNO_QUERY );
+ if ( ( !xOfficeDoc.is() || !xDocModify.is() ) && _rxModel.is() )
+ {
+ OSL_FAIL( "OApplicationController::attachModel: invalid model!" );
+ return false;
+ }
+
+ if ( m_xModel.is() && ( m_xModel != _rxModel ) && ( _rxModel.is() ) )
+ {
+ OSL_ENSURE( false, "OApplicationController::attachModel: missing implementation: setting a new model while we have another one!" );
+ // we'd need to completely update our view here, close sub components, and the like
+ return false;
+ }
+
+ const OUString aPropertyNames[] =
+ {
+ OUString(PROPERTY_URL), OUString(PROPERTY_USER)
+ };
+
+ // disconnect from old model
+ try
+ {
+ if ( m_xDataSource.is() )
+ {
+ for (const auto & aPropertyName : aPropertyNames)
+ {
+ m_xDataSource->removePropertyChangeListener( aPropertyName, this );
+ }
+ }
+
+ Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ xBroadcaster->removeModifyListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xModel = _rxModel;
+ m_xDataSource.set( xOfficeDoc.is() ? xOfficeDoc->getDataSource() : Reference< XDataSource >(), UNO_QUERY );
+
+ // connect to new model
+ try
+ {
+ if ( m_xDataSource.is() )
+ {
+ for (const auto & aPropertyName : aPropertyNames)
+ {
+ m_xDataSource->addPropertyChangeListener( aPropertyName, this );
+ }
+ }
+
+ Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY_THROW );
+ xBroadcaster->addModifyListener( this );
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // initial preview mode
+ if ( !m_xDataSource )
+ return true;
+
+ try
+ {
+ // to get the 'modified' for the data source
+ ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) );
+ if ( aLayoutInfo.has( INFO_PREVIEW ) )
+ {
+ const sal_Int32 nPreviewMode( aLayoutInfo.getOrDefault( INFO_PREVIEW, sal_Int32(0) ) );
+ m_ePreviewMode = static_cast< PreviewMode >( nPreviewMode );
+ if ( getView() )
+ getContainer()->switchPreview( m_ePreviewMode );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return true;
+}
+
+void OApplicationController::containerFound( const Reference< XContainer >& _xContainer)
+{
+ try
+ {
+ if ( _xContainer.is() )
+ {
+ m_aCurrentContainers.push_back(_xContainer);
+ _xContainer->addContainerListener(this);
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OUString OApplicationController::getCurrentlySelectedName(sal_Int32& _rnCommandType) const
+{
+ _rnCommandType = ( (getContainer()->getElementType() == E_QUERY)
+ ? CommandType::QUERY : ( (getContainer()->getElementType() == E_TABLE) ? CommandType::TABLE : -1 ));
+
+ OUString sName;
+ if ( _rnCommandType != -1 )
+ {
+ try
+ {
+ sName = getContainer()->getQualifiedName( nullptr );
+ OSL_ENSURE( !sName.isEmpty(), "OApplicationController::getCurrentlySelectedName: no name given!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ return sName;
+}
+
+void SAL_CALL OApplicationController::addSelectionChangeListener( const Reference< view::XSelectionChangeListener >& Listener )
+{
+ m_pSelectionNotifier->addListener( Listener );
+}
+
+void SAL_CALL OApplicationController::removeSelectionChangeListener( const Reference< view::XSelectionChangeListener >& Listener )
+{
+ m_pSelectionNotifier->removeListener( Listener );
+}
+
+sal_Bool SAL_CALL OApplicationController::select( const Any& _aSelection )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ Sequence< OUString> aSelection;
+ if ( !_aSelection.hasValue() || !getView() )
+ {
+ getContainer()->selectElements(aSelection);
+ return true;
+ }
+
+ // BEGIN compatibility
+ Sequence< NamedValue > aCurrentSelection;
+ if ( (_aSelection >>= aCurrentSelection) && aCurrentSelection.hasElements() )
+ {
+ ElementType eType = E_NONE;
+ const NamedValue* pIter = aCurrentSelection.getConstArray();
+ const NamedValue* pEnd = pIter + aCurrentSelection.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( pIter->Name == "Type" )
+ {
+ sal_Int32 nType = 0;
+ pIter->Value >>= nType;
+ if ( nType < DatabaseObject::TABLE || nType > DatabaseObject::REPORT )
+ throw IllegalArgumentException();
+ eType = static_cast< ElementType >( nType );
+ }
+ else if ( pIter->Name == "Selection" )
+ pIter->Value >>= aSelection;
+ }
+
+ m_aSelectContainerEvent.CancelCall(); // just in case the async select request was running
+ getContainer()->selectContainer(eType);
+ getContainer()->selectElements(aSelection);
+ return true;
+ }
+ // END compatibility
+
+ Sequence< NamedDatabaseObject > aSelectedObjects;
+ if ( !( _aSelection >>= aSelectedObjects ) )
+ {
+ aSelectedObjects.realloc( 1 );
+ if ( !( _aSelection >>= aSelectedObjects.getArray()[0] ) )
+ throw IllegalArgumentException();
+ }
+
+ SelectionByElementType aSelectedElements;
+ ElementType eSelectedCategory = E_NONE;
+ for ( const NamedDatabaseObject* pObject = aSelectedObjects.getConstArray();
+ pObject != aSelectedObjects.getConstArray() + aSelectedObjects.getLength();
+ ++pObject
+ )
+ {
+ switch ( pObject->Type )
+ {
+ case DatabaseObject::TABLE:
+ case DatabaseObjectContainer::SCHEMA:
+ case DatabaseObjectContainer::CATALOG:
+ aSelectedElements[ E_TABLE ].push_back( pObject->Name );
+ break;
+ case DatabaseObject::QUERY:
+ aSelectedElements[ E_QUERY ].push_back( pObject->Name );
+ break;
+ case DatabaseObject::FORM:
+ case DatabaseObjectContainer::FORMS_FOLDER:
+ aSelectedElements[ E_FORM ].push_back( pObject->Name );
+ break;
+ case DatabaseObject::REPORT:
+ case DatabaseObjectContainer::REPORTS_FOLDER:
+ aSelectedElements[ E_REPORT ].push_back( pObject->Name );
+ break;
+ case DatabaseObjectContainer::TABLES:
+ case DatabaseObjectContainer::QUERIES:
+ case DatabaseObjectContainer::FORMS:
+ case DatabaseObjectContainer::REPORTS:
+ if ( eSelectedCategory != E_NONE )
+ throw IllegalArgumentException(
+ DBA_RES(RID_STR_NO_DIFF_CAT),
+ *this, sal_Int16( pObject - aSelectedObjects.getConstArray() ) );
+ eSelectedCategory =
+ ( pObject->Type == DatabaseObjectContainer::TABLES ) ? E_TABLE
+ : ( pObject->Type == DatabaseObjectContainer::QUERIES ) ? E_QUERY
+ : ( pObject->Type == DatabaseObjectContainer::FORMS ) ? E_FORM
+ : ( pObject->Type == DatabaseObjectContainer::REPORTS ) ? E_REPORT
+ : E_NONE;
+ break;
+
+ default:
+ case DatabaseObjectContainer::DATA_SOURCE:
+ {
+ OUString sMessage(
+ DBA_RES(RID_STR_UNSUPPORTED_OBJECT_TYPE).
+ replaceFirst("$type$", OUString::number(pObject->Type)));
+ throw IllegalArgumentException(sMessage, *this, sal_Int16( pObject - aSelectedObjects.getConstArray() ));
+ }
+ }
+ }
+ for (auto const& selectedElement : aSelectedElements)
+ {
+ if ( selectedElement.first == m_eCurrentType )
+ {
+ getContainer()->selectElements( comphelper::containerToSequence(selectedElement.second) );
+ }
+ else
+ {
+ m_aPendingSelection[ selectedElement.first ] = selectedElement.second;
+ }
+ }
+
+ m_aSelectContainerEvent.CancelCall(); // just in case the async select request was running
+ getContainer()->selectContainer( eSelectedCategory );
+
+ return true;
+}
+
+Any SAL_CALL OApplicationController::getSelection( )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Sequence< NamedDatabaseObject > aCurrentSelection;
+ const ElementType eType( getContainer()->getElementType() );
+ if ( eType != E_NONE )
+ {
+ getContainer()->describeCurrentSelectionForType( eType, aCurrentSelection );
+ if ( !aCurrentSelection.hasElements() )
+ { // if no objects are selected, add an entry to the sequence which describes the overall category
+ // which is selected currently
+ aCurrentSelection.realloc(1);
+ auto pCurrentSelection = aCurrentSelection.getArray();
+ pCurrentSelection[0].Name = getDatabaseName();
+ switch ( eType )
+ {
+ case E_TABLE: pCurrentSelection[0].Type = DatabaseObjectContainer::TABLES; break;
+ case E_QUERY: pCurrentSelection[0].Type = DatabaseObjectContainer::QUERIES; break;
+ case E_FORM: pCurrentSelection[0].Type = DatabaseObjectContainer::FORMS; break;
+ case E_REPORT: pCurrentSelection[0].Type = DatabaseObjectContainer::REPORTS; break;
+ default:
+ OSL_FAIL( "OApplicationController::getSelection: unexpected current element type!" );
+ break;
+ }
+ }
+ }
+ return Any( aCurrentSelection );
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppController.hxx b/dbaccess/source/ui/app/AppController.hxx
new file mode 100644
index 000000000..b7579c0cf
--- /dev/null
+++ b/dbaccess/source/ui/app/AppController.hxx
@@ -0,0 +1,540 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <AppElementType.hxx>
+#include <callbacks.hxx>
+#include <commontypes.hxx>
+#include <dsntypes.hxx>
+#include <dbaccess/genericcontroller.hxx>
+#include <linkeddocuments.hxx>
+#include <TableCopyHelper.hxx>
+
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/ui/XContextMenuInterception.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase5.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <vcl/transfer.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+
+#include <memory>
+
+class TransferableHelper;
+class TransferableClipboardListener;
+
+namespace com::sun::star {
+ namespace container {
+ class XNameContainer;
+ class XContainer;
+ }
+ namespace ucb {
+ class XContent;
+ }
+}
+
+namespace svx
+{
+ class OComponentTransferable;
+}
+
+namespace weld
+{
+ class TreeView;
+}
+
+namespace dbaui
+{
+ class ODataClipboard;
+ class TreeListBox;
+ class SubComponentManager;
+ class OApplicationController;
+ class OApplicationView;
+ class OLinkedDocumentsAccess;
+ class SelectionNotifier;
+
+ typedef ::cppu::ImplHelper5 < css::container::XContainerListener
+ , css::beans::XPropertyChangeListener
+ , css::sdb::application::XDatabaseDocumentUI
+ , css::ui::XContextMenuInterception
+ , css::view::XSelectionSupplier
+ > OApplicationController_Base;
+
+
+ class OApplicationController
+ :public OGenericUnoController
+ ,public OApplicationController_Base
+ ,public IControlActionListener
+ ,public IContextMenuProvider
+ {
+ public:
+ typedef std::vector< css::uno::Reference< css::container::XContainer > > TContainerVector;
+
+ private:
+
+ OTableCopyHelper::DropDescriptor m_aAsyncDrop;
+
+ SharedConnection m_xDataSourceConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData >
+ m_xMetaData;
+
+ TransferableDataHelper m_aSystemClipboard; // content of the clipboard
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xDataSource;
+ css::uno::Reference< css::frame::XModel >
+ m_xModel;
+ ::comphelper::OInterfaceContainerHelper2
+ m_aContextMenuInterceptors;
+
+ TContainerVector m_aCurrentContainers; // the containers where we are listener on
+ ::rtl::Reference< SubComponentManager >
+ m_pSubComponentManager;
+ ::dbaccess::ODsnTypeCollection
+ m_aTypeCollection;
+ OTableCopyHelper m_aTableCopyHelper;
+ rtl::Reference<TransferableClipboardListener>
+ m_pClipboardNotifier; // notifier for changes in the clipboard
+ ImplSVEvent * m_nAsyncDrop;
+ OAsynchronousLink m_aSelectContainerEvent;
+ PreviewMode m_ePreviewMode; // the mode of the preview
+ ElementType m_eCurrentType;
+ bool m_bNeedToReconnect; // true when the settings of the data source were modified and the connection is no longer up to date
+ bool m_bSuspended; // is true when the controller was already suspended
+
+ std::unique_ptr< SelectionNotifier >
+ m_pSelectionNotifier;
+ typedef std::map< ElementType, std::vector< OUString > > SelectionByElementType;
+ SelectionByElementType m_aPendingSelection;
+
+ private:
+
+ OApplicationView* getContainer() const;
+
+ /** returns the database name
+ @return
+ the database name
+ */
+ OUString getDatabaseName() const;
+
+ /** returns the stripped database name.
+ @return
+ The stripped database name either the registered name or if it is a file url the last segment.
+ */
+ OUString getStrippedDatabaseName() const;
+
+ /** return the element type for given container
+ @param _xContainer The container where the element type has to be found
+ @return the element type corresponding to the given container
+ */
+ static ElementType getElementType(const css::uno::Reference< css::container::XContainer >& _xContainer);
+
+ /** opens a new sub frame with a table/query/form/report/view, passing additional arguments
+ */
+ css::uno::Reference< css::lang::XComponent > openElementWithArguments(
+ const OUString& _sName,
+ ElementType _eType,
+ ElementOpenMode _eOpenMode,
+ sal_uInt16 _nInstigatorCommand,
+ const ::comphelper::NamedValueCollection& _rAdditionalArguments
+ );
+
+ /** opens a new frame for creation or auto pilot
+ @param _eType
+ Defines the type to open
+ @param i_rAdditionalArguments
+ Additional arguments to pass when creating the component
+ */
+ css::uno::Reference< css::lang::XComponent >
+ newElement(
+ ElementType _eType,
+ const ::comphelper::NamedValueCollection& i_rAdditionalArguments,
+ css::uno::Reference< css::lang::XComponent >& o_rDocumentDefinition
+ );
+
+ /** creates a new database object, using an auto pilot
+ @param _eType
+ Defines the type of the object to create
+ @precond
+ Our mutex must not be locked.
+ @since #i39203#
+ */
+ void newElementWithPilot( ElementType _eType );
+
+ /** converts the query to a view
+ @param _sName
+ The name of the query.
+ */
+ void convertToView(const OUString& _sName);
+
+ /** checks if the connection for the selected data source is read only. If the connection doesn't exist, <TRUE/> will be returned.
+ @return
+ <TRUE/> if read only or doesn't exist, otherwise <FALSE/>
+ */
+ bool isConnectionReadOnly() const;
+
+ /// fills the list with the selected entries.
+ void getSelectionElementNames( std::vector< OUString>& _rNames ) const;
+
+ /// deletes the entries selected.
+ void deleteEntries();
+
+ /// renames the selected entry in the detail page
+ void renameEntry();
+
+ /** deletes queries, forms, or reports
+ @param _eType
+ the type of the objects
+ @param _rList
+ The names of the elements to delete
+ @param _bConfirm
+ determines whether the user must confirm the deletion
+ */
+ void deleteObjects( ElementType _eType,
+ const std::vector< OUString>& _rList,
+ bool _bConfirm );
+
+ /** deletes tables.
+ @param _rList
+ The list of tables.
+ */
+ void deleteTables(const std::vector< OUString>& _rList);
+
+ /// copies the current object into clipboard
+ rtl::Reference<TransferableHelper> copyObject();
+
+ /// fills rExchange with current object if it's a Table or Query
+ bool copySQLObject(ODataClipboard& rExchange);
+
+ /// fills rExchange with current object if it's a Form or Report
+ bool copyDocObject(svx::OComponentTransferable& rExchange);
+
+ /// returns the nameaccess
+ css::uno::Reference< css::container::XNameAccess > getElements(ElementType _eType);
+
+ /** returns the document access for the specific type
+ @param _eType
+ the type
+ @return std::unique_ptr<OLinkedDocumentsAccess>
+ */
+ std::unique_ptr<OLinkedDocumentsAccess> getDocumentsAccess(ElementType _eType);
+
+ /// returns the query definitions of the active data source.
+ css::uno::Reference< css::container::XNameContainer> getQueryDefinitions() const;
+
+ /** pastes a special format from the system clipboard to the currently selected object types
+ @param _nFormatId
+ The format to be copied.
+ */
+ void pasteFormat(SotClipboardFormatId _nFormatId);
+
+ /** pastes a query, form or report into the data source
+ @param _eType
+ The type of the object to paste.
+ @param _rPasteData
+ The data descriptor.
+ @param _sParentFolder
+ The name of the parent folder if it exists.
+ @param _bMove
+ if <TRUE/> the name of the content must be inserted without any change, otherwise not.
+ @return
+ <TRUE/> if the paste operations was successful, otherwise <FALSE/>.
+ */
+ bool paste( ElementType _eType, const svx::ODataAccessDescriptor& _rPasteData, const OUString& _sParentFolder = OUString(), bool _bMove = false);
+
+ /// returns the system clipboard.
+ const TransferableDataHelper& getViewClipboard() const { return m_aSystemClipboard; }
+
+ /// returns <TRUE/> if the clipboard supports a table format, otherwise <FALSE/>.
+ bool isTableFormat() const;
+
+ /** fills the vector with all supported formats
+ @param _eType
+ The type for which we need the formats
+ @param _rFormatIds
+ The vector to be filled up.
+ */
+ static void getSupportedFormats(ElementType _eType,std::vector<SotClipboardFormatId>& _rFormatIds);
+
+ /** adds a listener to the current name access.
+ @param _xCollection
+ The collection where we want to listen on.
+ */
+ void addContainerListener(const css::uno::Reference< css::container::XNameAccess>& _xCollection);
+
+ /** opens a uno dialog with the currently selected data source as initialize argument
+ @param _sServiceName
+ The service name of the dialog to be executed.
+ */
+ void openDialog(const OUString& _sServiceName);
+
+ /** when the settings of the data source changed,
+ it opens a dialog which ask to close all depending documents, then recreate the connection.
+ The SolarMutex has to be locked before calling this.
+ */
+ void askToReconnect();
+
+ /** remember a newly opened sub document for later access
+ */
+ void onDocumentOpened(
+ const OUString& _rName,
+ const sal_Int32 _nType,
+ const ElementOpenMode _eMode,
+ const css::uno::Reference< css::lang::XComponent >& _xDocument,
+ const css::uno::Reference< css::lang::XComponent >& _xDefinition
+ );
+
+ /** Inserts a new object into the hierarchy given be the type.
+ @param _eType
+ Where to insert the new item.
+ @param _sParentFolder
+ The name of the parent folder if it exists.
+ @param _xContent
+ The content to insert.
+ @param _bMove
+ if <TRUE/> the name of the content must be inserted without any change, otherwise not.
+ @return
+ <TRUE/> if the insert operations was successful, otherwise <FALSE/>.
+ */
+ bool insertHierarchyElement( ElementType _eType
+ ,const OUString& _sParentFolder
+ ,bool _bCollection = true
+ ,const css::uno::Reference< css::ucb::XContent>& _xContent = css::uno::Reference< css::ucb::XContent>()
+ ,bool _bMove = false);
+ /** checks if delete command or rename command is allowed
+ @param _eType
+ The element type.
+ @param _bDelete
+ If <TRUE> then the delete command should be checked.
+ @return
+ <TRUE> if the command is allowed
+ */
+ bool isRenameDeleteAllowed(ElementType _eType, bool _bDelete) const;
+ /** all selected entries will be opened, or edited, or converted to a view
+ @param _nId
+ The slot which should be executed.
+ @param _eOpenMode
+ Defines the mode of opening. @see ElementOpenMode
+ */
+ void doAction(sal_uInt16 _nId, ElementOpenMode _eOpenMode);
+
+ /** returns the currently selected table or query name.
+ *
+ * \return the name of the currently table or query. If the tables or query container is selected otherwise an empty string will be returned.
+ */
+ OUString getCurrentlySelectedName(sal_Int32& _rnCommandType) const;
+
+ /** shows the preview for the given entry
+ */
+ void showPreviewFor( const ElementType _eType,const OUString& _sName );
+
+ /** called we were attached to a frame
+
+ In particular, this is called *after* the controller has been announced to the model
+ (XModel::connectController)
+ */
+ void onAttachedFrame();
+
+ /// determines whether the given table name denotes a view which can be altered
+ bool impl_isAlterableView_nothrow( const OUString& _rTableOrViewName ) const;
+
+ /** verifies the object type denotes a valid DatabaseObject, and the object name denotes an existing
+ object of this type. Throws if not.
+ */
+ void impl_validateObjectTypeAndName_throw( const sal_Int32 _nObjectType, const ::std::optional< OUString >& i_rObjectName );
+
+ protected:
+ // initializing members
+
+ // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot.
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ // execute a feature
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ // OGenericUnoController
+ virtual void onLoadedMenu( const css::uno::Reference< css::frame::XLayoutManager >& _xLayoutManager ) override;
+
+ virtual css::uno::Reference< css::frame::XModel > getPrivateModel() const override
+ {
+ return m_xModel;
+ }
+
+ virtual ~OApplicationController() override;
+
+ public:
+ explicit OApplicationController(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // css::frame::XController
+ virtual void SAL_CALL attachFrame(const css::uno::Reference< css::frame::XFrame > & xFrame) override;
+ virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override;
+ virtual sal_Bool SAL_CALL attachModel(const css::uno::Reference< css::frame::XModel > & xModel) override;
+ virtual css::uno::Reference< css::frame::XModel > SAL_CALL getModel() override;
+
+ // css::container::XContainerListener
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& Event) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XDatabaseDocumentUI
+ virtual css::uno::Reference< css::sdbc::XDataSource > SAL_CALL getDataSource() override;
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL getApplicationMainWindow() override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getActiveConnection() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::lang::XComponent > > SAL_CALL getSubComponents() override;
+ virtual sal_Bool SAL_CALL isConnected( ) override;
+ // DO NOT CALL with getMutex() held!!
+ virtual void SAL_CALL connect( ) override;
+ virtual css::beans::Pair< ::sal_Int32, OUString > SAL_CALL identifySubComponent( const css::uno::Reference< css::lang::XComponent >& SubComponent ) override;
+ virtual sal_Bool SAL_CALL closeSubComponents( ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponent( ::sal_Int32 ObjectType, const OUString& ObjectName, sal_Bool ForEditing ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponentWithArguments( ::sal_Int32 ObjectType, const OUString& ObjectName, sal_Bool ForEditing, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL createComponent( ::sal_Int32 ObjectType, css::uno::Reference< css::lang::XComponent >& o_DocumentDefinition ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL createComponentWithArguments( ::sal_Int32 ObjectType, const css::uno::Sequence< css::beans::PropertyValue >& Arguments, css::uno::Reference< css::lang::XComponent >& o_DocumentDefinition ) override;
+
+ // XContextMenuInterception
+ virtual void SAL_CALL registerContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override;
+ virtual void SAL_CALL releaseContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override;
+
+ // XSelectionSupplier
+ virtual sal_Bool SAL_CALL select( const css::uno::Any& xSelection ) override;
+ virtual css::uno::Any SAL_CALL getSelection( ) override;
+ virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+
+ /** retrieves the current connection, creates it if necessary
+
+ If an error occurs, then this is either stored in the location pointed to by <arg>_pErrorInfo</arg>,
+ or, if <code>_pErrorInfo</code> is <NULL/>, then the error is displayed to the user.
+
+ DO NOT CALL with getMutex() held!!
+ */
+ const SharedConnection& ensureConnection( ::dbtools::SQLExceptionInfo* _pErrorInfo = nullptr );
+
+ /** retrieves the current connection
+ */
+ const SharedConnection& getConnection() const { return m_xDataSourceConnection; }
+
+ /// determines whether we're currently connected to the database
+ bool isConnected() const { return m_xDataSourceConnection.is(); }
+
+ /** refreshes the tables
+ */
+ void refreshTables();
+
+ /** called when an entry in a tree list box has been double-clicked
+ @param _rTree
+ The tree list box.
+ @return
+ <TRUE/> if the double click event has been handled by the called, and should not
+ be processed further.
+ */
+ bool onEntryDoubleClick(const weld::TreeView& rTree);
+
+ /** called when a container (category) in the application view has been selected
+ @param _pTree
+ The tree list box.
+ @return
+ <TRUE/> if the container could be changed otherwise <FALSE/>
+ */
+ bool onContainerSelect(ElementType _eType);
+
+ /** called when an entry in a tree view has been selected
+ @param _pEntry
+ the selected entry
+ */
+ void onSelectionChanged();
+
+ /** called when a "Copy" command is executed in a tree view
+ */
+ void onCopyEntry();
+
+ /** called when a "Paste" command is executed in a tree view
+ */
+ void onPasteEntry();
+
+ /** called when a "Delete" command is executed in a tree view
+ */
+ void onDeleteEntry();
+
+ /// called when the preview mode was changed
+ void previewChanged( sal_Int32 _nMode);
+
+ /// called when an object container of any kind was found during enumerating tree view elements
+ void containerFound( const css::uno::Reference< css::container::XContainer >& _xContainer);
+
+ // IController
+ virtual bool isDataSourceReadOnly() const override;
+
+ // IControlActionListener overridables
+ virtual bool requestQuickHelp(const void* pUserData, OUString& rText) const override;
+ virtual bool requestDrag(const weld::TreeIter& rEntry) override;
+ virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override;
+ virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override;
+
+ // IContextMenuProvider
+ virtual OUString getContextMenuResourceName() const override;
+ virtual IController& getCommandController() override;
+ virtual ::comphelper::OInterfaceContainerHelper2*
+ getContextMenuInterceptors() override;
+ virtual css::uno::Any getCurrentSelection(weld::TreeView& rControl) const override;
+ virtual vcl::Window* getMenuParent() const override;
+ virtual void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const override;
+
+ void OnInvalidateClipboard();
+ DECL_LINK( OnClipboardChanged, TransferableDataHelper*, void );
+ DECL_LINK( OnAsyncDrop, void*, void );
+ DECL_LINK( OnCreateWithPilot, void*, void );
+ DECL_LINK( OnSelectContainer, void*, void );
+ void OnFirstControllerConnected();
+
+ protected:
+ using OGenericUnoController::connect;
+
+ /** disconnects from our XConnection, and cleans up this connection
+ */
+ void disconnect();
+
+ // late construction
+ virtual bool Construct(vcl::Window* pParent) override;
+ virtual void describeSupportedFeatures() override;
+
+ protected:
+ // XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppControllerDnD.cxx b/dbaccess/source/ui/app/AppControllerDnD.cxx
new file mode 100644
index 000000000..3cc758acd
--- /dev/null
+++ b/dbaccess/source/ui/app/AppControllerDnD.cxx
@@ -0,0 +1,869 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "AppController.hxx"
+#include <comphelper/property.hxx>
+#include <core_resource.hxx>
+#include <strings.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <dlgsave.hxx>
+#include <vcl/weld.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <connectivity/dbexception.hxx>
+#include <sal/log.hxx>
+#include "AppView.hxx"
+#include <svx/dataaccessdescriptor.hxx>
+#include <svx/dbaobjectex.hxx>
+#include <strings.hrc>
+#include <vcl/svapp.hxx>
+#include <linkeddocuments.hxx>
+#include <connectivity/dbtools.hxx>
+#include <dbexchange.hxx>
+#include <UITools.hxx>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <svtools/querydelete.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <defaultobjectnamecheck.hxx>
+#include <osl/mutex.hxx>
+#include "subcomponentmanager.hxx"
+#include <set>
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::svx;
+using namespace ::svtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::util;
+
+void OApplicationController::deleteTables(const std::vector< OUString>& _rList)
+{
+ SharedConnection xConnection( ensureConnection() );
+
+ Reference<XTablesSupplier> xSup(xConnection,UNO_QUERY);
+ OSL_ENSURE(xSup.is(),"OApplicationController::deleteTable: no XTablesSupplier!");
+ if ( !xSup.is() )
+ return;
+
+ Reference<XNameAccess> xTables = xSup->getTables();
+ Reference<XDrop> xDrop(xTables,UNO_QUERY);
+ if ( xDrop.is() )
+ {
+ bool bConfirm = true;
+ std::vector< OUString>::const_iterator aEnd = _rList.end();
+ for (std::vector< OUString>::const_iterator aIter = _rList.begin(); aIter != aEnd; ++aIter)
+ {
+ OUString sTableName = *aIter;
+
+ sal_Int32 nResult = RET_YES;
+ if ( bConfirm )
+ nResult = ::dbaui::askForUserAction(getFrameWeld(), STR_TITLE_CONFIRM_DELETION, STR_QUERY_DELETE_TABLE, _rList.size() > 1 && (aIter+1) != _rList.end(), sTableName);
+
+ bool bUserConfirmedDelete =
+ ( RET_YES == nResult )
+ || ( RET_ALL == nResult );
+ if ( bUserConfirmedDelete && m_pSubComponentManager->closeSubFrames( sTableName, E_TABLE ) )
+ {
+ SQLExceptionInfo aErrorInfo;
+ try
+ {
+ if ( xTables->hasByName(sTableName) )
+ xDrop->dropByName(sTableName);
+ else
+ {// could be a view
+ Reference<XViewsSupplier> xViewsSup(xConnection,UNO_QUERY);
+
+ Reference<XNameAccess> xViews;
+ if ( xViewsSup.is() )
+ {
+ xViews = xViewsSup->getViews();
+ if ( xViews.is() && xViews->hasByName(sTableName) )
+ {
+ xDrop.set(xViews,UNO_QUERY);
+ if ( xDrop.is() )
+ xDrop->dropByName(sTableName);
+ }
+ }
+ }
+ }
+ catch(SQLContext& e) { aErrorInfo = e; }
+ catch(SQLWarning& e) { aErrorInfo = e; }
+ catch(SQLException& e) { aErrorInfo = e; }
+ catch(WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if(e.TargetException >>= aSql)
+ aErrorInfo = aSql;
+ else
+ OSL_FAIL("OApplicationController::implDropTable: something strange happened!");
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( aErrorInfo.isValid() )
+ showError(aErrorInfo);
+
+ if ( RET_ALL == nResult )
+ bConfirm = false;
+ }
+ else
+ break;
+ }
+ }
+ else
+ {
+ OUString sMessage(DBA_RES(STR_MISSING_TABLES_XDROP));
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sMessage));
+ xError->run();
+ }
+}
+
+void OApplicationController::deleteObjects( ElementType _eType, const std::vector< OUString>& _rList, bool _bConfirm )
+{
+ Reference< XNameContainer > xNames( getElements( _eType ), UNO_QUERY );
+ Reference< XHierarchicalNameContainer > xHierarchyName( xNames, UNO_QUERY );
+ if ( !xNames.is() )
+ return;
+
+ short eResult = _bConfirm ? svtools::QUERYDELETE_YES : svtools::QUERYDELETE_ALL;
+
+ // The list of elements to delete is allowed to contain related elements: A given element may
+ // be the ancestor or child of another element from the list.
+ // We want to ensure that ancestors get deleted first, so we normalize the list in this respect.
+ // #i33353#
+ // Note that this implicitly uses std::less< OUString > a comparison operation, which
+ // results in lexicographical order, which is exactly what we need, because "foo" is *before*
+ // any "foo/bar" in this order.
+ std::set< OUString > aDeleteNames(_rList.begin(), _rList.end());
+
+ std::set< OUString >::size_type nCount = aDeleteNames.size();
+ for ( std::set< OUString >::size_type nObjectsLeft = nCount; !aDeleteNames.empty(); )
+ {
+ std::set< OUString >::const_iterator aThisRound = aDeleteNames.begin();
+
+ if ( eResult != svtools::QUERYDELETE_ALL )
+ {
+ svtools::QueryDeleteDlg_Impl aDlg(getFrameWeld(), *aThisRound);
+
+ if ( nObjectsLeft > 1 )
+ aDlg.EnableAllButton();
+
+ eResult = aDlg.run();
+ }
+
+ bool bSuccess = false;
+
+ bool bUserConfirmedDelete =
+ ( eResult == svtools::QUERYDELETE_ALL )
+ || ( eResult == svtools::QUERYDELETE_YES );
+
+ if ( bUserConfirmedDelete
+ && ( _eType != E_QUERY || m_pSubComponentManager->closeSubFrames( *aThisRound, _eType ) )
+ )
+ {
+ try
+ {
+ if ( xHierarchyName.is() )
+ xHierarchyName->removeByHierarchicalName( *aThisRound );
+ else
+ xNames->removeByName( *aThisRound );
+
+ bSuccess = true;
+
+ // now that we removed the element, care for all its child elements
+ // which may also be a part of the list
+ // #i33353#
+ OSL_ENSURE( aThisRound->getLength() - 1 >= 0, "OApplicationController::deleteObjects: empty name?" );
+ OUString sSmallestSiblingName = *aThisRound + OUStringChar( sal_Unicode( '/' + 1) );
+
+ std::set< OUString >::const_iterator aUpperChildrenBound = aDeleteNames.lower_bound( sSmallestSiblingName );
+ for ( std::set< OUString >::const_iterator aObsolete = aThisRound;
+ aObsolete != aUpperChildrenBound;
+ )
+ {
+ std::set< OUString >::const_iterator aNextObsolete = aObsolete; ++aNextObsolete;
+ aDeleteNames.erase( aObsolete );
+ --nObjectsLeft;
+ aObsolete = aNextObsolete;
+ }
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch(const WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if ( e.TargetException >>= aSql )
+ showError( SQLExceptionInfo( e.TargetException ) );
+ else
+ OSL_FAIL( "OApplicationController::deleteObjects: something strange happened!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ // okay, this object could not be deleted (or the user did not want to delete it),
+ // but continue with the rest
+ aDeleteNames.erase( aThisRound );
+ --nObjectsLeft;
+ }
+ }
+}
+
+void OApplicationController::deleteEntries()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( !getContainer() )
+ return;
+
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ ElementType eType = getContainer()->getElementType();
+ switch(eType)
+ {
+ case E_TABLE:
+ deleteTables(aList);
+ break;
+ case E_QUERY:
+ deleteObjects( E_QUERY, aList, true );
+ break;
+ case E_FORM:
+ deleteObjects( E_FORM, aList, true );
+ break;
+ case E_REPORT:
+ deleteObjects( E_REPORT, aList, true );
+ break;
+ case E_NONE:
+ break;
+ }
+}
+
+// DO NOT CALL with getMutex() held!!
+const SharedConnection& OApplicationController::ensureConnection( ::dbtools::SQLExceptionInfo* _pErrorInfo )
+{
+
+ // This looks like double checked locking, but it is not,
+ // because every access (read *or* write) to m_xDataSourceConnection
+ // is mutexed.
+ // See http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
+ // for what I'm referring to.
+ // We cannot use the TLS (thread-local storage) solution
+ // since support for TLS is not up to the snuff on Windows :-(
+
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( m_xDataSourceConnection.is() )
+ return m_xDataSourceConnection;
+ }
+
+ weld::WaitObject aWO(getFrameWeld());
+ Reference<XConnection> conn;
+ {
+ SolarMutexGuard aSolarGuard;
+
+ OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE));
+ sConnectingContext = sConnectingContext.replaceFirst("$name$", getStrippedDatabaseName());
+
+ // do the connection *without* holding getMutex() to avoid deadlock
+ // when we are not in the main thread and we need username/password
+ // (and thus to display a dialog, which will be done by the main thread)
+ // and there is an event that needs getMutex() *before* us in the main thread's queue
+ // See fdo#63391
+ conn.set( connect( getDatabaseName(), sConnectingContext, _pErrorInfo ) );
+ }
+
+ if (conn.is())
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( m_xDataSourceConnection.is() )
+ {
+ Reference< XComponent > comp (conn, UNO_QUERY);
+ if(comp.is())
+ {
+ try
+ {
+ comp->dispose();
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "dbaui::OApplicationController::ensureConnection could not dispose of temporary unused connection" );
+ }
+ }
+ conn.clear();
+ }
+ else
+ {
+ m_xDataSourceConnection.reset(conn);
+ SQLExceptionInfo aError;
+ try
+ {
+ m_xMetaData = m_xDataSourceConnection->getMetaData();
+ }
+ catch( const SQLException& )
+ {
+ aError = ::cppu::getCaughtException();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ if ( aError.isValid() )
+ {
+ if ( _pErrorInfo )
+ {
+ *_pErrorInfo = aError;
+ }
+ else
+ {
+ SolarMutexGuard aSolarGuard;
+ showError( aError );
+ }
+ }
+ }
+ }
+
+ return m_xDataSourceConnection;
+}
+
+bool OApplicationController::isDataSourceReadOnly() const
+{
+ Reference<XStorable> xStore(m_xModel,UNO_QUERY);
+ return !xStore.is() || xStore->isReadonly();
+}
+
+bool OApplicationController::isConnectionReadOnly() const
+{
+ bool bIsConnectionReadOnly = true;
+ if ( m_xMetaData.is() )
+ {
+ try
+ {
+ bIsConnectionReadOnly = m_xMetaData->isReadOnly();
+ }
+ catch(const SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ // TODO check configuration
+ return bIsConnectionReadOnly;
+}
+
+Reference< XNameAccess > OApplicationController::getElements( ElementType _eType )
+{
+ Reference< XNameAccess > xElements;
+ try
+ {
+ switch ( _eType )
+ {
+ case E_REPORT:
+ {
+ Reference< XReportDocumentsSupplier > xSupp( m_xModel, UNO_QUERY_THROW );
+ xElements.set( xSupp->getReportDocuments(), UNO_SET_THROW );
+ }
+ break;
+
+ case E_FORM:
+ {
+ Reference< XFormDocumentsSupplier > xSupp( m_xModel, UNO_QUERY_THROW );
+ xElements.set( xSupp->getFormDocuments(), UNO_SET_THROW );
+ }
+ break;
+
+ case E_QUERY:
+ {
+ xElements.set( getQueryDefinitions(), UNO_QUERY_THROW );
+ }
+ break;
+
+ case E_TABLE:
+ {
+ if ( m_xDataSourceConnection.is() )
+ {
+ Reference< XTablesSupplier > xSup( getConnection(), UNO_QUERY_THROW );
+ xElements.set( xSup->getTables(), UNO_SET_THROW );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return xElements;
+}
+
+void OApplicationController::getSelectionElementNames(std::vector< OUString>& _rNames) const
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ OSL_ENSURE(getContainer(),"View isn't valid! -> GPF");
+
+ getContainer()->getSelectionElementNames( _rNames );
+}
+
+std::unique_ptr< OLinkedDocumentsAccess > OApplicationController::getDocumentsAccess( ElementType _eType )
+{
+ OSL_ENSURE( ( _eType == E_TABLE ) || ( _eType == E_QUERY ) || ( _eType == E_FORM ) || ( _eType == E_REPORT ),
+ "OApplicationController::getDocumentsAccess: only forms and reports are supported here!" );
+
+ SharedConnection xConnection( ensureConnection() );
+ Reference< XNameAccess > xDocContainer;
+
+ if ( ( _eType == E_FORM ) || ( _eType == E_REPORT ) )
+ {
+ xDocContainer.set( getElements( _eType ) );
+ OSL_ENSURE( xDocContainer.is(), "OApplicationController::getDocumentsAccess: invalid container!" );
+ }
+
+ std::unique_ptr< OLinkedDocumentsAccess > pDocuments( new OLinkedDocumentsAccess(
+ getFrameWeld(), this, getORB(), xDocContainer, xConnection, getDatabaseName()
+ ) );
+ return pDocuments;
+}
+
+bool OApplicationController::copySQLObject(ODataClipboard& rExchange)
+{
+ bool bSuccess = false;
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ ElementType eType = getContainer()->getElementType();
+ switch( eType )
+ {
+ case E_TABLE:
+ case E_QUERY:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ Reference< XDatabaseMetaData> xMetaData;
+ if ( xConnection.is() )
+ xMetaData = xConnection->getMetaData();
+
+ OUString sName = getContainer()->getQualifiedName( nullptr );
+ if ( !sName.isEmpty() )
+ {
+ OUString sDataSource = getDatabaseName();
+
+ if ( eType == E_TABLE )
+ {
+ rExchange.Update(sDataSource, CommandType::TABLE, sName, xConnection, getNumberFormatter(xConnection, getORB()), getORB());
+ }
+ else
+ {
+ rExchange.Update(sDataSource, CommandType::QUERY, sName, getNumberFormatter(xConnection, getORB()), getORB());
+ }
+ bSuccess = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+}
+
+bool OApplicationController::copyDocObject(svx::OComponentTransferable& rExchange)
+{
+ bool bSuccess = false;
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ ElementType eType = getContainer()->getElementType();
+ switch( eType )
+ {
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ Reference< XHierarchicalNameAccess > xElements(getElements(eType),UNO_QUERY);
+ if ( xElements.is() && !aList.empty() )
+ {
+ Reference< XContent> xContent(xElements->getByHierarchicalName(*aList.begin()),UNO_QUERY);
+ rExchange.Update(getDatabaseName(), xContent);
+ bSuccess = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+}
+
+rtl::Reference<TransferableHelper> OApplicationController::copyObject()
+{
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ ElementType eType = getContainer()->getElementType();
+ switch( eType )
+ {
+ case E_TABLE:
+ case E_QUERY:
+ {
+ rtl::Reference<ODataClipboard> xExchange(new ODataClipboard);
+ if (copySQLObject(*xExchange))
+ return xExchange;
+ break;
+ }
+ case E_FORM:
+ case E_REPORT:
+ {
+ rtl::Reference<svx::OComponentTransferable> xExchange(new svx::OComponentTransferable);
+ if (copyDocObject(*xExchange))
+ return xExchange;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return nullptr;
+}
+
+bool OApplicationController::paste( ElementType _eType, const svx::ODataAccessDescriptor& _rPasteData, const OUString& _sParentFolder, bool _bMove)
+{
+ try
+ {
+ if ( _eType == E_QUERY )
+ {
+ sal_Int32 nCommandType = CommandType::TABLE;
+ if ( _rPasteData.has(DataAccessDescriptorProperty::CommandType) )
+ _rPasteData[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
+
+ if ( CommandType::QUERY == nCommandType || CommandType::COMMAND == nCommandType )
+ {
+ // read all necessary data
+
+ OUString sCommand;
+ bool bEscapeProcessing = true;
+
+ _rPasteData[DataAccessDescriptorProperty::Command] >>= sCommand;
+ if ( _rPasteData.has(DataAccessDescriptorProperty::EscapeProcessing) )
+ _rPasteData[DataAccessDescriptorProperty::EscapeProcessing] >>= bEscapeProcessing;
+
+ // plausibility check
+ bool bValidDescriptor = false;
+ OUString sDataSourceName = _rPasteData.getDataSource();
+ if (CommandType::QUERY == nCommandType)
+ bValidDescriptor = sDataSourceName.getLength() && sCommand.getLength();
+ else if (CommandType::COMMAND == nCommandType)
+ bValidDescriptor = !sCommand.isEmpty();
+ if (!bValidDescriptor)
+ {
+ OSL_FAIL("OApplicationController::paste: invalid descriptor!");
+ return false;
+ }
+
+ // the target object name (as we'll suggest it to the user)
+ OUString sTargetName;
+ try
+ {
+ if ( CommandType::QUERY == nCommandType )
+ sTargetName = sCommand;
+
+ if ( sTargetName.isEmpty() )
+ {
+ OUString sDefaultName = DBA_RES(STR_QRY_TITLE);
+ sDefaultName = sDefaultName.getToken( 0, ' ' );
+
+ Reference< XNameAccess > xQueries( getQueryDefinitions(), UNO_QUERY_THROW );
+ sTargetName = ::dbtools::createUniqueName( xQueries, sDefaultName, false );
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ Reference< XPropertySet > xQuery;
+ if (CommandType::QUERY == nCommandType)
+ {
+ // need to extract the statement and the escape processing flag from the query object
+ bool bSuccess = false;
+ try
+ {
+ // the concrete query
+ Reference< XQueryDefinitionsSupplier > xSourceQuerySup(
+ getDataSourceByName( sDataSourceName, getFrameWeld(), getORB(), nullptr ),
+ UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSourceQuerySup->getQueryDefinitions(), UNO_SET_THROW );
+ if ( xQueries->hasByName( sCommand ) )
+ {
+ xQuery.set( xQueries->getByName(sCommand), UNO_QUERY_THROW );
+ bSuccess = true;
+ }
+ }
+ catch(SQLException&) { throw; } // caught and handled by the outer catch
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if (!bSuccess)
+ {
+ OSL_FAIL("OApplicationController::paste: could not extract the source query object!");
+ // TODO: maybe this is worth an error message to be displayed to the user...
+ return false;
+ }
+ }
+
+ Reference< XNameContainer > xDestQueries = getQueryDefinitions();
+ Reference< XSingleServiceFactory > xQueryFactory(xDestQueries, UNO_QUERY);
+ if (!xQueryFactory.is())
+ {
+ OSL_FAIL("OApplicationController::paste: invalid destination query container!");
+ return false;
+ }
+
+ // here we have everything needed to create a new query object...
+ // ... ehm, except a new name
+ ensureConnection();
+
+ DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::QUERY );
+ ::dbtools::SQLExceptionInfo aDummy;
+ bool bNeedAskForName = ( sCommand.isEmpty() )
+ /* we did not have a source name, so the target name was auto-generated */
+ || ( !aNameChecker.isNameValid( sTargetName, aDummy ) );
+ /* name is invalid in the target DB (e.g. because it already
+ has a /table/ with that name) */
+ if ( bNeedAskForName )
+ {
+ OSaveAsDlg aAskForName(getFrameWeld(),
+ CommandType::QUERY,
+ getORB(),
+ getConnection(),
+ sTargetName,
+ aNameChecker,
+ SADFlags::AdditionalDescription | SADFlags::TitlePasteAs );
+ if ( RET_OK != aAskForName.run() )
+ // cancelled by the user
+ return false;
+ sTargetName = aAskForName.getName();
+ }
+
+ // create a new object
+ Reference< XPropertySet > xNewQuery(xQueryFactory->createInstance(), UNO_QUERY);
+ OSL_ENSURE(xNewQuery.is(), "OApplicationController::paste: invalid object created by factory!");
+ if (xNewQuery.is())
+ {
+ // initialize
+ if ( xQuery.is() )
+ ::comphelper::copyProperties(xQuery,xNewQuery);
+ else
+ {
+ xNewQuery->setPropertyValue(PROPERTY_COMMAND,Any(sCommand));
+ xNewQuery->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,Any(bEscapeProcessing));
+ }
+ // insert
+ xDestQueries->insertByName( sTargetName, Any(xNewQuery) );
+ xNewQuery.set(xDestQueries->getByName( sTargetName),UNO_QUERY);
+ if ( xQuery.is() && xNewQuery.is() )
+ {
+ Reference<XColumnsSupplier> xSrcColSup(xQuery,UNO_QUERY);
+ Reference<XColumnsSupplier> xDstColSup(xNewQuery,UNO_QUERY);
+ if ( xSrcColSup.is() && xDstColSup.is() )
+ {
+ Reference<XNameAccess> xSrcNameAccess = xSrcColSup->getColumns();
+ Reference<XNameAccess> xDstNameAccess = xDstColSup->getColumns();
+ Reference<XDataDescriptorFactory> xFac(xDstNameAccess,UNO_QUERY);
+ Reference<XAppend> xAppend(xFac,UNO_QUERY);
+ if ( xSrcNameAccess.is() && xDstNameAccess.is() && xSrcNameAccess->hasElements() && xAppend.is() )
+ {
+ Reference<XPropertySet> xDstProp(xFac->createDataDescriptor());
+
+ Sequence< OUString> aSeq = xSrcNameAccess->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for( ; pIter != pEnd ; ++pIter)
+ {
+ Reference<XPropertySet> xSrcProp(xSrcNameAccess->getByName(*pIter),UNO_QUERY);
+ ::comphelper::copyProperties(xSrcProp,xDstProp);
+ xAppend->appendByDescriptor(xDstProp);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ SAL_WARN("dbaccess", "There should be a sequence in it!");
+ return true;
+ }
+ else if ( _rPasteData.has(DataAccessDescriptorProperty::Component) ) // forms or reports
+ {
+ Reference<XContent> xContent;
+ _rPasteData[DataAccessDescriptorProperty::Component] >>= xContent;
+ return insertHierarchyElement(_eType,_sParentFolder,Reference<XNameAccess>(xContent,UNO_QUERY).is(),xContent,_bMove);
+ }
+ }
+ catch(const SQLException&) { showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return false;
+}
+
+Reference<XNameContainer> OApplicationController::getQueryDefinitions() const
+{
+ Reference<XQueryDefinitionsSupplier> xSet(m_xDataSource,UNO_QUERY);
+ Reference<XNameContainer> xNames;
+ if ( xSet.is() )
+ {
+ xNames.set(xSet->getQueryDefinitions(),UNO_QUERY);
+ }
+ return xNames;
+}
+
+void OApplicationController::getSupportedFormats(ElementType _eType,std::vector<SotClipboardFormatId>& _rFormatIds)
+{
+ switch( _eType )
+ {
+ case E_TABLE:
+ _rFormatIds.push_back(SotClipboardFormatId::DBACCESS_TABLE);
+ _rFormatIds.push_back(SotClipboardFormatId::RTF);
+ _rFormatIds.push_back(SotClipboardFormatId::HTML);
+ [[fallthrough]];
+ case E_QUERY:
+ _rFormatIds.push_back(SotClipboardFormatId::DBACCESS_QUERY);
+ break;
+ default:
+ break;
+ }
+}
+
+bool OApplicationController::isTableFormat() const
+{
+ return OTableCopyHelper::isTableFormat(getViewClipboard());
+}
+
+IMPL_LINK_NOARG( OApplicationController, OnAsyncDrop, void*, void )
+{
+ m_nAsyncDrop = nullptr;
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( m_aAsyncDrop.nType == E_TABLE )
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ m_aTableCopyHelper.asyncCopyTagTable( m_aAsyncDrop, getDatabaseName(), xConnection );
+ }
+ else
+ {
+ if ( paste(m_aAsyncDrop.nType,m_aAsyncDrop.aDroppedData,m_aAsyncDrop.aUrl,m_aAsyncDrop.nAction == DND_ACTION_MOVE)
+ && m_aAsyncDrop.nAction == DND_ACTION_MOVE )
+ {
+ Reference<XContent> xContent;
+ m_aAsyncDrop.aDroppedData[DataAccessDescriptorProperty::Component] >>= xContent;
+ std::vector< OUString> aList;
+ sal_Int32 nIndex = 0;
+ OUString sName = xContent->getIdentifier()->getContentIdentifier();
+ std::u16string_view sErase = o3tl::getToken(sName,0,'/',nIndex); // we don't want to have the "private:forms" part
+ if ( nIndex != -1 )
+ {
+ aList.push_back(sName.copy(sErase.size() + 1));
+ deleteObjects( m_aAsyncDrop.nType, aList, false );
+ }
+ }
+ }
+
+ m_aAsyncDrop.aDroppedData.clear();
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppControllerGen.cxx b/dbaccess/source/ui/app/AppControllerGen.cxx
new file mode 100644
index 000000000..22dfb3663
--- /dev/null
+++ b/dbaccess/source/ui/app/AppControllerGen.cxx
@@ -0,0 +1,736 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppController.hxx"
+#include "AppDetailView.hxx"
+#include "AppView.hxx"
+#include <core_resource.hxx>
+#include <dbaccess_slotid.hrc>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <defaultobjectnamecheck.hxx>
+#include <dlgsave.hxx>
+#include <UITools.hxx>
+#include "subcomponentmanager.hxx"
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <sfx2/mailmodelapi.hxx>
+#include <svx/dbaexchange.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <vcl/mnemonic.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/weld.hxx>
+#include <osl/mutex.hxx>
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::connectivity;
+using namespace ::svx;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ucb;
+
+using ::com::sun::star::ui::XContextMenuInterceptor;
+
+namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject;
+namespace ErrorCondition = ::com::sun::star::sdb::ErrorCondition;
+
+void OApplicationController::convertToView(const OUString& _sName)
+{
+ try
+ {
+ SharedConnection xConnection( getConnection() );
+ Reference< XQueriesSupplier > xSup( xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSup->getQueries(), UNO_SET_THROW );
+ Reference< XPropertySet > xSourceObject( xQueries->getByName( _sName ), UNO_QUERY_THROW );
+
+ Reference< XTablesSupplier > xTablesSup( xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xTables( xTablesSup->getTables(), UNO_SET_THROW );
+
+ Reference< XDatabaseMetaData > xMeta = xConnection->getMetaData();
+
+ const OUString aDefaultName = ::dbaui::createDefaultName(xMeta, xTables, DBA_RES(STR_TBL_TITLE).getToken(0, ' '));
+
+ DynamicTableOrQueryNameCheck aNameChecker( xConnection, CommandType::TABLE );
+ OSaveAsDlg aDlg(getFrameWeld(), CommandType::TABLE, getORB(), xConnection, aDefaultName, aNameChecker, SADFlags::NONE);
+ if (aDlg.run() == RET_OK)
+ {
+ OUString sName = aDlg.getName();
+ OUString sCatalog = aDlg.getCatalog();
+ OUString sSchema = aDlg.getSchema();
+ OUString sNewName(
+ ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sName, false, ::dbtools::EComposeRule::InTableDefinitions ) );
+ Reference<XPropertySet> xView = ::dbaui::createView(sNewName,xConnection,xSourceObject);
+ if ( !xView.is() )
+ throw SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE),*this, "S1000",0,Any());
+ getContainer()->elementAdded(E_TABLE,sNewName,Any(xView));
+ }
+ }
+ catch(const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::pasteFormat(SotClipboardFormatId _nFormatId)
+{
+ if ( _nFormatId == SotClipboardFormatId::NONE )
+ return;
+
+ try
+ {
+ const TransferableDataHelper& rClipboard = getViewClipboard();
+ ElementType eType = getContainer()->getElementType();
+ if ( eType == E_TABLE )
+ {
+ m_aTableCopyHelper.pasteTable( _nFormatId, rClipboard, getDatabaseName(), ensureConnection() );
+ }
+ else
+ paste( eType, ODataAccessObjectTransferable::extractObjectDescriptor( rClipboard ) );
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::openDialog( const OUString& _sServiceName )
+{
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ weld::WaitObject aWO(getFrameWeld());
+
+ Sequence< Any > aArgs(3);
+ auto pArgs = aArgs.getArray();
+ sal_Int32 nArgPos = 0;
+
+ Reference< css::awt::XWindow> xWindow = getTopMostContainerWindow();
+ if ( !xWindow.is() )
+ {
+ OSL_ENSURE( getContainer(), "OApplicationController::Construct: have no view!" );
+ if ( getContainer() )
+ xWindow = VCLUnoHelper::GetInterface(getView()->Window::GetParent());
+ }
+ // the parent window
+ pArgs[nArgPos++] <<= PropertyValue( "ParentWindow",
+ 0,
+ Any(xWindow),
+ PropertyState_DIRECT_VALUE);
+
+ // the initial selection
+ OUString sInitialSelection;
+ if ( getContainer() )
+ sInitialSelection = getDatabaseName();
+ if ( !sInitialSelection.isEmpty() )
+ {
+ pArgs[ nArgPos++ ] <<= PropertyValue(
+ "InitialSelection", 0,
+ Any( sInitialSelection ), PropertyState_DIRECT_VALUE );
+ }
+
+ SharedConnection xConnection( getConnection() );
+ if ( xConnection.is() )
+ {
+ pArgs[ nArgPos++ ] <<= PropertyValue(
+ PROPERTY_ACTIVE_CONNECTION, 0,
+ makeAny( xConnection ), PropertyState_DIRECT_VALUE );
+ }
+ aArgs.realloc( nArgPos );
+
+ // create the dialog
+ Reference< XExecutableDialog > xAdminDialog;
+ xAdminDialog.set(
+ getORB()->getServiceManager()->createInstanceWithArgumentsAndContext(_sServiceName, aArgs, getORB()),
+ UNO_QUERY);
+
+ // execute it
+ if (xAdminDialog.is())
+ xAdminDialog->execute();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::refreshTables()
+{
+ if ( !(getContainer() && getContainer()->getDetailView()) )
+ return;
+
+ weld::WaitObject aWO(getFrameWeld());
+ OSL_ENSURE(getContainer()->getElementType() == E_TABLE,"Only allowed when the tables container is selected!");
+ try
+ {
+ Reference<XRefreshable> xRefresh(getElements(E_TABLE),UNO_QUERY);
+ if ( xRefresh.is() )
+ xRefresh->refresh();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Could not refresh tables!");
+ }
+
+ getContainer()->getDetailView()->clearPages(false);
+ getContainer()->getDetailView()->createTablesPage( ensureConnection() );
+}
+
+void SAL_CALL OApplicationController::propertyChange( const PropertyChangeEvent& evt )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( evt.PropertyName == PROPERTY_USER )
+ {
+ m_bNeedToReconnect = true;
+ InvalidateFeature(SID_DB_APP_STATUS_USERNAME);
+ }
+ else if ( evt.PropertyName == PROPERTY_URL )
+ {
+ m_bNeedToReconnect = true;
+ InvalidateFeature(SID_DB_APP_STATUS_DBNAME);
+ InvalidateFeature(SID_DB_APP_STATUS_TYPE);
+ InvalidateFeature(SID_DB_APP_STATUS_HOSTNAME);
+ }
+ else if ( PROPERTY_NAME == evt.PropertyName )
+ {
+ const ElementType eType = getContainer()->getElementType();
+ if ( eType == E_FORM || eType == E_REPORT )
+ {
+ OUString sOldName,sNewName;
+ evt.OldValue >>= sOldName;
+ evt.NewValue >>= sNewName;
+
+ // if the old name is empty, then this is a newly inserted content. We're notified of it via the
+ // elementInserted method, so there's no need to handle it here.
+
+ if ( !sOldName.isEmpty() )
+ {
+ Reference<XChild> xChild(evt.Source,UNO_QUERY);
+ if ( xChild.is() )
+ {
+ Reference<XContent> xContent(xChild->getParent(),UNO_QUERY);
+ if ( xContent.is() )
+ sOldName = xContent->getIdentifier()->getContentIdentifier() + "/" + sOldName;
+ }
+
+ getContainer()->elementReplaced( eType , sOldName, sNewName );
+ }
+ }
+ }
+
+ EventObject aEvt;
+ aEvt.Source = m_xModel;
+ modified(aEvt);
+}
+
+Reference< XDataSource > SAL_CALL OApplicationController::getDataSource()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ return xDataSource;
+}
+
+Reference< XWindow > SAL_CALL OApplicationController::getApplicationMainWindow()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ Reference< XFrame > xFrame( getFrame(), UNO_SET_THROW );
+ Reference< XWindow > xWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
+ return xWindow;
+}
+
+Sequence< Reference< XComponent > > SAL_CALL OApplicationController::getSubComponents()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_pSubComponentManager->getSubComponents();
+}
+
+Reference< XConnection > SAL_CALL OApplicationController::getActiveConnection()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_xDataSourceConnection.getTyped();
+}
+
+sal_Bool SAL_CALL OApplicationController::isConnected( )
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_xDataSourceConnection.is();
+}
+
+void SAL_CALL OApplicationController::connect( )
+{
+ SQLExceptionInfo aError;
+ SharedConnection xConnection = ensureConnection( &aError );
+ if ( !xConnection.is() )
+ {
+ if ( aError.isValid() )
+ aError.doThrow();
+
+ // no particular error, but nonetheless could not connect -> throw a generic exception
+ OUString sConnectingContext( DBA_RES( STR_COULDNOTCONNECT_DATASOURCE ) );
+ ::dbtools::throwGenericSQLException( sConnectingContext.replaceFirst( "$name$", getStrippedDatabaseName() ), *this );
+ }
+}
+
+beans::Pair< ::sal_Int32, OUString > SAL_CALL OApplicationController::identifySubComponent( const Reference< XComponent >& i_rSubComponent )
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ sal_Int32 nType = -1;
+ OUString sName;
+
+ if ( !m_pSubComponentManager->lookupSubComponent( i_rSubComponent, sName, nType ) )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ if ( nType == SID_DB_APP_DSRELDESIGN )
+ // this is somewhat hacky ... we're expected to return a DatabaseObject value. However, there is no such
+ // value for the relation design. /me thinks we should change the API definition here ...
+ nType = -1;
+
+ return beans::Pair< ::sal_Int32, OUString >( nType, sName );
+}
+
+sal_Bool SAL_CALL OApplicationController::closeSubComponents( )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_pSubComponentManager->closeSubComponents();
+}
+
+namespace
+{
+ ElementType lcl_objectType2ElementType( const sal_Int32 _nObjectType )
+ {
+ ElementType eType( E_NONE );
+ switch ( _nObjectType )
+ {
+ case DatabaseObject::TABLE: eType = E_TABLE; break;
+ case DatabaseObject::QUERY: eType = E_QUERY; break;
+ case DatabaseObject::FORM: eType = E_FORM; break;
+ case DatabaseObject::REPORT: eType = E_REPORT; break;
+ default:
+ OSL_FAIL( "lcl_objectType2ElementType: unsupported object type!" );
+ // this should have been caught earlier
+ }
+ return eType;
+ }
+}
+
+void OApplicationController::impl_validateObjectTypeAndName_throw( const sal_Int32 _nObjectType, const ::std::optional< OUString >& i_rObjectName )
+{
+ // ensure we're connected
+ if ( !isConnected() )
+ {
+ SQLError aError;
+ aError.raiseException( ErrorCondition::DB_NOT_CONNECTED, *this );
+ }
+
+ // ensure a proper object type
+ if ( ( _nObjectType != DatabaseObject::TABLE )
+ && ( _nObjectType != DatabaseObject::QUERY )
+ && ( _nObjectType != DatabaseObject::FORM )
+ && ( _nObjectType != DatabaseObject::REPORT )
+ )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ if ( !i_rObjectName )
+ return;
+
+ // ensure an existing object
+ Reference< XNameAccess > xContainer( getElements( lcl_objectType2ElementType( _nObjectType ) ) );
+ if ( !xContainer.is() )
+ // all possible reasons for this (e.g. not being connected currently) should
+ // have been handled before
+ throw RuntimeException( OUString(), *this );
+
+ bool bExistentObject = false;
+ switch ( _nObjectType )
+ {
+ case DatabaseObject::TABLE:
+ case DatabaseObject::QUERY:
+ bExistentObject = xContainer->hasByName( *i_rObjectName );
+ break;
+ case DatabaseObject::FORM:
+ case DatabaseObject::REPORT:
+ {
+ Reference< XHierarchicalNameAccess > xHierarchy( xContainer, UNO_QUERY_THROW );
+ bExistentObject = xHierarchy->hasByHierarchicalName( *i_rObjectName );
+ }
+ break;
+ }
+
+ if ( !bExistentObject )
+ throw NoSuchElementException( *i_rObjectName, *this );
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::loadComponent( ::sal_Int32 ObjectType,
+ const OUString& ObjectName, sal_Bool ForEditing )
+{
+ return loadComponentWithArguments( ObjectType, ObjectName, ForEditing, Sequence< PropertyValue >() );
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::loadComponentWithArguments( ::sal_Int32 ObjectType,
+ const OUString& ObjectName, sal_Bool ForEditing, const Sequence< PropertyValue >& Arguments )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ impl_validateObjectTypeAndName_throw( ObjectType, ObjectName );
+
+ Reference< XComponent > xComponent( openElementWithArguments(
+ ObjectName,
+ lcl_objectType2ElementType( ObjectType ),
+ ForEditing ? E_OPEN_DESIGN : E_OPEN_NORMAL,
+ ForEditing ? SID_DB_APP_EDIT : SID_DB_APP_OPEN,
+ ::comphelper::NamedValueCollection( Arguments )
+ ) );
+
+ return xComponent;
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::createComponent( ::sal_Int32 i_nObjectType, Reference< XComponent >& o_DocumentDefinition )
+{
+ return createComponentWithArguments( i_nObjectType, Sequence< PropertyValue >(), o_DocumentDefinition );
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::createComponentWithArguments( ::sal_Int32 i_nObjectType, const Sequence< PropertyValue >& i_rArguments, Reference< XComponent >& o_DocumentDefinition )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ impl_validateObjectTypeAndName_throw( i_nObjectType, ::std::optional< OUString >() );
+
+ Reference< XComponent > xComponent( newElement(
+ lcl_objectType2ElementType( i_nObjectType ),
+ ::comphelper::NamedValueCollection( i_rArguments ),
+ o_DocumentDefinition
+ ) );
+
+ return xComponent;
+}
+
+void SAL_CALL OApplicationController::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
+{
+ if ( Interceptor.is() )
+ m_aContextMenuInterceptors.addInterface( Interceptor );
+}
+
+void SAL_CALL OApplicationController::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
+{
+ m_aContextMenuInterceptors.removeInterface( Interceptor );
+}
+
+void OApplicationController::previewChanged( sal_Int32 _nMode )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( m_xDataSource.is() && !isDataSourceReadOnly() )
+ {
+ try
+ {
+ ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) );
+ sal_Int32 nOldMode = aLayoutInfo.getOrDefault( "Preview", _nMode );
+ if ( nOldMode != _nMode )
+ {
+ aLayoutInfo.put( "Preview", _nMode );
+ m_xDataSource->setPropertyValue( PROPERTY_LAYOUTINFORMATION, Any( aLayoutInfo.getPropertyValues() ) );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ InvalidateFeature(SID_DB_APP_DISABLE_PREVIEW);
+ InvalidateFeature(SID_DB_APP_VIEW_DOCINFO_PREVIEW);
+ InvalidateFeature(SID_DB_APP_VIEW_DOC_PREVIEW);
+}
+
+void OApplicationController::askToReconnect()
+{
+ if ( !m_bNeedToReconnect )
+ return;
+
+ m_bNeedToReconnect = false;
+ bool bClear = true;
+ if ( !m_pSubComponentManager->empty() )
+ {
+ std::unique_ptr<weld::MessageDialog> xQry(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ DBA_RES(STR_QUERY_CLOSEDOCUMENTS)));
+ switch (xQry->run())
+ {
+ case RET_YES:
+ closeSubComponents();
+ break;
+ default:
+ bClear = false;
+ break;
+ }
+ }
+ if ( bClear )
+ {
+ ElementType eType = getContainer()->getElementType();
+ disconnect();
+ getContainer()->getDetailView()->clearPages(false);
+ getContainer()->selectContainer(E_NONE); // invalidate the old selection
+ m_eCurrentType = E_NONE;
+ getContainer()->selectContainer(eType); // reselect the current one again
+ }
+}
+
+OUString OApplicationController::getDatabaseName() const
+{
+ OUString sDatabaseName;
+ try
+ {
+ if ( m_xDataSource.is() )
+ {
+ OSL_VERIFY( m_xDataSource->getPropertyValue( PROPERTY_NAME ) >>= sDatabaseName );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sDatabaseName;
+}
+
+OUString OApplicationController::getStrippedDatabaseName() const
+{
+ OUString sDatabaseName;
+ return ::dbaui::getStrippedDatabaseName( m_xDataSource, sDatabaseName );
+}
+
+void OApplicationController::onDocumentOpened( const OUString& _rName, const sal_Int32 _nType,
+ const ElementOpenMode _eMode, const Reference< XComponent >& _xDocument, const Reference< XComponent >& _rxDefinition )
+{
+ if ( !_xDocument.is() )
+ return;
+
+ try
+ {
+ OSL_ENSURE( _xDocument.is(), "OApplicationController::onDocumentOpened: is there any *valid* scenario where this fails?" );
+ m_pSubComponentManager->onSubComponentOpened( _rName, _nType, _eMode, _xDocument.is() ? _xDocument : _rxDefinition );
+
+ if ( _rxDefinition.is() )
+ {
+ Reference< XPropertySet > xProp( _rxDefinition, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPSI( xProp->getPropertySetInfo(), UNO_SET_THROW );
+ xProp->addPropertyChangeListener( PROPERTY_NAME, static_cast< XPropertyChangeListener* >( this ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+bool OApplicationController::insertHierarchyElement(ElementType _eType, const OUString& _sParentFolder, bool _bCollection, const Reference<XContent>& _xContent, bool _bMove)
+{
+ Reference<XHierarchicalNameContainer> xNames(getElements(_eType), UNO_QUERY);
+ return dbaui::insertHierarchyElement(getFrameWeld()
+ ,getORB()
+ ,xNames
+ ,_sParentFolder
+ ,_eType == E_FORM
+ ,_bCollection
+ ,_xContent
+ ,_bMove);
+}
+
+bool OApplicationController::isRenameDeleteAllowed(ElementType _eType, bool _bDelete) const
+{
+ ElementType eType = getContainer()->getElementType();
+ bool bEnabled = !isDataSourceReadOnly() && eType == _eType;
+ if ( bEnabled )
+ {
+
+ if ( E_TABLE == eType )
+ bEnabled = !isConnectionReadOnly() && getContainer()->isALeafSelected();
+
+ bool bCompareRes = false;
+ if ( _bDelete )
+ bCompareRes = getContainer()->getSelectionCount() > 0;
+ else
+ {
+ bCompareRes = getContainer()->getSelectionCount() == 1;
+ if ( bEnabled && bCompareRes && E_TABLE == eType )
+ {
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+
+ try
+ {
+ Reference< XNameAccess > xContainer = const_cast<OApplicationController*>(this)->getElements(eType);
+ bEnabled = (xContainer.is() && xContainer->hasByName(*aList.begin()));
+ if ( bEnabled )
+ bEnabled = Reference<XRename>(xContainer->getByName(*aList.begin()),UNO_QUERY).is();
+ }
+ catch(Exception&)
+ {
+ bEnabled = false;
+ }
+ }
+ }
+
+ bEnabled = bEnabled && bCompareRes;
+ }
+ return bEnabled;
+}
+
+void OApplicationController::onLoadedMenu(const Reference< css::frame::XLayoutManager >& _xLayoutManager)
+{
+
+ if ( !_xLayoutManager.is() )
+ return;
+
+ static constexpr OUStringLiteral s_sStatusbar = u"private:resource/statusbar/statusbar";
+ _xLayoutManager->createElement( s_sStatusbar );
+ _xLayoutManager->requestElement( s_sStatusbar );
+
+ if ( getContainer() )
+ {
+ // we need to share the "mnemonic space":
+ MnemonicGenerator aMnemonicGenerator;
+ // - the menu already has mnemonics
+ if (SystemWindow* pSystemWindow = getContainer()->GetSystemWindow())
+ pSystemWindow->CollectMenuBarMnemonics(aMnemonicGenerator);
+ // - the icons should use automatic ones
+ getContainer()->createIconAutoMnemonics( aMnemonicGenerator );
+ // - as well as the entries in the task pane
+ getContainer()->setTaskExternalMnemonics( aMnemonicGenerator );
+ }
+
+ Execute( SID_DB_APP_VIEW_FORMS, Sequence< PropertyValue >() );
+ InvalidateAll();
+}
+
+void OApplicationController::doAction(sal_uInt16 _nId, const ElementOpenMode _eOpenMode)
+{
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ ElementType eType = getContainer()->getElementType();
+ ::comphelper::NamedValueCollection aArguments;
+ ElementOpenMode eOpenMode = _eOpenMode;
+ if ( eType == E_REPORT && E_OPEN_FOR_MAIL == _eOpenMode )
+ {
+ aArguments.put("Hidden",true);
+ eOpenMode = E_OPEN_NORMAL;
+ }
+
+ std::vector< std::pair< OUString ,Reference< XModel > > > aComponents;
+ for (auto const& elem : aList)
+ {
+ if ( SID_DB_APP_CONVERTTOVIEW == _nId )
+ convertToView(elem);
+ else
+ {
+ Reference< XModel > xModel( openElementWithArguments( elem, eType, eOpenMode, _nId,aArguments ), UNO_QUERY );
+ aComponents.emplace_back( elem, xModel );
+ }
+ }
+
+ // special handling for mail, if more than one document is selected attach them all
+ if ( _eOpenMode != E_OPEN_FOR_MAIL )
+ return;
+
+
+ SfxMailModel aSendMail;
+ SfxMailModel::SendMailResult eResult = SfxMailModel::SEND_MAIL_OK;
+ for (auto const& component : aComponents)
+ {
+ try
+ {
+ Reference< XModel > xModel = component.second;
+
+ // Send document as e-Mail using stored/default type
+ eResult = aSendMail.AttachDocument(xModel,component.first);
+ ::comphelper::disposeComponent(xModel);
+ if (eResult != SfxMailModel::SEND_MAIL_OK)
+ break;
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ if ( !aSendMail.IsEmpty() )
+ aSendMail.Send( getFrame() );
+}
+
+ElementType OApplicationController::getElementType(const Reference< XContainer >& _xContainer)
+{
+ ElementType eRet = E_NONE;
+ Reference<XServiceInfo> xServiceInfo(_xContainer,UNO_QUERY);
+ if ( xServiceInfo.is() )
+ {
+ if ( xServiceInfo->supportsService(SERVICE_SDBCX_TABLES) )
+ eRet = E_TABLE;
+ else if ( xServiceInfo->supportsService(SERVICE_NAME_FORM_COLLECTION) )
+ eRet = E_FORM;
+ else if ( xServiceInfo->supportsService(SERVICE_NAME_REPORT_COLLECTION) )
+ eRet = E_REPORT;
+ else
+ eRet = E_QUERY;
+ }
+ return eRet;
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.cxx b/dbaccess/source/ui/app/AppDetailPageHelper.cxx
new file mode 100644
index 000000000..b7506744d
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailPageHelper.cxx
@@ -0,0 +1,1221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppDetailPageHelper.hxx"
+#include <tools/diagnose_ex.h>
+#include <tabletree.hxx>
+#include <dbtreelistbox.hxx>
+#include <com/sun/star/awt/PopupMenu.hpp>
+#include <com/sun/star/awt/XTabController.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/frame/thePopupMenuControllerFactory.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/frame/Frame.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XFrames.hpp>
+#include <com/sun/star/frame/XFramesSupplier.hpp>
+#include <com/sun/star/frame/XPopupMenuController.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/ucb/Command.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <o3tl/string_view.hxx>
+#include "AppView.hxx"
+#include <helpids.h>
+#include <strings.hxx>
+#include <dbaccess_slotid.hrc>
+#include <databaseobjectview.hxx>
+#include <imageprovider.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <tools/stream.hxx>
+#include "AppController.hxx"
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <memory>
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdb::application;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star;
+using ::com::sun::star::awt::XTabController;
+
+namespace dbaui
+{
+ namespace DatabaseObject = css::sdb::application::DatabaseObject;
+ namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer;
+}
+
+namespace
+{
+ bool lcl_findEntry_impl(const TreeListBox& rTree, std::u16string_view rName, weld::TreeIter& rIter)
+ {
+ bool bReturn = false;
+ sal_Int32 nIndex = 0;
+ std::u16string_view sName( o3tl::getToken(rName,0,'/',nIndex) );
+
+ const weld::TreeView& rTreeView = rTree.GetWidget();
+ bool bEntry = true;
+ do
+ {
+ if (rTreeView.get_text(rIter) == sName)
+ {
+ if ( nIndex != -1 )
+ {
+ sName = o3tl::getToken(rName,0,'/',nIndex);
+ bEntry = rTreeView.iter_children(rIter);
+ }
+ else
+ {
+ bReturn = true;
+ break;
+ }
+ }
+ else
+ bEntry = rTreeView.iter_next_sibling(rIter);
+ }
+ while (bEntry);
+
+ return bReturn;
+ }
+
+ bool lcl_findEntry(const TreeListBox& rTree, std::u16string_view rName, weld::TreeIter& rIter)
+ {
+ sal_Int32 nIndex = 0;
+ std::u16string_view sErase = o3tl::getToken(rName,0,'/',nIndex); // we don't want to have the "private:forms" part
+ return nIndex != -1 && lcl_findEntry_impl(rTree, rName.substr(sErase.size() + 1), rIter);
+ }
+}
+
+OAppDetailPageHelper::OAppDetailPageHelper(weld::Container* pParent, OAppBorderWindow& rBorderWin, PreviewMode ePreviewMode)
+ : OChildWindow(pParent, "dbaccess/ui/detailwindow.ui", "DetailWindow")
+ , m_rBorderWin(rBorderWin)
+ , m_xBox(m_xBuilder->weld_container("box"))
+ , m_xFL(m_xBuilder->weld_widget("separator"))
+ , m_xMBPreview(m_xBuilder->weld_menu_button("disablepreview"))
+ , m_xPreview(new OPreviewWindow)
+ , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview))
+ , m_xDocumentInfo(new ODocumentInfoPreview)
+ , m_xDocumentInfoWin(new weld::CustomWeld(*m_xBuilder, "infopreview", *m_xDocumentInfo))
+ , m_xTablePreview(m_xBuilder->weld_container("tablepreview"))
+ , m_ePreviewMode(ePreviewMode)
+{
+ m_xContainer->set_stack_background();
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:DBDisablePreview",
+ "com.sun.star.sdb.OfficeDatabaseDocument");
+ m_xMBPreview->set_label(vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
+ m_xMBPreview->set_help_id(HID_APP_VIEW_PREVIEW_CB);
+
+ m_xMBPreview->connect_selected(LINK(this, OAppDetailPageHelper, MenuSelectHdl));
+ m_xMBPreview->connect_toggled(LINK(this, OAppDetailPageHelper, OnDropdownClickHdl));
+
+ m_xPreview->SetHelpId(HID_APP_VIEW_PREVIEW_1);
+
+ m_xTablePreview->set_help_id(HID_APP_VIEW_PREVIEW_2);
+ m_xDocumentInfo->SetHelpId(HID_APP_VIEW_PREVIEW_3);
+
+ m_xWindow = m_xTablePreview->CreateChildFrame();
+}
+
+OAppDetailPageHelper::~OAppDetailPageHelper()
+{
+ try
+ {
+ Reference< ::util::XCloseable> xCloseable(m_xFrame,UNO_QUERY);
+ if ( xCloseable.is() )
+ xCloseable->close(true);
+ m_xFrame.clear();
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "Exception thrown while disposing preview frame!");
+ }
+
+ for (auto& rpBox : m_aLists)
+ {
+ if (!rpBox)
+ continue;
+ rpBox.reset();
+ }
+
+ m_xWindow->dispose();
+ m_xWindow.clear();
+
+ m_xTablePreview.reset();
+ m_xDocumentInfoWin.reset();
+ m_xDocumentInfo.reset();
+ m_xPreviewWin.reset();
+ m_xPreview.reset();
+ m_xMBPreview.reset();
+ m_xFL.reset();
+ m_xBox.reset();
+}
+
+int OAppDetailPageHelper::getVisibleControlIndex() const
+{
+ int i = 0;
+ for (; i < E_ELEMENT_TYPE_COUNT ; ++i)
+ {
+ if (m_aLists[i] && m_aLists[i]->get_visible())
+ break;
+ }
+ return i;
+}
+
+void OAppDetailPageHelper::selectAll()
+{
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT)
+ {
+ m_aLists[nPos]->GetWidget().select_all();
+ }
+}
+
+void OAppDetailPageHelper::GrabFocus()
+{
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT)
+ m_aLists[nPos]->GetWidget().grab_focus();
+ else if (m_xMBPreview && m_xMBPreview->get_visible())
+ m_xMBPreview->grab_focus();
+}
+
+bool OAppDetailPageHelper::HasChildPathFocus() const
+{
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT && m_aLists[nPos]->GetWidget().has_focus())
+ return true;
+ return m_xMBPreview && m_xMBPreview->has_focus();
+}
+
+void OAppDetailPageHelper::sort(int nPos, bool bAscending)
+{
+ assert(m_aLists[nPos] && "List can not be NULL! ->GPF");
+ m_aLists[nPos]->GetWidget().set_sort_order(bAscending);
+}
+
+bool OAppDetailPageHelper::isSortUp() const
+{
+ bool bAscending = false;
+
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT)
+ bAscending = m_aLists[nPos]->GetWidget().get_sort_order();
+
+ return bAscending;
+}
+
+void OAppDetailPageHelper::sortDown()
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ sort(nPos, false);
+}
+
+void OAppDetailPageHelper::sortUp()
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ sort(nPos, true);
+}
+
+void OAppDetailPageHelper::getSelectionElementNames(std::vector<OUString>& rNames) const
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return;
+
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ sal_Int32 nCount = rTreeView.n_children();
+ rNames.reserve(nCount);
+ ElementType eType = getElementType();
+
+ rTreeView.selected_foreach([this, eType, &rTreeView, &rNames](weld::TreeIter& rEntry){
+ if ( eType == E_TABLE )
+ {
+ if (!rTreeView.iter_has_child(rEntry))
+ rNames.push_back(getQualifiedName(&rEntry));
+ }
+ else
+ {
+ OUString sName = rTreeView.get_text(rEntry);
+ std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
+ bool bParent = rTreeView.iter_parent(*xParent);
+ while (bParent)
+ {
+ sName = rTreeView.get_text(*xParent) + "/" + sName;
+ bParent = rTreeView.iter_parent(*xParent);
+ }
+ rNames.push_back(sName);
+ }
+
+ return false;
+ });
+}
+
+void OAppDetailPageHelper::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence< NamedDatabaseObject >& out_rSelectedObjects)
+{
+ for (size_t i=0; i < E_ELEMENT_TYPE_COUNT; ++i)
+ {
+ if (&m_aLists[i]->GetWidget() == &rControl)
+ {
+ describeCurrentSelectionForType(static_cast<ElementType>(i), out_rSelectedObjects);
+ return;
+ }
+ }
+ OSL_FAIL( "OAppDetailPageHelper::describeCurrentSelectionForControl: invalid control!" );
+}
+
+void OAppDetailPageHelper::describeCurrentSelectionForType(const ElementType eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects)
+{
+ OSL_ENSURE( eType < E_ELEMENT_TYPE_COUNT, "OAppDetailPageHelper::describeCurrentSelectionForType: invalid type!" );
+ DBTreeViewBase* pList = ( eType < E_ELEMENT_TYPE_COUNT ) ? m_aLists[eType].get() : nullptr;
+ OSL_ENSURE( pList, "OAppDetailPageHelper::describeCurrentSelectionForType: "
+ "You really should ensure this type has already been viewed before!" );
+ if ( !pList )
+ return;
+
+ std::vector< NamedDatabaseObject > aSelected;
+
+ weld::TreeView& rTreeView = pList->GetWidget();
+ rTreeView.selected_foreach([pList, eType, &rTreeView, &aSelected](weld::TreeIter& rEntry){
+ NamedDatabaseObject aObject;
+ switch (eType)
+ {
+ case E_TABLE:
+ {
+ OTableTreeListBox& rTableTree = static_cast<OTableTreeListBox&>(pList->getListBox());
+ aObject = rTableTree.describeObject(rEntry);
+ break;
+ }
+ case E_QUERY:
+ aObject.Type = DatabaseObject::QUERY;
+ aObject.Name = rTreeView.get_text(rEntry);
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ OUString sName = rTreeView.get_text(rEntry);
+ std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
+ bool bParent = rTreeView.iter_parent(*xParent);
+ while (bParent)
+ {
+ sName = rTreeView.get_text(*xParent) + "/" + sName;
+ bParent = rTreeView.iter_parent(*xParent);
+ }
+
+ if (isLeaf(rTreeView, rEntry))
+ aObject.Type = (eType == E_FORM) ? DatabaseObject::FORM : DatabaseObject::REPORT;
+ else
+ aObject.Type = (eType == E_FORM) ? DatabaseObjectContainer::FORMS_FOLDER : DatabaseObjectContainer::REPORTS_FOLDER;
+ aObject.Name = sName;
+ break;
+ }
+ default:
+ OSL_FAIL( "OAppDetailPageHelper::describeCurrentSelectionForType: unexpected type!" );
+ break;
+ }
+
+ if (!aObject.Name.isEmpty())
+ aSelected.push_back(aObject);
+
+ return false;
+ });
+
+ _out_rSelectedObjects = comphelper::containerToSequence(aSelected);
+}
+
+vcl::Window* OAppDetailPageHelper::getMenuParent() const
+{
+ return &m_rBorderWin;
+}
+
+void OAppDetailPageHelper::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ int x, y, width, height;
+ if (rControl.get_extents_relative_to(m_rBorderWin.getTopLevel(), x, y, width, height))
+ {
+ rPos.AdjustX(x);
+ rPos.AdjustY(y);
+ }
+}
+
+void OAppDetailPageHelper::selectElements(const Sequence< OUString>& _aNames)
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return;
+
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ rTreeView.unselect_all();
+ const OUString* pIter = _aNames.getConstArray();
+ const OUString* pEnd = pIter + _aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ auto xEntry = rTree.getListBox().GetEntryPosByName(*pIter);
+ if (!xEntry)
+ continue;
+ rTreeView.select(*xEntry);
+ }
+}
+
+OUString OAppDetailPageHelper::getQualifiedName(const weld::TreeIter* _pEntry) const
+{
+ int nPos = getVisibleControlIndex();
+ OUString sComposedName;
+
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return sComposedName;
+
+ OSL_ENSURE(m_aLists[nPos],"Tables tree view is NULL! -> GPF");
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(_pEntry));
+ if (!_pEntry)
+ {
+ if (!rTreeView.get_selected(xEntry.get()))
+ xEntry.reset();
+ }
+
+ if (!xEntry)
+ return sComposedName;
+
+ if ( getElementType() == E_TABLE )
+ {
+ const OTableTreeListBox& rTableTreeListBox = static_cast<const OTableTreeListBox&>(m_aLists[nPos]->getListBox());
+ sComposedName = rTableTreeListBox.getQualifiedTableName(*xEntry);
+ }
+ else
+ {
+ sComposedName = rTreeView.get_text(*xEntry);
+ bool bParent = rTreeView.iter_parent(*xEntry);
+ while (bParent)
+ {
+ sComposedName = rTreeView.get_text(*xEntry) + "/" + sComposedName;
+ bParent = rTreeView.iter_parent(*xEntry);
+ }
+ }
+
+ return sComposedName;
+}
+
+ElementType OAppDetailPageHelper::getElementType() const
+{
+ int nPos = getVisibleControlIndex();
+ return static_cast<ElementType>(nPos);
+}
+
+sal_Int32 OAppDetailPageHelper::getSelectionCount()
+{
+ sal_Int32 nCount = 0;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ nCount = rTreeView.count_selected_rows();
+ }
+ return nCount;
+}
+
+sal_Int32 OAppDetailPageHelper::getElementCount() const
+{
+ sal_Int32 nCount = 0;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ nCount = rTreeView.n_children();
+ }
+ return nCount;
+}
+
+bool OAppDetailPageHelper::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry)
+{
+ sal_Int32 nEntryType = rTreeView.get_id(rEntry).toInt32();
+ return !( ( nEntryType == DatabaseObjectContainer::TABLES )
+ || ( nEntryType == DatabaseObjectContainer::CATALOG )
+ || ( nEntryType == DatabaseObjectContainer::SCHEMA )
+ || ( nEntryType == DatabaseObjectContainer::FORMS_FOLDER )
+ || ( nEntryType == DatabaseObjectContainer::REPORTS_FOLDER ));
+}
+
+bool OAppDetailPageHelper::isALeafSelected() const
+{
+ int nPos = getVisibleControlIndex();
+ bool bLeafSelected = false;
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ rTreeView.selected_foreach([&rTreeView, &bLeafSelected](weld::TreeIter& rEntry){
+ bLeafSelected = isLeaf(rTreeView, rEntry);
+ return bLeafSelected;
+ });
+ }
+ return bLeafSelected;
+}
+
+std::unique_ptr<weld::TreeIter> OAppDetailPageHelper::getEntry( const Point& _aPosPixel) const
+{
+ std::unique_ptr<weld::TreeIter> xReturn;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ xReturn = rTreeView.make_iterator();
+ if (!rTreeView.get_dest_row_at_pos(_aPosPixel, xReturn.get(), false))
+ xReturn.reset();
+ }
+ return xReturn;
+}
+
+void OAppDetailPageHelper::createTablesPage(const Reference< XConnection>& _xConnection)
+{
+ OSL_ENSURE(_xConnection.is(),"Connection is NULL! -> GPF");
+
+ if ( !m_aLists[E_TABLE] )
+ {
+ m_aLists[E_TABLE].reset(new DBTableTreeView(m_xBox.get()));
+ setupTree(*m_aLists[E_TABLE]);
+ m_aLists[E_TABLE]->GetWidget().set_help_id(HID_APP_TABLE_TREE);
+ }
+
+ weld::TreeView& rTreeView = m_aLists[E_TABLE]->GetWidget();
+ if (!rTreeView.n_children())
+ {
+ static_cast<OTableTreeListBox&>(m_aLists[E_TABLE]->getListBox()).UpdateTableList(_xConnection);
+
+ std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xFirst))
+ rTreeView.expand_row(*xFirst);
+ rTreeView.unselect_all();
+ }
+
+ setDetailPage(*m_aLists[E_TABLE]);
+}
+
+OUString OAppDetailPageHelper::getElementIcons(ElementType _eType)
+{
+ sal_Int32 nDatabaseObjectType( 0 );
+ switch(_eType )
+ {
+ case E_FORM: nDatabaseObjectType = DatabaseObject::FORM; break;
+ case E_REPORT: nDatabaseObjectType = DatabaseObject::REPORT; break;
+ case E_QUERY: nDatabaseObjectType = DatabaseObject::QUERY; break;
+ default:
+ OSL_FAIL( "OAppDetailPageHelper::GetElementIcons: invalid element type!" );
+ return OUString();
+ }
+
+ return ImageProvider::getDefaultImageResourceID(nDatabaseObjectType);
+}
+
+void OAppDetailPageHelper::createPage(ElementType _eType,const Reference< XNameAccess >& _xContainer)
+{
+ OSL_ENSURE(E_TABLE != _eType,"E_TABLE isn't allowed.");
+
+ OString sHelpId;
+ switch( _eType )
+ {
+ case E_FORM:
+ sHelpId = HID_APP_FORM_TREE;
+ break;
+ case E_REPORT:
+ sHelpId = HID_APP_REPORT_TREE;
+ break;
+ case E_QUERY:
+ sHelpId = HID_APP_QUERY_TREE;
+ break;
+ default:
+ OSL_FAIL("Illegal call!");
+ }
+ OUString sImageId = getElementIcons(_eType);
+
+ if ( !m_aLists[_eType] )
+ {
+ m_aLists[_eType] = createSimpleTree(sHelpId, _eType);
+ }
+
+ if ( !m_aLists[_eType] )
+ return;
+
+ weld::TreeView& rTreeView = m_aLists[_eType]->GetWidget();
+ if (!rTreeView.n_children() && _xContainer.is())
+ {
+ rTreeView.make_unsorted();
+ fillNames( _xContainer, _eType, sImageId, nullptr );
+ rTreeView.make_sorted();
+
+ rTreeView.unselect_all();
+ }
+ setDetailPage(*m_aLists[_eType]);
+}
+
+void OAppDetailPageHelper::setDetailPage(DBTreeViewBase& rTreeView)
+{
+ bool bHasFocus = false;
+
+ DBTreeViewBase* pCurrent = getCurrentView();
+ if (pCurrent)
+ {
+ weld::Widget& rCurrent = pCurrent->GetWidget();
+ bHasFocus = rCurrent.has_focus();
+ pCurrent->hide();
+ }
+
+ showPreview(nullptr);
+ m_xFL->show();
+ rTreeView.show();
+ m_xMBPreview->show();
+ switchPreview(m_ePreviewMode,true);
+
+ if (bHasFocus)
+ rTreeView.GetWidget().grab_focus();
+}
+
+namespace
+{
+ namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer;
+
+ sal_Int32 lcl_getFolderIndicatorForType( const ElementType _eType )
+ {
+ const sal_Int32 nFolderIndicator =
+ ( _eType == E_FORM ) ? DatabaseObjectContainer::FORMS_FOLDER
+ : ( _eType == E_REPORT ) ? DatabaseObjectContainer::REPORTS_FOLDER : -1;
+ return nFolderIndicator;
+ }
+}
+
+void OAppDetailPageHelper::fillNames( const Reference< XNameAccess >& _xContainer, const ElementType _eType,
+ const OUString& rImageId, const weld::TreeIter* _pParent )
+{
+ OSL_ENSURE(_xContainer.is(),"Data source is NULL! -> GPF");
+ OSL_ENSURE( ( _eType >= E_TABLE ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OAppDetailPageHelper::fillNames: invalid type!" );
+
+ DBTreeViewBase* pList = m_aLists[_eType].get();
+ OSL_ENSURE( pList, "OAppDetailPageHelper::fillNames: you really should create the list before calling this!" );
+ if ( !pList )
+ return;
+
+ if ( !(_xContainer.is() && _xContainer->hasElements()) )
+ return;
+
+ weld::TreeView& rTreeView = pList->GetWidget();
+
+ std::unique_ptr<weld::TreeIter> xRet = rTreeView.make_iterator();
+ const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType );
+
+ Sequence< OUString> aSeq = _xContainer->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ Reference<XNameAccess> xSubElements(_xContainer->getByName(*pIter),UNO_QUERY);
+ if ( xSubElements.is() )
+ {
+ OUString sId(OUString::number(nFolderIndicator));
+
+ rTreeView.insert(_pParent, -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, *pIter, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ getBorderWin().getView()->getAppController().containerFound( Reference< XContainer >( xSubElements, UNO_QUERY ) );
+ fillNames( xSubElements, _eType, rImageId, xRet.get());
+ }
+ else
+ {
+ rTreeView.insert(_pParent, -1, nullptr, nullptr, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, *pIter, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ rTreeView.set_image(*xRet, rImageId);
+ }
+ }
+}
+
+std::unique_ptr<DBTreeViewBase> OAppDetailPageHelper::createSimpleTree(const OString& rHelpId, ElementType eType)
+{
+ const bool bSQLType = eType == E_TABLE || eType == E_QUERY;
+ std::unique_ptr<DBTreeViewBase> xTreeView(new DBTreeView(m_xBox.get(), bSQLType));
+ xTreeView->GetWidget().set_help_id(rHelpId);
+ setupTree(*xTreeView);
+ return xTreeView;
+}
+
+void OAppDetailPageHelper::setupTree(DBTreeViewBase& rDBTreeView)
+{
+ weld::WaitObject aWaitCursor(m_rBorderWin.GetFrameWeld());
+
+ rDBTreeView.getListBox().setCopyHandler(LINK(this, OAppDetailPageHelper, OnCopyEntry));
+ rDBTreeView.getListBox().setPasteHandler(LINK(this, OAppDetailPageHelper, OnPasteEntry));
+ rDBTreeView.getListBox().setDeleteHandler(LINK(this, OAppDetailPageHelper, OnDeleteEntry));
+
+ weld::TreeView& rTreeView = rDBTreeView.GetWidget();
+ rTreeView.make_sorted();
+ rTreeView.set_selection_mode(SelectionMode::Multiple);
+ // an arbitrary small size it's allowed to shrink to
+ rTreeView.set_size_request(42, 42);
+
+ rTreeView.connect_row_activated(LINK(this, OAppDetailPageHelper, OnEntryDoubleClick));
+
+ rDBTreeView.getListBox().SetSelChangeHdl(LINK(this, OAppDetailPageHelper, OnEntrySelChange));
+
+ rDBTreeView.getListBox().setControlActionListener(&getBorderWin().getView()->getAppController());
+ rDBTreeView.getListBox().setContextMenuProvider(&getBorderWin().getView()->getAppController());
+}
+
+void OAppDetailPageHelper::clearPages()
+{
+ showPreview(nullptr);
+ for (auto& rpBox : m_aLists)
+ {
+ if ( rpBox )
+ rpBox->GetWidget().clear();
+ }
+}
+
+bool OAppDetailPageHelper::isFilled() const
+{
+ size_t i = 0;
+ for (; i < E_ELEMENT_TYPE_COUNT && !m_aLists[i]; ++i)
+ ;
+ return i != E_ELEMENT_TYPE_COUNT;
+}
+
+void OAppDetailPageHelper::elementReplaced(ElementType eType,
+ const OUString& rOldName,
+ const OUString& rNewName)
+{
+ DBTreeViewBase* pTreeView = getCurrentView();
+ if (!pTreeView)
+ return;
+
+ weld::TreeView& rTreeView = pTreeView->GetWidget();
+ rTreeView.make_unsorted();
+
+ switch (eType)
+ {
+ case E_TABLE:
+ static_cast<OTableTreeListBox&>(pTreeView->getListBox()).removedTable(rOldName);
+ static_cast<OTableTreeListBox&>(pTreeView->getListBox()).addedTable(rNewName);
+ break;
+ case E_QUERY:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry_impl(pTreeView->getListBox(), rOldName, *xIter))
+ rTreeView.set_text(*xIter, rNewName);
+ break;
+ }
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), rOldName, *xIter))
+ rTreeView.set_text(*xIter, rNewName);
+ break;
+ }
+ default:
+ OSL_FAIL("Invalid element type");
+ }
+
+ rTreeView.make_sorted();
+}
+
+std::unique_ptr<weld::TreeIter> OAppDetailPageHelper::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject )
+{
+ std::unique_ptr<weld::TreeIter> xRet;
+ DBTreeViewBase* pTreeView = m_aLists[_eType].get();
+ if (!pTreeView)
+ return xRet;
+ weld::TreeView& rTreeView = pTreeView->GetWidget();
+ rTreeView.make_unsorted();
+ if (_eType == E_TABLE)
+ {
+ xRet = static_cast<OTableTreeListBox&>(pTreeView->getListBox()).addedTable( _rName );
+ }
+ else
+ {
+ std::unique_ptr<weld::TreeIter> xEntry;
+ Reference<XChild> xChild(_rObject,UNO_QUERY);
+ if ( xChild.is() && E_QUERY != _eType )
+ {
+ Reference<XContent> xContent(xChild->getParent(),UNO_QUERY);
+ if ( xContent.is() )
+ {
+ OUString sName = xContent->getIdentifier()->getContentIdentifier();
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), sName, *xIter))
+ xEntry = std::move(xIter);
+ }
+ }
+
+ OUString sImageId = getElementIcons(_eType);
+ Reference<XNameAccess> xContainer(_rObject,UNO_QUERY);
+ if ( xContainer.is() )
+ {
+ const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType );
+ OUString sId(OUString::number(nFolderIndicator));
+
+ xRet = rTreeView.make_iterator();
+ rTreeView.insert(xEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, _rName, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ fillNames(xContainer, _eType, sImageId, xRet.get());
+ }
+ else
+ {
+ xRet = rTreeView.make_iterator();
+ rTreeView.insert(xEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, _rName, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ rTreeView.set_image(*xRet, sImageId);
+ }
+ }
+ rTreeView.make_sorted();
+ return xRet;
+}
+
+void OAppDetailPageHelper::elementRemoved( ElementType _eType,const OUString& _rName )
+{
+ DBTreeViewBase* pTreeView = getCurrentView();
+ if ( !pTreeView )
+ return;
+
+ weld::TreeView& rTreeView = pTreeView->GetWidget();
+
+ switch( _eType )
+ {
+ case E_TABLE:
+ // we don't need to clear the table here, it is already done by the dispose listener
+ static_cast<OTableTreeListBox&>(pTreeView->getListBox()).removedTable(_rName);
+ break;
+ case E_QUERY:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry_impl(pTreeView->getListBox(), _rName, *xIter))
+ rTreeView.remove(*xIter);
+ break;
+ }
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), _rName, *xIter))
+ rTreeView.remove(*xIter);
+ break;
+ }
+ default:
+ OSL_FAIL("Invalid element type");
+ }
+ if (!rTreeView.n_children())
+ showPreview(nullptr);
+}
+
+IMPL_LINK(OAppDetailPageHelper, OnEntryDoubleClick, weld::TreeView&, rTreeView, bool)
+{
+ return getBorderWin().getView()->getAppController().onEntryDoubleClick(rTreeView);
+}
+
+IMPL_LINK_NOARG(OAppDetailPageHelper, OnEntrySelChange, LinkParamNone*, void)
+{
+ getBorderWin().getView()->getAppController().onSelectionChanged();
+}
+
+IMPL_LINK_NOARG( OAppDetailPageHelper, OnCopyEntry, LinkParamNone*, void )
+{
+ getBorderWin().getView()->getAppController().onCopyEntry();
+}
+
+IMPL_LINK_NOARG( OAppDetailPageHelper, OnPasteEntry, LinkParamNone*, void )
+{
+ getBorderWin().getView()->getAppController().onPasteEntry();
+}
+
+IMPL_LINK_NOARG( OAppDetailPageHelper, OnDeleteEntry, LinkParamNone*, void )
+{
+ getBorderWin().getView()->getAppController().onDeleteEntry();
+}
+
+bool OAppDetailPageHelper::isPreviewEnabled() const
+{
+ return m_ePreviewMode != E_PREVIEWNONE;
+}
+
+namespace
+{
+ OUString stripTrailingDots(std::u16string_view rStr)
+ {
+ return OUString(comphelper::string::stripEnd(rStr, '.'));
+ }
+}
+
+void OAppDetailPageHelper::switchPreview(PreviewMode _eMode,bool _bForce)
+{
+ if ( !(m_ePreviewMode != _eMode || _bForce) )
+ return;
+
+ m_ePreviewMode = _eMode;
+
+ getBorderWin().getView()->getAppController().previewChanged(static_cast<sal_Int32>(m_ePreviewMode));
+
+ OUString aCommand;
+ switch ( m_ePreviewMode )
+ {
+ case E_PREVIEWNONE:
+ aCommand = ".uno:DBDisablePreview";
+ break;
+ case E_DOCUMENT:
+ aCommand = ".uno:DBShowDocPreview";
+ break;
+ case E_DOCUMENTINFO:
+ if ( getBorderWin().getView()->getAppController().isCommandEnabled(SID_DB_APP_VIEW_DOCINFO_PREVIEW) )
+ aCommand = ".uno:DBShowDocInfoPreview";
+ else
+ {
+ m_ePreviewMode = E_PREVIEWNONE;
+ aCommand = ".uno:DBDisablePreview";
+ }
+ break;
+ }
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, "com.sun.star.sdb.OfficeDatabaseDocument");
+ OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+ m_xMBPreview->set_label(stripTrailingDots(aCommandLabel));
+
+ // simulate a selectionChanged event at the controller, to force the preview to be updated
+ if ( isPreviewEnabled() )
+ {
+ DBTreeViewBase* pCurrent = getCurrentView();
+ if (pCurrent && pCurrent->GetWidget().get_selected(nullptr))
+ {
+ getBorderWin().getView()->getAppController().onSelectionChanged();
+ }
+ }
+ else
+ {
+ m_xTablePreview->hide();
+ m_xPreview->Hide();
+ m_xDocumentInfo->Hide();
+ }
+}
+
+void OAppDetailPageHelper::showPreview(const Reference< XContent >& _xContent)
+{
+ if ( !isPreviewEnabled() )
+ return;
+
+ m_xTablePreview->hide();
+
+ weld::WaitObject aWaitCursor(m_rBorderWin.GetFrameWeld());
+ try
+ {
+ Reference<XCommandProcessor> xContent(_xContent,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ css::ucb::Command aCommand;
+ if ( m_ePreviewMode == E_DOCUMENT )
+ aCommand.Name = "preview";
+ else
+ aCommand.Name = "getDocumentInfo";
+
+ Any aPreview = xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >());
+ if ( m_ePreviewMode == E_DOCUMENT )
+ {
+ m_xDocumentInfo->Hide();
+ m_xPreview->Show();
+
+ Graphic aGraphic;
+ Sequence < sal_Int8 > aBmpSequence;
+ if ( aPreview >>= aBmpSequence )
+ {
+ SvMemoryStream aData( aBmpSequence.getArray(),
+ aBmpSequence.getLength(),
+ StreamMode::READ );
+
+ GraphicConverter::Import(aData,aGraphic);
+ }
+ m_xPreview->setGraphic( aGraphic );
+ m_xPreview->Invalidate();
+ }
+ else
+ {
+ m_xPreview->Hide();
+ m_xDocumentInfo->clear();
+ m_xDocumentInfo->Show();
+ Reference<document::XDocumentProperties> xProp(
+ aPreview, UNO_QUERY);
+ if ( xProp.is() )
+ m_xDocumentInfo->fill(xProp);
+ }
+ }
+ else
+ {
+ m_xPreview->Hide();
+ m_xDocumentInfo->Hide();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OAppDetailPageHelper::showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable)
+{
+ if ( !isPreviewEnabled() )
+ return;
+
+ weld::WaitObject aWaitCursor(m_rBorderWin.GetFrameWeld());
+ m_xPreview->Hide();
+ m_xDocumentInfo->Hide();
+ m_xTablePreview->show();
+ if ( !m_xFrame.is() )
+ {
+ try
+ {
+ m_xFrame = Frame::create( getBorderWin().getView()->getORB() );
+ m_xFrame->initialize( m_xWindow );
+
+ // no layout manager (and thus no toolbars) in the preview
+ // Must be called after initialize ... but before any other call to this frame.
+ // Otherwise frame throws "life time exceptions" as e.g. NON_INITIALIZED
+ m_xFrame->setLayoutManager( Reference< XLayoutManager >() );
+
+ Reference<XFramesSupplier> xSup(getBorderWin().getView()->getAppController().getXController()->getFrame(),UNO_QUERY);
+ if ( xSup.is() )
+ {
+ Reference<XFrames> xFrames = xSup->getFrames();
+ xFrames->append( Reference<XFrame>(m_xFrame,UNO_QUERY_THROW));
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+
+ Reference< XDatabaseDocumentUI > xApplication( getBorderWin().getView()->getAppController().getXController(), UNO_QUERY );
+ std::unique_ptr< DatabaseObjectView > pDispatcher( new ResultSetBrowser(
+ getBorderWin().getView()->getORB(),
+ xApplication, nullptr, _bTable
+ ) );
+ pDispatcher->setTargetFrame( Reference<XFrame>(m_xFrame,UNO_QUERY_THROW) );
+
+ ::comphelper::NamedValueCollection aArgs;
+ aArgs.put( "Preview", true );
+ aArgs.put( "ReadOnly", true );
+ aArgs.put( "AsTemplate", false );
+ aArgs.put( PROPERTY_SHOWMENU, false );
+
+ Reference< XController > xPreview( pDispatcher->openExisting( Any( _sDataSourceName ), _sName, aArgs ), UNO_QUERY );
+ bool bClearPreview = !xPreview.is();
+
+ // clear the preview when the query or table could not be loaded
+ if ( !bClearPreview )
+ {
+ Reference< XTabController > xTabController( xPreview, UNO_QUERY );
+ bClearPreview = !xTabController.is();
+ if ( !bClearPreview )
+ {
+ Reference< XLoadable > xLoadable( xTabController->getModel(), UNO_QUERY );
+ bClearPreview = !( xLoadable.is() && xLoadable->isLoaded() );
+ }
+ }
+ if ( bClearPreview )
+ showPreview(nullptr);
+}
+
+namespace
+{
+ class MenuStatusListener final : public ::cppu::WeakImplHelper<css::frame::XStatusListener>
+ {
+ weld::MenuButton& m_rMBPreview;
+ public:
+ MenuStatusListener(weld::MenuButton& rMBPreview)
+ : m_rMBPreview(rMBPreview)
+ {
+ }
+
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent &rEvent) override
+ {
+ if (!rEvent.IsEnabled)
+ {
+ const OUString &rURL = rEvent.FeatureURL.Complete;
+ m_rMBPreview.remove_item(rURL.toUtf8());
+ }
+ }
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& /*rSource*/) override
+ {
+ }
+ };
+};
+
+IMPL_LINK_NOARG(OAppDetailPageHelper, OnDropdownClickHdl, weld::Toggleable&, void)
+{
+ if (!m_xMBPreview->get_active())
+ return;
+
+ m_xMBPreview->clear();
+
+ // execute the menu
+ css::uno::Reference<css::uno::XComponentContext> xContext(getBorderWin().getView()->getORB());
+ css::uno::Reference<css::frame::XUIControllerFactory> xPopupMenuFactory(css::frame::thePopupMenuControllerFactory::get(xContext));
+ if (!xPopupMenuFactory.is())
+ return;
+
+ auto xFrame = getBorderWin().getView()->getAppController().getFrame();
+
+ css::uno::Sequence<css::uno::Any> aArgs {
+ css::uno::Any(comphelper::makePropertyValue("InToolbar", true)),
+ css::uno::Any(comphelper::makePropertyValue("ModuleIdentifier", OUString("com.sun.star.sdb.OfficeDatabaseDocument"))),
+ css::uno::Any(comphelper::makePropertyValue("Frame", xFrame)) };
+
+ css::uno::Reference<css::frame::XPopupMenuController> xPopupController
+ (xPopupMenuFactory->createInstanceWithArgumentsAndContext(".uno:DBPreview", aArgs, xContext), css::uno::UNO_QUERY);
+
+ if (!xPopupController.is())
+ return;
+
+ css::uno::Reference<css::awt::XPopupMenu> xPopupMenu(css::awt::PopupMenu::create(xContext));
+ xPopupController->setPopupMenu(xPopupMenu);
+
+ css::util::URL aTargetURL;
+ Reference<XDispatchProvider> xDispatchProvider(xFrame, css::uno::UNO_QUERY);
+
+ css::uno::Reference<css::frame::XStatusListener> xStatusListener(new MenuStatusListener(*m_xMBPreview));
+
+ for (int i = 0, nCount = xPopupMenu->getItemCount(); i < nCount; ++i)
+ {
+ auto nItemId = xPopupMenu->getItemId(i);
+ // in practice disabled items are initially enabled so this doesn't have an effect and
+ // an status update is needed to query the enabled/disabled state
+ if (!xPopupMenu->isItemEnabled(nItemId))
+ continue;
+
+ aTargetURL.Complete = xPopupMenu->getCommand(nItemId);
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aTargetURL.Complete,
+ "com.sun.star.sdb.OfficeDatabaseDocument");
+ m_xMBPreview->append_item(aTargetURL.Complete, vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
+
+ // Add/remove status listener to get a status update once so we can remove any disabled items from the menu
+ auto xDispatch = xDispatchProvider->queryDispatch(aTargetURL, "_self",
+ css::frame::FrameSearchFlag::SELF);
+ if (xDispatch.is())
+ {
+ xDispatch->addStatusListener(xStatusListener, aTargetURL);
+ xDispatch->removeStatusListener(xStatusListener, aTargetURL);
+ }
+ }
+
+ css::uno::Reference<css::lang::XComponent> xComponent(xPopupController, css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+IMPL_LINK(OAppDetailPageHelper, MenuSelectHdl, const OString&, rIdent, void)
+{
+ if (rIdent.isEmpty())
+ return;
+
+ css::util::URL aURL;
+ aURL.Complete = OUString::fromUtf8(rIdent);
+
+ Reference<XDispatchProvider> xProvider(getBorderWin().getView()->getAppController().getFrame(), UNO_QUERY);
+ Reference<XDispatch> xDisp = xProvider->queryDispatch(aURL, "_self", 0);
+ xDisp->dispatch(aURL, css::uno::Sequence<css::beans::PropertyValue>());
+
+ m_xMBPreview->set_label(stripTrailingDots(m_xMBPreview->get_item_label(rIdent)));
+}
+
+OPreviewWindow::OPreviewWindow()
+{
+}
+
+bool OPreviewWindow::ImplGetGraphicCenterRect(const vcl::RenderContext& rRenderContext, const Graphic& rGraphic, tools::Rectangle& rResultRect) const
+{
+ const Size aWinSize( GetOutputSizePixel() );
+ Size aNewSize(rRenderContext.LogicToPixel(rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode()));
+ bool bRet = false;
+
+ if( aNewSize.Width() && aNewSize.Height() )
+ {
+ // scale to fit window
+ const double fGrfWH = static_cast<double>(aNewSize.Width()) / aNewSize.Height();
+ const double fWinWH = static_cast<double>(aWinSize.Width()) / aWinSize.Height();
+
+ if ( fGrfWH < fWinWH )
+ {
+ aNewSize.setWidth( static_cast<tools::Long>( aWinSize.Height() * fGrfWH ) );
+ aNewSize.setHeight( aWinSize.Height() );
+ }
+ else
+ {
+ aNewSize.setWidth( aWinSize.Width() );
+ aNewSize.setHeight( static_cast<tools::Long>( aWinSize.Width() / fGrfWH) );
+ }
+
+ const Point aNewPos( ( aWinSize.Width() - aNewSize.Width() ) >> 1,
+ ( aWinSize.Height() - aNewSize.Height() ) >> 1 );
+
+ rResultRect = tools::Rectangle( aNewPos, aNewSize );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void OPreviewWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+{
+ if (ImplGetGraphicCenterRect(rRenderContext, m_aGraphicObj.GetGraphic(), m_aPreviewRect))
+ {
+ const Point aPos(m_aPreviewRect.TopLeft());
+ const Size aSize(m_aPreviewRect.GetSize());
+
+ if (m_aGraphicObj.IsAnimated())
+ m_aGraphicObj.StartAnimation(rRenderContext, aPos, aSize);
+ else
+ m_aGraphicObj.Draw(rRenderContext, aPos, aSize);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.hxx b/dbaccess/source/ui/app/AppDetailPageHelper.hxx
new file mode 100644
index 000000000..25cc3229a
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailPageHelper.hxx
@@ -0,0 +1,349 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <vcl/graph.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+#include <AppElementType.hxx>
+#include <ChildWindow.hxx>
+#include "DocumentInfoPreview.hxx"
+
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::frame { class XFrame2; }
+namespace com::sun::star::io { class XPersist; }
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class ODocumentInfoPreview;
+ class DBTreeViewBase;
+ class TreeListBox;
+
+ class OPreviewWindow final : public weld::CustomWidgetController
+ {
+ GraphicObject m_aGraphicObj;
+ tools::Rectangle m_aPreviewRect;
+
+ /** gets the graphic center rect
+ @param rRenderContext
+ the context to which we are drawing
+ @param rGraphic
+ the graphic
+ @param rResultRect
+ the resulting rectangle
+
+ @return
+ <TRUE/> when successful
+ */
+ bool ImplGetGraphicCenterRect(const vcl::RenderContext& rRenderContext, const Graphic& rGraphic, tools::Rectangle& rResultRect) const;
+
+ public:
+ OPreviewWindow();
+
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+
+ void setGraphic(const Graphic& _rGraphic ) { m_aGraphicObj.SetGraphic(_rGraphic); }
+ };
+
+ // A helper class for the controls in the detail page.
+ // Combines general functionality.
+ class OAppDetailPageHelper final : public OChildWindow
+ {
+ std::unique_ptr<DBTreeViewBase> m_aLists[size_t(E_ELEMENT_TYPE_COUNT)];
+ OAppBorderWindow& m_rBorderWin;
+ std::unique_ptr<weld::Container> m_xBox;
+ std::unique_ptr<weld::Widget> m_xFL;
+ std::unique_ptr<weld::MenuButton> m_xMBPreview;
+
+ std::unique_ptr<OPreviewWindow> m_xPreview;
+ std::unique_ptr<weld::CustomWeld> m_xPreviewWin;
+
+ std::unique_ptr<ODocumentInfoPreview> m_xDocumentInfo;
+ std::unique_ptr<weld::CustomWeld> m_xDocumentInfoWin;
+
+ std::unique_ptr<weld::Container> m_xTablePreview;
+
+ PreviewMode m_ePreviewMode;
+ css::uno::Reference < css::frame::XFrame2 >
+ m_xFrame;
+ css::uno::Reference< css::awt::XWindow >
+ m_xWindow;
+
+ /// returns the index of the visible control
+ int getVisibleControlIndex() const;
+
+ /** sorts the entries in the tree list box.
+ @param nPos
+ Which list should be sorted.
+ @param bAscending
+ If sort should be Ascending of Descending
+ */
+ void sort(int nPos, bool bAscending);
+
+ /** retrieves the resource ids of the images representing elements of the given type
+ */
+ static OUString getElementIcons(ElementType _eType);
+
+ /** fills the names in the listbox
+ @param _xContainer
+ This can either be the queries, forms or report names.
+ @param _eType
+ the type of elements which are being filled
+ @param _nImageId
+ the resource id of the image to use for non-container entries
+ @param _pParent
+ The parent of the entries to be inserted.
+ */
+ void fillNames( const css::uno::Reference< css::container::XNameAccess >& _xContainer,
+ const ElementType _eType,
+ const OUString& rImageId,
+ const weld::TreeIter* _pParent );
+
+ /** sets the detail page
+ @param rTreeView
+ The control which should be visible.
+ */
+ void setDetailPage(DBTreeViewBase& rTreeView);
+
+ /** sets all HandleCallbacks
+ @param rTreeView
+ The newly created DBTreeViewBase
+ */
+ void setupTree(DBTreeViewBase& rTreeView);
+
+ /** creates the tree and sets all HandleCallbacks
+ @param nHelpId
+ The help id of the control
+ @param eType
+ The element type of the control
+ @return
+ The new tree.
+ */
+ std::unique_ptr<DBTreeViewBase> createSimpleTree(const OString& rHelpId, ElementType eType);
+
+ DECL_LINK( OnEntryDoubleClick, weld::TreeView&, bool );
+ DECL_LINK( OnEntrySelChange, LinkParamNone*, void );
+
+ DECL_LINK( OnCopyEntry, LinkParamNone*, void );
+ DECL_LINK( OnPasteEntry, LinkParamNone*, void );
+ DECL_LINK( OnDeleteEntry, LinkParamNone*, void );
+
+ DECL_LINK(OnDropdownClickHdl, weld::Toggleable&, void);
+ DECL_LINK(MenuSelectHdl, const OString&, void);
+
+ OAppBorderWindow& getBorderWin() const { return m_rBorderWin; }
+
+ public:
+ OAppDetailPageHelper(weld::Container* pParent, OAppBorderWindow& rBorderWin, PreviewMode ePreviewMode);
+ virtual ~OAppDetailPageHelper() override;
+
+ virtual void GrabFocus() override;
+ virtual bool HasChildPathFocus() const override;
+
+ /** creates the tables page
+ @param _xConnection
+ The connection to get the table names
+ */
+ void createTablesPage(const css::uno::Reference< css::sdbc::XConnection>& _xConnection);
+
+ /** creates the page for the specific type.
+ @param _eType
+ The type which should be created. E_TABLE isn't allowed.
+ @param _xContainer
+ The container of the elements to be inserted.
+ */
+ void createPage(ElementType _eType,const css::uno::Reference< css::container::XNameAccess >& _xContainer);
+
+ /** returns the current visible tree list box
+ */
+ DBTreeViewBase* getCurrentView() const
+ {
+ ElementType eType = getElementType();
+ return (eType != E_NONE ) ? m_aLists[static_cast<sal_Int32>(eType)].get() : nullptr;
+ }
+
+ /// select all entries in the visible control
+ void selectAll();
+
+ /// returns <TRUE/> if it sorts ascending
+ bool isSortUp() const;
+
+ /// sorts all entries ascending
+ void sortDown();
+
+ /// sorts all entries descending
+ void sortUp();
+
+ /** returns the element names which are selected
+ @param _rNames
+ The list will be filled.
+ */
+ void getSelectionElementNames( std::vector< OUString>& _rNames ) const;
+
+ /** describes the current selection for the given control
+ */
+ void describeCurrentSelectionForControl(
+ const weld::TreeView& rControl,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** describes the current selection for the given ElementType
+ */
+ void describeCurrentSelectionForType(
+ const ElementType _eType,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** get the menu parent window for the given control
+ */
+ vcl::Window* getMenuParent() const;
+ void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const;
+
+ /** select all names on the currently selected container. Non existence names where ignored.
+ *
+ * \param _aNames the element names
+ */
+ void selectElements(const css::uno::Sequence< OUString>& _aNames);
+
+ /** return the qualified name.
+ @param _pEntry
+ The entry of a table, or query, form, report to get the qualified name.
+ If the entry is <NULL/>, the first selected is chosen.
+ @return
+ the qualified name
+ */
+ OUString getQualifiedName( const weld::TreeIter* _pEntry ) const;
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /// returns the count of selected entries
+ sal_Int32 getSelectionCount();
+
+ /// returns the count of entries
+ sal_Int32 getElementCount() const;
+
+ /** returns if an entry is a leaf
+ @param rTreeView
+ The TreeView rEntry belongs to
+ @param rEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry);
+
+ /** returns if one of the selected entries is a leaf
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isALeafSelected() const;
+
+ std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const;
+
+ /// clears the detail pages
+ void clearPages();
+
+ /// returns <TRUE/> when a detail page was filled
+ bool isFilled() const;
+
+ /** adds a new object to the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the object to be inserted
+ @param _rObject
+ The object to add.
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ std::unique_ptr<weld::TreeIter> elementAdded(ElementType eType,
+ const OUString& rName,
+ const css::uno::Any& rObject);
+
+ /** replaces an objects name with a new one
+ @param _eType
+ The type where the entry should be appended.
+ @param _rOldName
+ The old name of the object to be replaced
+ @param _rNewName
+ The new name of the object to be replaced
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ void elementReplaced(ElementType eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName );
+
+ /** removes an element from the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the element to be removed.
+ @param _rxConn
+ If we remove a table, the connection must be set.
+ */
+ void elementRemoved(ElementType _eType
+ ,const OUString& _rName );
+
+ /// returns the preview mode
+ PreviewMode getPreviewMode() const { return m_ePreviewMode;}
+
+ /// <TRUE/> if the preview is enabled
+ bool isPreviewEnabled() const;
+
+ /** switches to the given preview mode
+ @param _eMode
+ the mode to set for the preview
+ @param _bForce
+ Force the preview to be reset
+ */
+ void switchPreview(PreviewMode _eMode,bool _bForce = false);
+
+ /** shows the Preview of the content when it is enabled.
+ @param _xContent
+ The content which must support the "preview" command.
+ */
+ void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent);
+
+ /** shows the Preview of a table or query
+ @param _sDataSourceName
+ the name of the data source
+ @param _sName
+ the name of table or query
+ @param _bTable
+ <TRUE/> if it is a table, otherwise <FALSE/>
+ @return void
+ */
+ void showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailView.cxx b/dbaccess/source/ui/app/AppDetailView.cxx
new file mode 100644
index 000000000..63a9f7f39
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailView.cxx
@@ -0,0 +1,510 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppDetailView.hxx"
+#include <osl/diagnose.h>
+#include <helpids.h>
+#include <strings.hrc>
+#include "AppView.hxx"
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XImageManager.hpp>
+#include <com/sun/star/ui/ImageType.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <core_resource.hxx>
+#include <vcl/svapp.hxx>
+#include "AppDetailPageHelper.hxx"
+#include <dbaccess/IController.hxx>
+#include <algorithm>
+#include <dbtreelistbox.hxx>
+#include "AppController.hxx"
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::graphic;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using ::com::sun::star::util::URL;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+TaskEntry::TaskEntry( const char* _pAsciiUNOCommand, TranslateId _pHelpID, TranslateId pTitleResourceID, bool _bHideWhenDisabled )
+ :sUNOCommand( OUString::createFromAscii( _pAsciiUNOCommand ) )
+ ,pHelpID( _pHelpID )
+ ,sTitle( DBA_RES(pTitleResourceID) )
+ ,bHideWhenDisabled( _bHideWhenDisabled )
+{
+}
+
+void OTasksWindow::updateHelpText()
+{
+ TranslateId pHelpTextId;
+ int nCurEntry = m_xTreeView->get_selected_index();
+ if (nCurEntry != -1)
+ pHelpTextId = weld::fromId<TaskEntry*>(m_xTreeView->get_id(nCurEntry))->pHelpID;
+ setHelpText(pHelpTextId);
+}
+
+IMPL_LINK(OTasksWindow, onSelected, weld::TreeView&, rTreeView, bool)
+{
+ m_nCursorIndex = rTreeView.get_cursor_index();
+ if (m_nCursorIndex != -1)
+ {
+ URL aCommand;
+ aCommand.Complete = weld::fromId<TaskEntry*>(rTreeView.get_id(m_nCursorIndex))->sUNOCommand;
+ getDetailView()->getBorderWin().getView()->getAppController().executeChecked( aCommand, Sequence< PropertyValue >() );
+ }
+ return true;
+}
+
+void OTasksWindow::GrabFocus()
+{
+ if (!m_xTreeView)
+ return;
+ m_xTreeView->grab_focus();
+}
+
+bool OTasksWindow::HasChildPathFocus() const
+{
+ return m_xTreeView && m_xTreeView->has_focus();
+}
+
+IMPL_LINK_NOARG(OTasksWindow, FocusInHdl, weld::Widget&, void)
+{
+ m_xTreeView->select(m_nCursorIndex != -1 ? m_nCursorIndex : 0);
+}
+
+IMPL_LINK_NOARG(OTasksWindow, FocusOutHdl, weld::Widget&, void)
+{
+ m_nCursorIndex = m_xTreeView->get_cursor_index();
+ m_xTreeView->unselect_all();
+}
+
+IMPL_LINK_NOARG(OTasksWindow, OnEntrySelectHdl, weld::TreeView&, void)
+{
+ m_nCursorIndex = m_xTreeView->get_cursor_index();
+ updateHelpText();
+}
+
+OTasksWindow::OTasksWindow(weld::Container* pParent, OApplicationDetailView* pDetailView)
+ : OChildWindow(pParent, "dbaccess/ui/taskwindow.ui", "TaskWindow")
+ , m_xTreeView(m_xBuilder->weld_tree_view("treeview"))
+ , m_xDescription(m_xBuilder->weld_label("description"))
+ , m_xHelpText(m_xBuilder->weld_text_view("helptext"))
+ , m_pDetailView(pDetailView)
+ , m_nCursorIndex(-1)
+{
+ m_xContainer->set_stack_background();
+
+ m_xTreeView->set_help_id(HID_APP_CREATION_LIST);
+ m_xTreeView->connect_row_activated(LINK(this, OTasksWindow, onSelected));
+ m_xTreeView->connect_changed(LINK(this, OTasksWindow, OnEntrySelectHdl));
+ m_xTreeView->connect_focus_in(LINK(this, OTasksWindow, FocusInHdl));
+ m_xTreeView->connect_focus_out(LINK(this, OTasksWindow, FocusOutHdl));
+ // an arbitrary small size it's allowed to shrink to
+ m_xTreeView->set_size_request(42, 42);
+
+ m_xHelpText->set_help_id(HID_APP_HELP_TEXT);
+ m_xDescription->set_help_id(HID_APP_DESCRIPTION_TEXT);
+}
+
+OTasksWindow::~OTasksWindow()
+{
+ Clear();
+}
+
+void OTasksWindow::setHelpText(TranslateId pId)
+{
+ if (pId)
+ m_xHelpText->set_text(DBA_RES(pId));
+ else
+ m_xHelpText->set_text(OUString());
+}
+
+void OTasksWindow::fillTaskEntryList( const TaskEntryList& _rList )
+{
+ Clear();
+
+ try
+ {
+ Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
+ theModuleUIConfigurationManagerSupplier::get( getDetailView()->getBorderWin().getView()->getORB() );
+ Reference< XUIConfigurationManager > xUIConfigMgr = xModuleCfgMgrSupplier->getUIConfigurationManager(
+ "com.sun.star.sdb.OfficeDatabaseDocument"
+ );
+ Reference< XImageManager > xImageMgr( xUIConfigMgr->getImageManager(), UNO_QUERY );
+
+ // copy the commands so we can use them with the config managers
+ Sequence< OUString > aCommands( _rList.size() );
+ OUString* pCommands = aCommands.getArray();
+ for (auto const& copyTask : _rList)
+ {
+ *pCommands = copyTask.sUNOCommand;
+ ++pCommands;
+ }
+
+ Sequence< Reference< XGraphic> > aImages = xImageMgr->getImages(
+ ImageType::SIZE_DEFAULT | ImageType::COLOR_NORMAL ,
+ aCommands
+ );
+
+ const Reference< XGraphic >* pImages( aImages.getConstArray() );
+
+ size_t nIndex = 0;
+ for (auto const& task : _rList)
+ {
+ OUString sId = weld::toId(new TaskEntry(task));
+ m_xTreeView->append(sId, task.sTitle);
+ m_xTreeView->set_image(nIndex++, *pImages++);
+ }
+ }
+ catch(Exception&)
+ {
+ }
+
+ m_xTreeView->unselect_all();
+ updateHelpText();
+ Enable(!_rList.empty());
+}
+
+void OTasksWindow::Clear()
+{
+ m_xTreeView->all_foreach([this](weld::TreeIter& rEntry){
+ TaskEntry* pUserData = weld::fromId<TaskEntry*>(m_xTreeView->get_id(rEntry));
+ delete pUserData;
+ return false;
+ });
+
+ m_xTreeView->clear();
+}
+
+OApplicationDetailView::OApplicationDetailView(weld::Container* pParent, OAppBorderWindow& rBorder,
+ PreviewMode ePreviewMode)
+ : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/appdetailwindow.ui"))
+ , m_xContainer(m_xBuilder->weld_container("AppDetailWindow"))
+ , m_xHorzSplitter(m_xBuilder->weld_paned("splitter"))
+ , m_xTasksParent(m_xBuilder->weld_container("tasks"))
+ , m_xContainerParent(m_xBuilder->weld_container("container"))
+ , m_xTasks(new dbaui::OTitleWindow(m_xTasksParent.get(), STR_TASKS))
+ , m_xTitleContainer(new dbaui::OTitleWindow(m_xContainerParent.get(), TranslateId()))
+ , m_rBorderWin(rBorder)
+{
+ m_xControlHelper = std::make_shared<OAppDetailPageHelper>(m_xTitleContainer->getChildContainer(), m_rBorderWin, ePreviewMode);
+ m_xTitleContainer->setChildWindow(m_xControlHelper);
+
+ std::shared_ptr<OChildWindow> xTasks = std::make_shared<OTasksWindow>(m_xTasks->getChildContainer(), this);
+ xTasks->Enable(!m_rBorderWin.getView()->getCommandController().isDataSourceReadOnly());
+ m_xTasks->setChildWindow(xTasks);
+}
+
+OApplicationDetailView::~OApplicationDetailView()
+{
+}
+
+void OApplicationDetailView::setTaskExternalMnemonics( MnemonicGenerator const & rMnemonics )
+{
+ m_aExternalMnemonics = rMnemonics;
+}
+
+void OApplicationDetailView::createTablesPage(const Reference< XConnection >& _xConnection )
+{
+ impl_createPage( E_TABLE, _xConnection, nullptr );
+}
+
+void OApplicationDetailView::createPage( ElementType _eType,const Reference< XNameAccess >& _xContainer )
+{
+ impl_createPage( _eType, nullptr, _xContainer );
+}
+
+void OApplicationDetailView::impl_createPage( ElementType _eType, const Reference< XConnection >& _rxConnection,
+ const Reference< XNameAccess >& _rxNonTableElements )
+{
+ // get the data for the pane
+ const TaskPaneData& rData = impl_getTaskPaneData( _eType );
+ getTasksWindow().fillTaskEntryList( rData.aTasks );
+
+ // enable the pane as a whole, depending on the availability of the first command
+ OSL_ENSURE( !rData.aTasks.empty(), "OApplicationDetailView::impl_createPage: no tasks at all!?" );
+ bool bEnabled = !rData.aTasks.empty()
+ && getBorderWin().getView()->getCommandController().isCommandEnabled( rData.aTasks[0].sUNOCommand );
+ getTasksWindow().Enable( bEnabled );
+ m_xTitleContainer->setTitle(rData.pTitleId);
+
+ // let our helper create the object list
+ if ( _eType == E_TABLE )
+ GetControlHelper()->createTablesPage( _rxConnection );
+ else
+ GetControlHelper()->createPage( _eType, _rxNonTableElements );
+}
+
+void OApplicationDetailView::impl_fillTaskPaneData(ElementType _eType, TaskPaneData& _rData) const
+{
+ TaskEntryList& rList( _rData.aTasks );
+ rList.clear(); rList.reserve( 4 );
+
+ switch ( _eType )
+ {
+ case E_TABLE:
+ rList.emplace_back( ".uno:DBNewTable", RID_STR_TABLES_HELP_TEXT_DESIGN, RID_STR_NEW_TABLE );
+ rList.emplace_back( ".uno:DBNewTableAutoPilot", RID_STR_TABLES_HELP_TEXT_WIZARD, RID_STR_NEW_TABLE_AUTO );
+ rList.emplace_back( ".uno:DBNewView", RID_STR_VIEWS_HELP_TEXT_DESIGN, RID_STR_NEW_VIEW, true );
+ _rData.pTitleId = RID_STR_TABLES_CONTAINER;
+ break;
+
+ case E_FORM:
+ rList.emplace_back( ".uno:DBNewForm", RID_STR_FORMS_HELP_TEXT, RID_STR_NEW_FORM );
+ rList.emplace_back( ".uno:DBNewFormAutoPilot", RID_STR_FORMS_HELP_TEXT_WIZARD, RID_STR_NEW_FORM_AUTO );
+ _rData.pTitleId = RID_STR_FORMS_CONTAINER;
+ break;
+
+ case E_REPORT:
+ rList.emplace_back( ".uno:DBNewReport", RID_STR_REPORT_HELP_TEXT, RID_STR_NEW_REPORT, true );
+ rList.emplace_back( ".uno:DBNewReportAutoPilot", RID_STR_REPORTS_HELP_TEXT_WIZARD, RID_STR_NEW_REPORT_AUTO );
+ _rData.pTitleId = RID_STR_REPORTS_CONTAINER;
+ break;
+
+ case E_QUERY:
+ rList.emplace_back( ".uno:DBNewQuery", RID_STR_QUERIES_HELP_TEXT, RID_STR_NEW_QUERY );
+ rList.emplace_back( ".uno:DBNewQueryAutoPilot", RID_STR_QUERIES_HELP_TEXT_WIZARD, RID_STR_NEW_QUERY_AUTO );
+ rList.emplace_back( ".uno:DBNewQuerySql", RID_STR_QUERIES_HELP_TEXT_SQL, RID_STR_NEW_QUERY_SQL );
+ _rData.pTitleId = RID_STR_QUERIES_CONTAINER;
+ break;
+
+ default:
+ OSL_FAIL( "OApplicationDetailView::impl_fillTaskPaneData: illegal element type!" );
+ }
+
+ // remove the entries which are not enabled currently
+ for (TaskEntryList::iterator pTask = rList.begin(); pTask != rList.end();)
+ {
+ if ( pTask->bHideWhenDisabled
+ && !getBorderWin().getView()->getCommandController().isCommandEnabled( pTask->sUNOCommand )
+ )
+ pTask = rList.erase( pTask );
+ else
+ {
+ ++pTask;
+ }
+ }
+}
+
+const TaskPaneData& OApplicationDetailView::impl_getTaskPaneData( ElementType _eType )
+{
+ if ( m_aTaskPaneData.empty() )
+ m_aTaskPaneData.resize( size_t(E_ELEMENT_TYPE_COUNT) );
+ OSL_ENSURE( ( _eType >= 0 ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OApplicationDetailView::impl_getTaskPaneData: illegal element type!" );
+ TaskPaneData& rData = m_aTaskPaneData[ _eType ];
+
+ //oj: do not check, otherwise extensions will only be visible after a reload.
+ impl_fillTaskPaneData( _eType, rData );
+
+ return rData;
+}
+
+OUString OApplicationDetailView::getQualifiedName(const weld::TreeIter* _pEntry) const
+{
+ return GetControlHelper()->getQualifiedName( _pEntry );
+}
+
+bool OApplicationDetailView::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry)
+{
+ return OAppDetailPageHelper::isLeaf(rTreeView, rEntry);
+}
+
+bool OApplicationDetailView::isALeafSelected() const
+{
+ return GetControlHelper()->isALeafSelected();
+}
+
+void OApplicationDetailView::selectAll()
+{
+ GetControlHelper()->selectAll();
+}
+
+void OApplicationDetailView::sortDown()
+{
+ GetControlHelper()->sortDown();
+}
+
+void OApplicationDetailView::sortUp()
+{
+ GetControlHelper()->sortUp();
+}
+
+bool OApplicationDetailView::isFilled() const
+{
+ return GetControlHelper()->isFilled();
+}
+
+ElementType OApplicationDetailView::getElementType() const
+{
+ return GetControlHelper()->getElementType();
+}
+
+void OApplicationDetailView::clearPages(bool _bTaskAlso)
+{
+ if ( _bTaskAlso )
+ getTasksWindow().Clear();
+ GetControlHelper()->clearPages();
+}
+
+sal_Int32 OApplicationDetailView::getSelectionCount()
+{
+ return GetControlHelper()->getSelectionCount();
+}
+
+sal_Int32 OApplicationDetailView::getElementCount() const
+{
+ return GetControlHelper()->getElementCount();
+}
+
+void OApplicationDetailView::getSelectionElementNames( std::vector< OUString>& _rNames ) const
+{
+ GetControlHelper()->getSelectionElementNames( _rNames );
+}
+
+void OApplicationDetailView::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence< NamedDatabaseObject >& out_rSelectedObjects)
+{
+ GetControlHelper()->describeCurrentSelectionForControl(rControl, out_rSelectedObjects);
+}
+
+void OApplicationDetailView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ GetControlHelper()->describeCurrentSelectionForType( _eType, _out_rSelectedObjects );
+}
+
+vcl::Window* OApplicationDetailView::getMenuParent() const
+{
+ return GetControlHelper()->getMenuParent();
+}
+
+void OApplicationDetailView::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ return GetControlHelper()->adjustMenuPosition(rControl, rPos);
+}
+
+void OApplicationDetailView::selectElements(const Sequence< OUString>& _aNames)
+{
+ GetControlHelper()->selectElements( _aNames );
+}
+
+std::unique_ptr<weld::TreeIter> OApplicationDetailView::getEntry(const Point& rPoint) const
+{
+ return GetControlHelper()->getEntry(rPoint);
+}
+
+bool OApplicationDetailView::isCutAllowed()
+{
+ return false;
+}
+
+bool OApplicationDetailView::isCopyAllowed()
+{
+ return true;
+}
+
+bool OApplicationDetailView::isPasteAllowed() { return true; }
+
+void OApplicationDetailView::copy() { }
+
+void OApplicationDetailView::cut() { }
+
+void OApplicationDetailView::paste() { }
+
+std::unique_ptr<weld::TreeIter> OApplicationDetailView::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject )
+{
+ return GetControlHelper()->elementAdded(_eType, _rName, _rObject);
+}
+
+void OApplicationDetailView::elementRemoved(ElementType _eType,const OUString& _rName )
+{
+ GetControlHelper()->elementRemoved(_eType,_rName );
+}
+
+void OApplicationDetailView::elementReplaced(ElementType _eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName )
+{
+ GetControlHelper()->elementReplaced( _eType, _rOldName, _rNewName );
+}
+
+PreviewMode OApplicationDetailView::getPreviewMode() const
+{
+ return GetControlHelper()->getPreviewMode();
+}
+
+bool OApplicationDetailView::isPreviewEnabled() const
+{
+ return GetControlHelper()->isPreviewEnabled();
+}
+
+void OApplicationDetailView::switchPreview(PreviewMode _eMode)
+{
+ GetControlHelper()->switchPreview(_eMode);
+}
+
+void OApplicationDetailView::showPreview(const Reference< XContent >& _xContent)
+{
+ GetControlHelper()->showPreview(_xContent);
+}
+
+void OApplicationDetailView::showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable)
+{
+ GetControlHelper()->showPreview(_sDataSourceName,_sName,_bTable);
+}
+
+bool OApplicationDetailView::isSortUp() const
+{
+ return GetControlHelper()->isSortUp();
+}
+
+TreeListBox* OApplicationDetailView::getTreeWindow() const
+{
+ DBTreeViewBase* pCurrent = GetControlHelper()->getCurrentView();
+ if (!pCurrent)
+ return nullptr;
+ return &pCurrent->getListBox();
+}
+
+OAppDetailPageHelper* OApplicationDetailView::GetControlHelper()
+{
+ return static_cast<OAppDetailPageHelper*>(m_xControlHelper.get());
+}
+
+const OAppDetailPageHelper* OApplicationDetailView::GetControlHelper() const
+{
+ return static_cast<const OAppDetailPageHelper*>(m_xControlHelper.get());
+}
+
+bool OApplicationDetailView::HasChildPathFocus() const
+{
+ return m_xHorzSplitter->has_focus() ||
+ m_xTasks->HasChildPathFocus() ||
+ m_xTitleContainer->HasChildPathFocus();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailView.hxx b/dbaccess/source/ui/app/AppDetailView.hxx
new file mode 100644
index 000000000..f074df440
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailView.hxx
@@ -0,0 +1,318 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <vcl/mnemonic.hxx>
+#include <IClipBoardTest.hxx>
+#include "AppTitleWindow.hxx"
+#include <AppElementType.hxx>
+
+#include <vector>
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class OApplicationDetailView;
+ class OAppDetailPageHelper;
+ class OTasksWindow;
+ class TreeListBox;
+
+ struct TaskEntry
+ {
+ OUString sUNOCommand;
+ TranslateId pHelpID;
+ OUString sTitle;
+ bool bHideWhenDisabled;
+ // TODO: we should be consistent in the task pane and the menus/toolbars:
+ // If an entry is disabled in the latter, it should also be disabled in the former.
+ // If an entry is *hidden* in the former, it should also be hidden in the latter.
+
+ TaskEntry( const char* _pAsciiUNOCommand, TranslateId pHelpID, TranslateId pTitleResourceID, bool _bHideWhenDisabled = false );
+ };
+ typedef std::vector< TaskEntry > TaskEntryList;
+
+ struct TaskPaneData
+ {
+ /// the tasks available in the pane
+ TaskEntryList aTasks;
+ /// the resource ID for the title of the pane
+ TranslateId pTitleId;
+ };
+
+ class OTasksWindow final : public OChildWindow
+ {
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ std::unique_ptr<weld::Label> m_xDescription;
+ std::unique_ptr<weld::TextView> m_xHelpText;
+ OApplicationDetailView* m_pDetailView;
+
+ int m_nCursorIndex;
+
+ DECL_LINK(onSelected, weld::TreeView&, bool);
+ DECL_LINK(OnEntrySelectHdl, weld::TreeView&, void);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+
+ void updateHelpText();
+
+ public:
+ OTasksWindow(weld::Container* pParent, OApplicationDetailView* pDetailView);
+ ~OTasksWindow();
+
+ virtual void GrabFocus() override;
+
+ virtual bool HasChildPathFocus() const override;
+
+ OApplicationDetailView* getDetailView() const { return m_pDetailView; }
+
+ /// fills the Creation listbox with the necessary strings and images
+ void fillTaskEntryList( const TaskEntryList& _rList );
+
+ void Clear();
+ void setHelpText(TranslateId pId);
+ };
+
+ class OApplicationDetailView final : public IClipboardTest
+ {
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Paned> m_xHorzSplitter;
+ std::unique_ptr<weld::Container> m_xTasksParent;
+ std::unique_ptr<weld::Container> m_xContainerParent;
+ std::unique_ptr<OTitleWindow> m_xTasks;
+ std::unique_ptr<OTitleWindow> m_xTitleContainer;
+ OAppBorderWindow& m_rBorderWin; // my parent
+ std::shared_ptr<OChildWindow> m_xControlHelper;
+ std::vector< TaskPaneData > m_aTaskPaneData;
+ MnemonicGenerator m_aExternalMnemonics;
+
+ const OAppDetailPageHelper* GetControlHelper() const;
+ OAppDetailPageHelper* GetControlHelper();
+
+ public:
+ OApplicationDetailView(weld::Container* pParent, OAppBorderWindow& rBorder, PreviewMode ePreviewMode);
+ ~OApplicationDetailView();
+
+ /** creates the tables page
+ @param _xConnection
+ The connection to get the table names
+ */
+ void createTablesPage(const css::uno::Reference< css::sdbc::XConnection>& _xConnection);
+
+ /** creates the page for the specific type.
+ @param _eType
+ The type which should be created. E_TABLE isn't allowed.
+ @param _xContainer
+ The container of the elements to be inserted.
+ */
+ void createPage(ElementType _eType,const css::uno::Reference< css::container::XNameAccess >& _xContainer);
+
+ void setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics );
+
+ OAppBorderWindow& getBorderWin() const { return m_rBorderWin; }
+ OTasksWindow& getTasksWindow() const { return *static_cast< OTasksWindow* >( m_xTasks->getChildWindow() ); }
+
+ bool isCutAllowed() override ;
+ bool isCopyAllowed() override ;
+ bool isPasteAllowed() override;
+ void copy() override;
+ void cut() override;
+ void paste() override;
+
+ /** return the qualified name.
+ @param _pEntry
+ The entry of a table, or query, form, report to get the qualified name.
+ If the entry is <NULL/>, the first selected is chosen.
+ @return
+ the qualified name
+ */
+ OUString getQualifiedName(const weld::TreeIter* _pEntry) const;
+
+ /** returns if an entry is a leaf
+ @param rTreeView
+ The TreeView pEntry belongs to
+ @param rEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry);
+
+ /** returns if one of the selected entries is a leaf
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isALeafSelected() const;
+
+ /** select all entries in the detail page
+ */
+ void selectAll();
+
+ /// returns <TRUE/> if it sorts ascending
+ bool isSortUp() const;
+
+ /// sort the entries in the detail page down
+ void sortDown();
+
+ /// sort the entries in the detail page up
+ void sortUp();
+
+ /// returns <TRUE/> when a detail page was filled
+ bool isFilled() const;
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /** clears the detail pages.
+ @param _bTaskAlso
+ If <TRUE/> the task window will also be cleared.
+ */
+ void clearPages(bool _bTaskAlso = true);
+
+ /// returns the count of entries
+ sal_Int32 getElementCount() const;
+
+ /// returns the count of selected entries
+ sal_Int32 getSelectionCount();
+
+ /** returns the element names which are selected
+ @param _rNames
+ The list will be filled.
+ */
+ void getSelectionElementNames(std::vector< OUString>& _rNames ) const;
+
+ /** describes the current selection for the given control
+ */
+ void describeCurrentSelectionForControl(
+ const weld::TreeView& rControl,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** describes the current selection for the given ElementType
+ */
+ void describeCurrentSelectionForType(
+ const ElementType _eType,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** get the menu parent window for the given control
+ */
+ vcl::Window* getMenuParent() const;
+ void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const;
+
+ /** select all names on the currently selected container. Non existence names where ignored.
+ *
+ * \param _aNames the element names
+ */
+ void selectElements(const css::uno::Sequence< OUString>& _aNames);
+
+ /** adds a new object to the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the object to be inserted
+ @param _rObject
+ The object to add.
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ std::unique_ptr<weld::TreeIter> elementAdded(ElementType eType,
+ const OUString& rName,
+ const css::uno::Any& rObject);
+
+ /** replaces an objects name with a new one
+ @param _eType
+ The type where the entry should be appended.
+ @param _rOldName
+ The old name of the object to be replaced
+ @param _rNewName
+ The new name of the object to be replaced
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ @param _xObject
+ The object which was replaced
+ */
+ void elementReplaced(ElementType eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName );
+
+ /** removes an element from the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the element to be removed.
+ @param _rxConn
+ If we remove a table, the connection must be set.
+ */
+ void elementRemoved(ElementType _eType
+ ,const OUString& _rName );
+
+ /// returns the preview mode
+ PreviewMode getPreviewMode() const;
+
+ /// <TRUE/> if the preview is enabled
+ bool isPreviewEnabled() const;
+
+ /** switches to the given preview mode
+ @param _eMode
+ the mode to set for the preview
+ */
+ void switchPreview(PreviewMode _eMode);
+
+ /** shows the Preview of the content when it is enabled.
+ @param _xContent
+ The content which must support the "preview" command.
+ */
+ void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent);
+
+ /** shows the Preview of a table or query
+ @param _sDataSourceName
+ the name of the data source
+ @param _sName
+ the name of table or query
+ @param _bTable
+ <TRUE/> if it is a table, otherwise <FALSE/>
+ @return void
+ */
+ void showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable);
+
+ std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const;
+
+ TreeListBox* getTreeWindow() const;
+
+ bool HasChildPathFocus() const;
+ private:
+ void impl_createPage(
+ ElementType _eType,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::container::XNameAccess >& _rxNonTableElements
+ );
+
+ const TaskPaneData& impl_getTaskPaneData( ElementType _eType );
+ void impl_fillTaskPaneData( ElementType _eType, TaskPaneData& _rData ) const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppIconControl.cxx b/dbaccess/source/ui/app/AppIconControl.cxx
new file mode 100644
index 000000000..1448c4015
--- /dev/null
+++ b/dbaccess/source/ui/app/AppIconControl.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppIconControl.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <sfx2/thumbnailviewitem.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/event.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <callbacks.hxx>
+#include <AppElementType.hxx>
+
+namespace dbaui
+{
+class OApplicationIconControlDropTarget final : public DropTargetHelper
+{
+private:
+ OApplicationIconControl& m_rControl;
+
+public:
+ OApplicationIconControlDropTarget(OApplicationIconControl& rControl)
+ : DropTargetHelper(rControl.GetDrawingArea()->get_drop_target())
+ , m_rControl(rControl)
+ {
+ }
+
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
+ {
+ return m_rControl.AcceptDrop(rEvt);
+ }
+
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
+ {
+ return m_rControl.ExecuteDrop(rEvt);
+ }
+};
+
+OApplicationIconControl::OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll)
+ : ThumbnailView(std::move(xScroll), nullptr)
+ , m_pActionListener(nullptr)
+ , m_nMaxWidth(0)
+ , m_nMaxHeight(0)
+{
+ mnVItemSpace = 6; // row spacing
+ mbSelectOnFocus = false;
+ DrawMnemonics(true);
+}
+
+void OApplicationIconControl::Fill()
+{
+ static const struct CategoryDescriptor
+ {
+ TranslateId pLabelResId;
+ ElementType eType;
+ rtl::OUStringConstExpr aImageResId;
+ } aCategories[] = { { RID_STR_TABLES_CONTAINER, E_TABLE, BMP_TABLEFOLDER_TREE_L },
+ { RID_STR_QUERIES_CONTAINER, E_QUERY, BMP_QUERYFOLDER_TREE_L },
+ { RID_STR_FORMS_CONTAINER, E_FORM, BMP_FORMFOLDER_TREE_L },
+ { RID_STR_REPORTS_CONTAINER, E_REPORT, BMP_REPORTFOLDER_TREE_L } };
+
+ for (const CategoryDescriptor& aCategorie : aCategories)
+ {
+ // E_TABLE is 0, but 0 means void so use id of enum + 1
+ std::unique_ptr<ThumbnailViewItem> xItem(
+ new ThumbnailViewItem(*this, aCategorie.eType + 1));
+ xItem->mbBorder = false;
+ xItem->maPreview1 = BitmapEx(aCategorie.aImageResId);
+ const Size& rSize = xItem->maPreview1.GetSizePixel();
+ m_nMaxWidth = std::max(m_nMaxWidth, rSize.Width());
+ m_nMaxHeight = std::max(m_nMaxHeight, rSize.Height());
+ xItem->maTitle = DBA_RES(aCategorie.pLabelResId);
+ m_nMaxWidth = std::max<tools::Long>(m_nMaxWidth, GetTextWidth(xItem->maTitle));
+ AppendItem(std::move(xItem));
+ }
+
+ const int nMargin = 12;
+ const int nWidthRequest = m_nMaxWidth + 2 * nMargin;
+ set_size_request(nWidthRequest, -1);
+ // we expect a Resize at which point we'll set the item sizes based on our final size
+}
+
+ElementType OApplicationIconControl::GetSelectedItem() const
+{
+ for (const auto& rItem : mItemList)
+ {
+ if (!rItem->mbSelected)
+ continue;
+ return static_cast<ElementType>(rItem->mnId - 1);
+ }
+ return E_NONE;
+}
+
+void OApplicationIconControl::createIconAutoMnemonics(MnemonicGenerator& rMnemonics)
+{
+ for (const auto& rItem : mItemList)
+ rMnemonics.RegisterMnemonic(rItem->maTitle);
+
+ // exchange texts with generated mnemonics
+ for (auto& rItem : mItemList)
+ rItem->maTitle = rMnemonics.CreateMnemonic(rItem->maTitle);
+}
+
+void OApplicationIconControl::Resize()
+{
+ // fill the full width of the allocated area and give two lines of space to
+ // center the title in
+ setItemDimensions(GetOutputSizePixel().Width(), m_nMaxHeight, GetTextHeight() * 2, 0);
+ ThumbnailView::Resize();
+}
+
+bool OApplicationIconControl::IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const
+{
+ bool bRet = false;
+
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+ for (const auto& rItem : mItemList)
+ {
+ if (rI18nHelper.MatchMnemonic(rItem->maTitle, cChar))
+ {
+ bRet = true;
+ rType = static_cast<ElementType>(rItem->mnId - 1);
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+bool OApplicationIconControl::DoKeyShortCut(const KeyEvent& rKEvt)
+{
+ bool bMod2 = rKEvt.GetKeyCode().IsMod2();
+ sal_Unicode cChar = rKEvt.GetCharCode();
+ ElementType eType(E_NONE);
+ if (bMod2 && cChar && IsMnemonicChar(cChar, eType))
+ {
+ // shortcut is clicked
+ deselectItems();
+ SelectItem(eType + 1);
+ return true;
+ }
+
+ return false;
+}
+
+bool OApplicationIconControl::KeyInput(const KeyEvent& rKEvt)
+{
+ return DoKeyShortCut(rKEvt) || ThumbnailView::KeyInput(rKEvt);
+}
+
+void OApplicationIconControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ThumbnailView::SetDrawingArea(pDrawingArea);
+ m_xDropTarget.reset(new OApplicationIconControlDropTarget(*this));
+}
+
+sal_Int8 OApplicationIconControl::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ sal_Int8 nDropOption = DND_ACTION_NONE;
+ if (m_pActionListener)
+ {
+ sal_uInt16 nEntry = GetItemId(rEvt.maPosPixel);
+ if (nEntry)
+ {
+ deselectItems();
+ SelectItem(nEntry);
+ nDropOption
+ = m_pActionListener->queryDrop(rEvt, m_xDropTarget->GetDataFlavorExVector());
+ }
+ }
+ return nDropOption;
+}
+
+sal_Int8 OApplicationIconControl::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ if (m_pActionListener)
+ m_pActionListener->executeDrop(rEvt);
+ return DND_ACTION_NONE;
+}
+
+OApplicationIconControl::~OApplicationIconControl() {}
+
+void OApplicationIconControl::GetFocus()
+{
+ ThumbnailView::GetFocus();
+ Invalidate(); // redraw focus rect
+}
+
+void OApplicationIconControl::LoseFocus()
+{
+ ThumbnailView::LoseFocus();
+ Invalidate(); // redraw focus rect
+}
+
+tools::Rectangle OApplicationIconControl::GetFocusRect()
+{
+ if (HasFocus())
+ {
+ // Get the last selected item in the list
+ for (tools::Long i = mFilteredItemList.size() - 1; i >= 0; --i)
+ {
+ ThumbnailViewItem* pItem = mFilteredItemList[i];
+ if (pItem->isSelected())
+ {
+ tools::Rectangle aRet(pItem->getDrawArea());
+ aRet.AdjustLeft(THUMBNAILVIEW_ITEM_CORNER);
+ aRet.AdjustTop(1);
+ aRet.AdjustRight(-THUMBNAILVIEW_ITEM_CORNER);
+ aRet.AdjustBottom(-2);
+ return aRet;
+ }
+ }
+ }
+ return tools::Rectangle();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppIconControl.hxx b/dbaccess/source/ui/app/AppIconControl.hxx
new file mode 100644
index 000000000..1146a77a1
--- /dev/null
+++ b/dbaccess/source/ui/app/AppIconControl.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sfx2/thumbnailview.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/weld.hxx>
+#include <AppElementType.hxx>
+
+class MnemonicGenerator;
+
+namespace dbaui
+{
+ class IControlActionListener;
+ class IconControl;
+ class OApplicationIconControlDropTarget;
+
+ class OApplicationIconControl final : public ThumbnailView
+ {
+ std::unique_ptr<OApplicationIconControlDropTarget> m_xDropTarget;
+ IControlActionListener* m_pActionListener;
+
+ tools::Long m_nMaxWidth;
+ tools::Long m_nMaxHeight;
+
+ bool IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const;
+
+ public:
+ explicit OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual void Resize() override;
+ virtual tools::Rectangle GetFocusRect() override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+ bool DoKeyShortCut(const KeyEvent& rKEvt);
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual ~OApplicationIconControl() override;
+
+ ElementType GetSelectedItem() const;
+
+ void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; }
+ void Fill();
+
+ void createIconAutoMnemonics(MnemonicGenerator& rMnemonics);
+
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppSwapWindow.cxx b/dbaccess/source/ui/app/AppSwapWindow.cxx
new file mode 100644
index 000000000..ea2066c72
--- /dev/null
+++ b/dbaccess/source/ui/app/AppSwapWindow.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppSwapWindow.hxx"
+#include <helpids.h>
+#include "AppView.hxx"
+#include <sfx2/thumbnailviewitem.hxx>
+#include <vcl/event.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/svapp.hxx>
+#include "AppController.hxx"
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+OApplicationSwapWindow::OApplicationSwapWindow(weld::Container* pParent,
+ OAppBorderWindow& rBorderWindow)
+ : OChildWindow(pParent, "dbaccess/ui/appswapwindow.ui", "AppSwapWindow")
+ , m_xIconControl(new OApplicationIconControl(m_xBuilder->weld_scrolled_window("scroll", true)))
+ , m_xIconControlWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xIconControl))
+ , m_eLastType(E_NONE)
+ , m_rBorderWin(rBorderWindow)
+ , m_nChangeEvent(nullptr)
+{
+ m_xContainer->set_stack_background();
+
+ m_xIconControl->SetHelpId(HID_APP_SWAP_ICONCONTROL);
+ m_xIconControl->Fill();
+ m_xIconControl->setItemStateHdl(LINK(this, OApplicationSwapWindow, OnContainerSelectHdl));
+ m_xIconControl->setControlActionListener(&m_rBorderWin.getView()->getAppController());
+}
+
+void OApplicationSwapWindow::GrabFocus()
+{
+ if (m_xIconControl)
+ m_xIconControl->GrabFocus();
+}
+
+bool OApplicationSwapWindow::HasChildPathFocus() const
+{
+ return m_xIconControl && m_xIconControl->HasFocus();
+}
+
+OApplicationSwapWindow::~OApplicationSwapWindow()
+{
+ if (m_nChangeEvent)
+ Application::RemoveUserEvent(m_nChangeEvent);
+}
+
+void OApplicationSwapWindow::clearSelection()
+{
+ m_xIconControl->deselectItems();
+ onContainerSelected(E_NONE);
+}
+
+void OApplicationSwapWindow::createIconAutoMnemonics(MnemonicGenerator& rMnemonics)
+{
+ m_xIconControl->createIconAutoMnemonics(rMnemonics);
+}
+
+bool OApplicationSwapWindow::interceptKeyInput(const KeyEvent& _rEvent)
+{
+ const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode();
+ if (rKeyCode.GetModifier() == KEY_MOD2)
+ return m_xIconControl->DoKeyShortCut(_rEvent);
+ // not handled
+ return false;
+}
+
+ElementType OApplicationSwapWindow::getElementType() const
+{
+ return m_xIconControl->GetSelectedItem();
+}
+
+bool OApplicationSwapWindow::onContainerSelected(ElementType _eType)
+{
+ if (m_eLastType == _eType)
+ return true;
+
+ if (m_rBorderWin.getView()->getAppController().onContainerSelect(_eType))
+ {
+ if (_eType != E_NONE)
+ m_eLastType = _eType;
+ return true;
+ }
+
+ if (!m_nChangeEvent)
+ m_nChangeEvent
+ = Application::PostUserEvent(LINK(this, OApplicationSwapWindow, ChangeToLastSelected));
+ return false;
+}
+
+IMPL_LINK(OApplicationSwapWindow, OnContainerSelectHdl, const ThumbnailViewItem*, pEntry, void)
+{
+ if (pEntry->mbSelected)
+ {
+ ElementType eType = static_cast<ElementType>(pEntry->mnId - 1);
+ onContainerSelected(eType); // i87582
+ }
+}
+
+IMPL_LINK_NOARG(OApplicationSwapWindow, ChangeToLastSelected, void*, void)
+{
+ m_nChangeEvent = nullptr;
+ selectContainer(m_eLastType);
+}
+
+void OApplicationSwapWindow::selectContainer(ElementType eType)
+{
+ m_xIconControl->deselectItems();
+ m_xIconControl->SelectItem(eType + 1); // will trigger onContainerSelected
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppSwapWindow.hxx b/dbaccess/source/ui/app/AppSwapWindow.hxx
new file mode 100644
index 000000000..1ce972e3b
--- /dev/null
+++ b/dbaccess/source/ui/app/AppSwapWindow.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <IClipBoardTest.hxx>
+#include "AppIconControl.hxx"
+#include <AppElementType.hxx>
+#include <ChildWindow.hxx>
+
+struct ImplSVEvent;
+class MnemonicGenerator;
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class OApplicationSwapWindow : public OChildWindow
+ , public IClipboardTest
+ {
+ std::unique_ptr<OApplicationIconControl> m_xIconControl;
+ std::unique_ptr<weld::CustomWeld> m_xIconControlWin;
+ ElementType m_eLastType;
+ OAppBorderWindow& m_rBorderWin;
+ ImplSVEvent* m_nChangeEvent;
+
+ DECL_LINK( OnContainerSelectHdl, const ThumbnailViewItem*, void );
+ DECL_LINK( ChangeToLastSelected, void*, void );
+
+ public:
+ OApplicationSwapWindow(weld::Container* pParent, OAppBorderWindow& rBorderWindow);
+ virtual ~OApplicationSwapWindow() override;
+
+ virtual void GrabFocus() override;
+ virtual bool HasChildPathFocus() const override;
+
+ bool isCutAllowed() override { return false; }
+ bool isCopyAllowed() override { return false; }
+ bool isPasteAllowed() override { return false; }
+ void copy() override { }
+ void cut() override { }
+ void paste() override { }
+
+ /** automatically creates mnemonics for the icon/texts in our left hand side panel
+ */
+ void createIconAutoMnemonics( MnemonicGenerator& _rMnemonics );
+
+ /** called to give the window the chance to intercept key events, while it has not
+ the focus
+
+ @return <TRUE/> if and only if the event has been handled, and should not
+ not be further processed
+ */
+ bool interceptKeyInput( const KeyEvent& _rEvent );
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /** clears the selection in the icon choice control and calls the handler
+ */
+ void clearSelection();
+
+ /** changes the container which should be displayed. The select handler will also be called.
+ @param _eType
+ Which container to show.
+ */
+ void selectContainer(ElementType _eType);
+
+ private:
+ bool onContainerSelected( ElementType _eType );
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppTitleWindow.cxx b/dbaccess/source/ui/app/AppTitleWindow.cxx
new file mode 100644
index 000000000..d5e604394
--- /dev/null
+++ b/dbaccess/source/ui/app/AppTitleWindow.cxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <vcl/svapp.hxx>
+#include "AppTitleWindow.hxx"
+
+namespace dbaui
+{
+OTitleWindow::OTitleWindow(weld::Container* pParent, TranslateId pTitleId)
+ : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/titlewindow.ui"))
+ , m_xContainer(m_xBuilder->weld_container("TitleWindow"))
+ , m_xTitleFrame(m_xBuilder->weld_container("titleparent"))
+ , m_xTitle(m_xBuilder->weld_label("title"))
+ , m_xChildContainer(m_xBuilder->weld_container("box"))
+{
+ setTitle(pTitleId);
+
+ m_xContainer->set_stack_background();
+ m_xTitleFrame->set_title_background();
+ m_xTitle->set_label_type(weld::LabelType::Title);
+}
+
+OTitleWindow::~OTitleWindow() {}
+
+weld::Container* OTitleWindow::getChildContainer() { return m_xChildContainer.get(); }
+
+void OTitleWindow::setChildWindow(const std::shared_ptr<OChildWindow>& rChild)
+{
+ m_xChild = rChild;
+}
+
+void OTitleWindow::setTitle(TranslateId pTitleId)
+{
+ if (!pTitleId)
+ return;
+ m_xTitle->set_label(DBA_RES(pTitleId));
+}
+
+void OTitleWindow::GrabFocus()
+{
+ if (m_xChild)
+ m_xChild->GrabFocus();
+}
+
+bool OTitleWindow::HasChildPathFocus() const { return m_xChild && m_xChild->HasChildPathFocus(); }
+
+} // namespace dbaui
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppTitleWindow.hxx b/dbaccess/source/ui/app/AppTitleWindow.hxx
new file mode 100644
index 000000000..d57f52416
--- /dev/null
+++ b/dbaccess/source/ui/app/AppTitleWindow.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <ChildWindow.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace dbaui
+{
+ class OTitleWindow final
+ {
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Container> m_xTitleFrame;
+ std::unique_ptr<weld::Label> m_xTitle;
+ std::unique_ptr<weld::Container> m_xChildContainer;
+ std::shared_ptr<OChildWindow> m_xChild;
+
+ public:
+ OTitleWindow(weld::Container* pParent, TranslateId pTitleId);
+ ~OTitleWindow();
+
+ void GrabFocus();
+
+ bool HasChildPathFocus() const;
+
+ /** gets the window which should be used as a child's parent */
+ weld::Container* getChildContainer();
+
+ /** sets the child window which should be displayed below the title. It will be destroyed at the end.
+ @param _pChild
+ The child window.
+ */
+ void setChildWindow(const std::shared_ptr<OChildWindow>& rChild);
+
+ /** gets the child window.
+
+ @return
+ The child window.
+ */
+ OChildWindow* getChildWindow() const { return m_xChild.get(); }
+
+ /** sets the title text out of the resource
+ @param pTitleId
+ The resource id of the title text.
+ */
+ void setTitle(TranslateId pTitleId);
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppView.cxx b/dbaccess/source/ui/app/AppView.cxx
new file mode 100644
index 000000000..b300df8df
--- /dev/null
+++ b/dbaccess/source/ui/app/AppView.cxx
@@ -0,0 +1,473 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppView.hxx"
+#include <strings.hrc>
+#include <tools/diagnose_ex.h>
+#include <vcl/event.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include "AppDetailView.hxx"
+#include "AppSwapWindow.hxx"
+#include <vcl/settings.hxx>
+#include "AppTitleWindow.hxx"
+#include "AppController.hxx"
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+OAppBorderWindow::OAppBorderWindow(OApplicationView* pParent, PreviewMode ePreviewMode)
+ : InterimItemWindow(pParent, "dbaccess/ui/appborderwindow.ui", "AppBorderWindow", false)
+ , m_xPanelParent(m_xBuilder->weld_container("panel"))
+ , m_xDetailViewParent(m_xBuilder->weld_container("detail"))
+ , m_xView(pParent)
+{
+ SetStyle(GetStyle() | WB_DIALOGCONTROL);
+
+ m_xPanel.reset(new OTitleWindow(m_xPanelParent.get(), STR_DATABASE));
+ std::shared_ptr<OChildWindow> xSwap = std::make_shared<OApplicationSwapWindow>(m_xPanel->getChildContainer(), *this);
+
+ m_xPanel->setChildWindow(xSwap);
+
+ m_xDetailView.reset(new OApplicationDetailView(m_xDetailViewParent.get(), *this, ePreviewMode));
+
+ ImplInitSettings();
+}
+
+OAppBorderWindow::~OAppBorderWindow()
+{
+ disposeOnce();
+}
+
+void OAppBorderWindow::dispose()
+{
+ // destroy children
+ m_xPanel.reset();
+ m_xDetailView.reset();
+ m_xPanelParent.reset();
+ m_xDetailViewParent.reset();
+ m_xView.clear();
+ InterimItemWindow::dispose();
+}
+
+void OAppBorderWindow::GetFocus()
+{
+ if (m_xPanel)
+ m_xPanel->GrabFocus();
+}
+
+OApplicationSwapWindow* OAppBorderWindow::getPanel() const
+{
+ return static_cast<OApplicationSwapWindow*>(m_xPanel->getChildWindow());
+}
+
+OApplicationView::OApplicationView( vcl::Window* pParent
+ ,const Reference< XComponentContext >& _rxOrb
+ ,OApplicationController& _rAppController
+ ,PreviewMode _ePreviewMode
+ ) :
+ ODataView( pParent, _rAppController, _rxOrb, WB_DIALOGCONTROL )
+ ,m_rAppController( _rAppController )
+{
+ m_pWin = VclPtr<OAppBorderWindow>::Create(this,_ePreviewMode);
+ m_pWin->Show();
+
+ ImplInitSettings();
+}
+
+OApplicationView::~OApplicationView()
+{
+ disposeOnce();
+}
+
+void OApplicationView::dispose()
+{
+ stopComponentListening(m_xObject);
+ m_xObject.clear();
+ m_pWin->Hide();
+ m_pWin.disposeAndClear();
+ ODataView::dispose();
+}
+
+void OApplicationView::createIconAutoMnemonics( MnemonicGenerator& _rMnemonics )
+{
+ if ( m_pWin && m_pWin->getPanel() )
+ m_pWin->getPanel()->createIconAutoMnemonics( _rMnemonics );
+}
+
+void OApplicationView::setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics )
+{
+ if ( m_pWin && m_pWin->getDetailView() )
+ m_pWin->getDetailView()->setTaskExternalMnemonics( _rMnemonics );
+}
+
+void OApplicationView::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ ODataView::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OApplicationView::resizeDocumentView(tools::Rectangle& _rPlayground)
+{
+ if ( m_pWin && !_rPlayground.IsEmpty() )
+ {
+ Size aFLSize = LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont));
+ _rPlayground.Move( aFLSize.Width(),aFLSize.Height() );
+ Size aOldSize = _rPlayground.GetSize();
+ _rPlayground.SetSize( Size(aOldSize.Width() - 2*aFLSize.Width(), aOldSize.Height() - 2*aFLSize.Height()) );
+
+ m_pWin->SetPosSizePixel(_rPlayground.TopLeft() , _rPlayground.GetSize() );
+ }
+ // just for completeness: there is no space left, we occupied it all ...
+ _rPlayground.SetPos( _rPlayground.BottomRight() );
+ _rPlayground.SetSize( Size( 0, 0 ) );
+}
+
+OApplicationView::ChildFocusState OApplicationView::getChildFocus() const
+{
+ ChildFocusState eChildFocus;
+ if( m_pWin && getPanel() && getPanel()->HasChildPathFocus() )
+ eChildFocus = PANELSWAP;
+ else if ( m_pWin && getDetailView() && getDetailView()->HasChildPathFocus() )
+ eChildFocus = DETAIL;
+ else
+ eChildFocus = NONE;
+ return eChildFocus;
+}
+
+bool OApplicationView::PreNotify( NotifyEvent& rNEvt )
+{
+ switch(rNEvt.GetType())
+ {
+ case MouseNotifyEvent::KEYINPUT:
+ {
+ const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent();
+ // give the pane the chance to intercept mnemonic accelerators
+ // #i34790#
+ if ( getPanel() && getPanel()->interceptKeyInput( *pKeyEvent ) )
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ODataView::PreNotify(rNEvt);
+}
+
+IClipboardTest* OApplicationView::getActiveChild() const
+{
+ IClipboardTest* pTest = nullptr;
+ if (getChildFocus() == DETAIL)
+ pTest = getDetailView();
+ return pTest;
+}
+
+bool OApplicationView::isCopyAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isCopyAllowed();
+}
+
+bool OApplicationView::isCutAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isCutAllowed();
+}
+
+bool OApplicationView::isPasteAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isPasteAllowed();
+}
+
+void OApplicationView::copy()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->copy();
+}
+
+void OApplicationView::cut()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->cut();
+}
+
+void OApplicationView::paste()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->paste();
+}
+
+OUString OApplicationView::getQualifiedName(const weld::TreeIter* _pEntry) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getQualifiedName( _pEntry );
+}
+
+bool OApplicationView::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return OApplicationDetailView::isLeaf(rTreeView, rEntry);
+}
+
+bool OApplicationView::isALeafSelected() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isALeafSelected();
+}
+
+void OApplicationView::selectAll()
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->selectAll();
+}
+
+bool OApplicationView::isSortUp() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isSortUp();
+}
+
+void OApplicationView::sortDown()
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->sortDown();
+}
+
+void OApplicationView::sortUp()
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->sortUp();
+}
+
+bool OApplicationView::isFilled() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isFilled();
+}
+
+ElementType OApplicationView::getElementType() const
+{
+ OSL_ENSURE(m_pWin && getDetailView() && getPanel(),"Detail view is NULL! -> GPF");
+ return getDetailView()->HasChildPathFocus() ? getDetailView()->getElementType() : getPanel()->getElementType();
+}
+
+sal_Int32 OApplicationView::getSelectionCount() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getSelectionCount();
+}
+
+sal_Int32 OApplicationView::getElementCount() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getElementCount();
+}
+
+void OApplicationView::getSelectionElementNames( std::vector< OUString>& _rNames ) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->getSelectionElementNames( _rNames );
+}
+
+void OApplicationView::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence<NamedDatabaseObject>& out_rSelectedObjects)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->describeCurrentSelectionForControl(rControl, out_rSelectedObjects);
+}
+
+vcl::Window* OApplicationView::getMenuParent() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getMenuParent();
+}
+
+void OApplicationView::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->adjustMenuPosition(rControl, rPos);
+}
+
+void OApplicationView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->describeCurrentSelectionForType( _eType, _out_rSelectedObjects );
+}
+
+void OApplicationView::selectElements(const Sequence< OUString>& _aNames)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->selectElements( _aNames );
+}
+
+std::unique_ptr<weld::TreeIter> OApplicationView::elementAdded(ElementType eType,const OUString& _rName, const Any& _rObject )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->elementAdded(eType,_rName,_rObject);
+}
+
+void OApplicationView::elementRemoved(ElementType eType,const OUString& _rName )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->elementRemoved(eType,_rName);
+}
+
+void OApplicationView::elementReplaced(ElementType _eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->elementReplaced(_eType, _rOldName, _rNewName );
+}
+
+void OApplicationView::clearPages()
+{
+ OSL_ENSURE(m_pWin && getDetailView() && getPanel(),"Detail view is NULL! -> GPF");
+ getPanel()->clearSelection();
+ getDetailView()->clearPages();
+}
+
+void OApplicationView::selectContainer(ElementType _eType)
+{
+ OSL_ENSURE(m_pWin && getPanel(),"Detail view is NULL! -> GPF");
+ weld::WaitObject aWO(GetFrameWeld());
+ getPanel()->selectContainer(_eType);
+}
+
+std::unique_ptr<weld::TreeIter> OApplicationView::getEntry(const Point& rPosPixel) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getEntry(rPosPixel);
+}
+
+PreviewMode OApplicationView::getPreviewMode() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getPreviewMode();
+}
+
+bool OApplicationView::isPreviewEnabled() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isPreviewEnabled();
+}
+
+void OApplicationView::switchPreview(PreviewMode _eMode)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->switchPreview(_eMode);
+}
+
+void OApplicationView::showPreview(const Reference< XContent >& _xContent)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ stopComponentListening(m_xObject);
+ m_xObject = nullptr;
+ getDetailView()->showPreview(_xContent);
+}
+
+void OApplicationView::showPreview( const OUString& _sDataSourceName,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const OUString& _sName,
+ bool _bTable)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ if ( !isPreviewEnabled() )
+ return;
+
+ stopComponentListening(m_xObject);
+ m_xObject = nullptr;
+ try
+ {
+ Reference<XNameAccess> xNameAccess;
+ if ( _bTable )
+ {
+ Reference<XTablesSupplier> xSup(_xConnection,UNO_QUERY);
+ if ( xSup.is() )
+ xNameAccess = xSup->getTables();
+ }
+ else
+ {
+ Reference<XQueriesSupplier> xSup(_xConnection,UNO_QUERY);
+ if ( xSup.is() )
+ xNameAccess = xSup->getQueries();
+ }
+ if ( xNameAccess.is() && xNameAccess->hasByName(_sName) )
+ m_xObject.set(xNameAccess->getByName(_sName),UNO_QUERY);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ if ( m_xObject.is() )
+ startComponentListening(m_xObject);
+ getDetailView()->showPreview(_sDataSourceName,_sName,_bTable);
+}
+
+void OApplicationView::GetFocus()
+{
+ if (m_pWin && getChildFocus() == NONE)
+ m_pWin->GrabFocus();
+}
+
+void OApplicationView::_disposing( const css::lang::EventObject& /*_rSource*/ )
+{
+ if ( m_pWin && getDetailView() )
+ showPreview(nullptr);
+}
+
+void OApplicationView::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*GetOutDev(), aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppView.hxx b/dbaccess/source/ui/app/AppView.hxx
new file mode 100644
index 000000000..59a6d477a
--- /dev/null
+++ b/dbaccess/source/ui/app/AppView.hxx
@@ -0,0 +1,302 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dbaccess/dataview.hxx>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <unotools/eventlisteneradapter.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/weld.hxx>
+#include <IClipBoardTest.hxx>
+#include <AppElementType.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+
+class MnemonicGenerator;
+
+namespace dbaui
+{
+ class OApplicationView;
+ class OApplicationDetailView;
+ class OApplicationSwapWindow;
+ class OTitleWindow;
+ class OApplicationController;
+
+ class OAppBorderWindow final : public InterimItemWindow
+ {
+ std::unique_ptr<weld::Container> m_xPanelParent;
+ std::unique_ptr<weld::Container> m_xDetailViewParent;
+ std::unique_ptr<OTitleWindow> m_xPanel;
+ std::unique_ptr<OApplicationDetailView> m_xDetailView;
+ VclPtr<OApplicationView> m_xView;
+
+ public:
+ OAppBorderWindow(OApplicationView* pParent, PreviewMode ePreviewMode);
+ virtual ~OAppBorderWindow() override;
+ virtual void dispose() override;
+
+ // Window overrides
+ virtual void GetFocus() override;
+
+ OApplicationView* getView() const { return m_xView.get(); }
+ OApplicationSwapWindow* getPanel() const;
+ OApplicationDetailView* getDetailView() const { return m_xDetailView.get(); }
+ weld::Container& getTopLevel() { return *m_xContainer; }
+ };
+
+ class OApplicationView : public ODataView
+ ,public IClipboardTest
+ ,public ::utl::OEventListenerAdapter
+ {
+ enum ChildFocusState
+ {
+ PANELSWAP,
+ DETAIL,
+ NONE
+ };
+ private:
+ css::uno::Reference< css::lang::XComponent >
+ m_xObject;
+ VclPtr<OAppBorderWindow> m_pWin;
+ OApplicationController& m_rAppController;
+
+ ChildFocusState getChildFocus() const;
+ IClipboardTest* getActiveChild() const;
+
+ void ImplInitSettings();
+ protected:
+
+ // return the Rectangle where I can paint myself
+ virtual void resizeDocumentView(tools::Rectangle& rRect) override;
+
+ // OEventListenerAdapter
+ virtual void _disposing( const css::lang::EventObject& _rSource ) override;
+
+ // Window
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ public:
+ OApplicationView( vcl::Window* pParent
+ ,const css::uno::Reference< css::uno::XComponentContext >&
+ ,OApplicationController& _rAppController
+ ,PreviewMode _ePreviewMode
+ );
+ virtual ~OApplicationView() override;
+ virtual void dispose() override;
+
+ /// automatically creates mnemonics for the icon/texts in our left hand side panel
+ void createIconAutoMnemonics( MnemonicGenerator& _rMnemonics );
+
+ /// automatically creates mnemonics for the texts in our task pane
+ void setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics );
+
+ // Window overrides
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void GetFocus() override;
+
+ OApplicationController& getAppController() const { return m_rAppController; }
+
+ // IClipboardTest
+ virtual bool isCutAllowed() override;
+ virtual bool isCopyAllowed() override;
+ virtual bool isPasteAllowed() override;
+ virtual void copy() override;
+ virtual void cut() override;
+ virtual void paste() override;
+
+ /// get the left panel
+ OApplicationSwapWindow* getPanel() const { return m_pWin->getPanel(); }
+ /// get the detail page
+ OApplicationDetailView* getDetailView() const { return m_pWin->getDetailView(); }
+
+ /** return the qualified name.
+ @param _pEntry
+ The entry of a table, or query, form, report to get the qualified name.
+ If the entry is <NULL/>, the first selected is chosen.
+ @return
+ the qualified name
+ */
+ OUString getQualifiedName(const weld::TreeIter* _pEntry) const;
+
+ /** returns if an entry is a leaf
+ @param rTreeView
+ The TreeView rEntry belongs to
+ @param rEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) const;
+
+ /** returns if one of the selected entries is a leaf
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isALeafSelected() const;
+
+ /** select all entries in the detail page
+ */
+ void selectAll();
+
+ /// returns <TRUE/> if it sorts ascending
+ bool isSortUp() const;
+
+ /// sort the entries in the detail page down
+ void sortDown();
+
+ /// sort the entries in the detail page up
+ void sortUp();
+
+ /// returns <TRUE/> when a detail page was filled
+ bool isFilled() const;
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /// returns the count of entries
+ sal_Int32 getElementCount() const;
+
+ /// returns the count of selected entries
+ sal_Int32 getSelectionCount() const;
+
+ /** clears the detail page and the selection on the left side.
+ The task window will also be cleared.
+ */
+ void clearPages();
+
+ /** returns the element names which are selected
+ @param _rNames
+ The list will be filled.
+ */
+ void getSelectionElementNames( std::vector< OUString>& _rNames ) const;
+
+ /** describes the current selection for the given control
+ */
+ void describeCurrentSelectionForControl(
+ const weld::TreeView& rControl,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** describes the current selection for the given ElementType
+ */
+ void describeCurrentSelectionForType(
+ const ElementType _eType,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** get the menu parent window for the given control
+ */
+ vcl::Window* getMenuParent() const;
+
+ /** adjust rPos relative to rControl to instead relative to getMenuParent */
+ void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const;
+
+ /** select all names on the currently selected container. Non existence names where ignored.
+ *
+ * \param _aNames the element names
+ */
+ void selectElements(const css::uno::Sequence< OUString>& _aNames);
+
+ /** adds a new object to the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the object to be inserted
+ @param _rObject
+ The object to add.
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ std::unique_ptr<weld::TreeIter> elementAdded(ElementType eType,
+ const OUString& rName,
+ const css::uno::Any& rObject);
+
+ /** replaces an objects name with a new one
+ @param _eType
+ The type where the entry should be appended.
+ @param _rOldName
+ The old name of the object to be replaced
+ @param _rNewName
+ The new name of the object to be replaced
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ @param _xObject
+ The object which was replaced
+ */
+ void elementReplaced(ElementType eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName );
+
+ /** removes an element from the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the element to be removed.
+ @param _rxConn
+ If we remove a table, the connection must be set.
+ */
+ void elementRemoved(ElementType _eType
+ ,const OUString& _rName );
+
+ /** changes the container which should be displayed. The select handler will also be called.
+ @param _eType
+ Which container to show.
+ */
+ void selectContainer(ElementType _eType);
+
+ /// returns the preview mode
+ PreviewMode getPreviewMode() const;
+
+ /// <TRUE/> if the preview is enabled
+ bool isPreviewEnabled() const;
+
+ /** switches to the given preview mode
+ @param _eMode
+ the mode to set for the preview
+ */
+ void switchPreview(PreviewMode _eMode);
+
+ /** shows the Preview of the content when it is enabled.
+ @param _xContent
+ The content which must support the "preview" command.
+ */
+ void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent);
+
+ /** shows the Preview of a table or query
+ @param _sDataSourceName
+ the name of the data source
+ @param _xConnection
+ the connection which will be shared
+ @param _sName
+ the name of table or query
+ @param _bTable
+ <TRUE/> if it is a table, otherwise <FALSE/>
+ @return void
+ */
+ void showPreview( const OUString& _sDataSourceName,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const OUString& _sName,
+ bool _bTable);
+
+ std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/ChildWindow.cxx b/dbaccess/source/ui/app/ChildWindow.cxx
new file mode 100644
index 000000000..a8091c863
--- /dev/null
+++ b/dbaccess/source/ui/app/ChildWindow.cxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <vcl/svapp.hxx>
+#include <ChildWindow.hxx>
+
+namespace dbaui
+{
+OChildWindow::OChildWindow(weld::Container* pParent, const OUString& rUIXMLDescription,
+ const OString& rID)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , m_xContainer(m_xBuilder->weld_container(rID))
+{
+}
+
+OChildWindow::~OChildWindow() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/dbaccess/source/ui/app/DocumentInfoPreview.cxx b/dbaccess/source/ui/app/DocumentInfoPreview.cxx
new file mode 100644
index 000000000..7220eb2bd
--- /dev/null
+++ b/dbaccess/source/ui/app/DocumentInfoPreview.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <rtl/ustring.hxx>
+#include "DocumentInfoPreview.hxx"
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itemset.hxx>
+#include <tools/datetime.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/localedatawrapper.hxx>
+
+#include <templwin.hrc>
+#include "templwin.hxx"
+
+namespace dbaui {
+
+ODocumentInfoPreview::ODocumentInfoPreview()
+{
+}
+
+void ODocumentInfoPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ WeldEditView::SetDrawingArea(pDrawingArea);
+ m_xEditView->HideCursor();
+ m_xEditView->SetReadOnly(true);
+}
+
+ODocumentInfoPreview::~ODocumentInfoPreview()
+{
+}
+
+void ODocumentInfoPreview::clear() {
+ m_xEditEngine->SetText(OUString());
+}
+
+void ODocumentInfoPreview::fill(
+ css::uno::Reference< css::document::XDocumentProperties > const & xDocProps)
+{
+ assert(xDocProps.is());
+
+ insertNonempty(DI_TITLE, xDocProps->getTitle());
+ insertNonempty(DI_FROM, xDocProps->getAuthor());
+ insertDateTime(DI_DATE, xDocProps->getCreationDate());
+ insertNonempty(DI_MODIFIEDBY, xDocProps->getModifiedBy());
+ insertDateTime(DI_MODIFIEDDATE, xDocProps->getModificationDate());
+ insertNonempty(DI_PRINTBY, xDocProps->getPrintedBy());
+ insertDateTime(DI_PRINTDATE, xDocProps->getPrintDate());
+ insertNonempty(DI_THEME, xDocProps->getSubject());
+ insertNonempty(
+ DI_KEYWORDS,
+ comphelper::string::convertCommaSeparated(xDocProps->getKeywords()));
+ insertNonempty(DI_DESCRIPTION, xDocProps->getDescription());
+
+ // User-defined (custom) properties:
+ css::uno::Reference< css::beans::XPropertySet > user(
+ xDocProps->getUserDefinedProperties(), css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::beans::XPropertySetInfo > info(
+ user->getPropertySetInfo());
+ const css::uno::Sequence< css::beans::Property > props(info->getProperties());
+ for (const auto& rProp : props) {
+ OUString name(rProp.Name);
+ css::uno::Any aAny(user->getPropertyValue(name));
+ css::uno::Reference< css::script::XTypeConverter > conv(
+ css::script::Converter::create(
+ comphelper::getProcessComponentContext()));
+ OUString value;
+ try {
+ value = conv->convertToSimpleType(aAny, css::uno::TypeClass_STRING).
+ get< OUString >();
+ } catch (css::script::CannotConvertException &) {
+ TOOLS_INFO_EXCEPTION("svtools.contnr", "ignored");
+ }
+ if (!value.isEmpty()) {
+ insertEntry(name, value);
+ }
+ }
+
+ m_xEditView->SetSelection(ESelection(0, 0, 0, 0));
+}
+
+namespace
+{
+ ESelection InsertAtEnd(const EditEngine& rEditEngine)
+ {
+ const sal_uInt32 nPara = rEditEngine.GetParagraphCount() -1;
+ sal_Int32 nLastLen = rEditEngine.GetText(nPara).getLength();
+ return ESelection(nPara, nLastLen, nPara, nLastLen);
+ }
+}
+
+void ODocumentInfoPreview::insertEntry(
+ std::u16string_view title, OUString const & value)
+{
+ if (!m_xEditEngine->GetText().isEmpty()) {
+ m_xEditEngine->QuickInsertText("\n\n", InsertAtEnd(*m_xEditEngine));
+ }
+
+ OUString caption(OUString::Concat(title) + ":\n");
+ m_xEditEngine->QuickInsertText(caption, InsertAtEnd(*m_xEditEngine));
+
+ SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT));
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CJK));
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CTL));
+ int nCaptionPara = m_xEditEngine->GetParagraphCount() - 2;
+ m_xEditEngine->QuickSetAttribs(aSet, ESelection(nCaptionPara, 0, nCaptionPara, caption.getLength() - 1));
+
+ m_xEditEngine->QuickInsertText(value, InsertAtEnd(*m_xEditEngine));
+}
+
+void ODocumentInfoPreview::insertNonempty(tools::Long id, OUString const & value)
+{
+ if (!value.isEmpty()) {
+ insertEntry(SvtDocInfoTable_Impl::GetString(id), value);
+ }
+}
+
+void ODocumentInfoPreview::insertDateTime(
+ tools::Long id, css::util::DateTime const & value)
+{
+ DateTime aToolsDT(
+ Date(value.Day, value.Month, value.Year),
+ tools::Time(
+ value.Hours, value.Minutes, value.Seconds, value.NanoSeconds));
+ if (aToolsDT.IsValidAndGregorian()) {
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ OUString buf = rLocaleWrapper.getDate(aToolsDT) +
+ ", " +
+ rLocaleWrapper.getTime(aToolsDT);
+ insertEntry(SvtDocInfoTable_Impl::GetString(id), buf);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/DocumentInfoPreview.hxx b/dbaccess/source/ui/app/DocumentInfoPreview.hxx
new file mode 100644
index 000000000..0c9548d0a
--- /dev/null
+++ b/dbaccess/source/ui/app/DocumentInfoPreview.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <svx/weldeditview.hxx>
+
+namespace com :: sun :: star :: uno { template <typename > class Reference; }
+
+namespace com::sun::star {
+ namespace document { class XDocumentProperties; }
+ namespace util { struct DateTime; }
+}
+
+namespace dbaui {
+
+class ODocumentInfoPreview final : public WeldEditView {
+public:
+ ODocumentInfoPreview();
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual ~ODocumentInfoPreview() override;
+
+ void clear();
+
+ void fill(css::uno::Reference< css::document::XDocumentProperties > const & xDocProps);
+
+private:
+ void insertEntry(std::u16string_view title, OUString const & value);
+
+ void insertNonempty(tools::Long id, OUString const & value);
+
+ void insertDateTime(tools::Long id, css::util::DateTime const & value);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/subcomponentmanager.cxx b/dbaccess/source/ui/app/subcomponentmanager.cxx
new file mode 100644
index 000000000..bf92f2400
--- /dev/null
+++ b/dbaccess/source/ui/app/subcomponentmanager.cxx
@@ -0,0 +1,551 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "subcomponentmanager.hxx"
+#include "AppController.hxx"
+#include <strings.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/embed/XComponentSupplier.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <dbaccess/dataview.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+
+#include <algorithm>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::frame::XModel2;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::util::XCloseable;
+ using ::com::sun::star::awt::XTopWindow;
+ using ::com::sun::star::embed::XComponentSupplier;
+ using ::com::sun::star::ucb::XCommandProcessor;
+ using ::com::sun::star::ucb::Command;
+ using ::com::sun::star::document::XDocumentEventBroadcaster;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+
+ // helper structs
+ namespace
+ {
+ struct SubComponentDescriptor
+ {
+ /// the name of the sub component, empty if it is yet unsaved
+ OUString sName;
+ /// type of the component - an ElementType value, except for relation design
+ sal_Int32 nComponentType;
+ /// the mode in which the sub component has been opened
+ ElementOpenMode eOpenMode;
+ /// the frame which the component resides in. Must not be <NULL/>
+ Reference< XFrame > xFrame;
+ /// the controller of the sub component. Must not be <NULL/>
+ Reference< XController > xController;
+ /// the model of the sub component. Might be <NULL/>
+ Reference< XModel > xModel;
+ /// the document definition which holds the component, if any; as CommandProcessor
+ Reference< XCommandProcessor > xComponentCommandProcessor;
+ /// the document definition which holds the component, if any; as PropertySet
+ Reference< XPropertySet > xDocumentDefinitionProperties;
+
+ SubComponentDescriptor()
+ :nComponentType( -1 )
+ ,eOpenMode( E_OPEN_NORMAL )
+ {
+ }
+
+ SubComponentDescriptor( const OUString& i_rName, const sal_Int32 i_nComponentType,
+ const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent )
+ :sName( i_rName )
+ ,nComponentType( i_nComponentType )
+ ,eOpenMode( i_eOpenMode )
+ {
+ if ( !impl_constructFrom( i_rComponent ) )
+ {
+ // i_rComponent is neither a model, nor a controller, nor a frame
+ // => it must be a css.sdb.DocumentDefinition
+ Reference< XComponentSupplier > xCompSupp( i_rComponent, UNO_QUERY_THROW );
+ Reference< XComponent > xComponent( xCompSupp->getComponent(), UNO_QUERY_THROW );
+ if ( !impl_constructFrom( xComponent ) )
+ throw RuntimeException("Illegal component type." );
+ xComponentCommandProcessor.set( i_rComponent, UNO_QUERY_THROW );
+ xDocumentDefinitionProperties.set( i_rComponent, UNO_QUERY_THROW );
+ }
+ }
+
+ bool is() const { return xFrame.is(); }
+
+ private:
+ bool impl_constructFrom( const Reference< XComponent >& _rxComponent )
+ {
+ // is it a model?
+ xModel.set( _rxComponent, UNO_QUERY );
+ if ( xModel.is() )
+ {
+ xController.set( xModel->getCurrentController() );
+ if ( xController.is() )
+ xFrame.set( xController->getFrame(), UNO_SET_THROW );
+ }
+ else
+ {
+ // is it a controller?
+ xController.set( _rxComponent, UNO_QUERY );
+ if ( xController.is() )
+ {
+ xFrame.set( xController->getFrame(), UNO_SET_THROW );
+ }
+ else
+ {
+ // is it a frame?
+ xFrame.set( _rxComponent, UNO_QUERY );
+ if ( !xFrame.is() )
+ return false;
+
+ // ensure we have a controller
+ xController.set( xFrame->getController(), UNO_SET_THROW );
+ }
+
+ // check whether there is a model (not required)
+ xModel.set( xController->getModel() );
+ }
+
+ return true;
+ }
+ };
+
+ struct SelectSubComponent
+ {
+ Reference< XComponent > operator()( const SubComponentDescriptor &_desc ) const
+ {
+ if ( _desc.xModel.is() )
+ return _desc.xModel;
+ OSL_ENSURE( _desc.xController.is(), "SelectSubComponent::operator(): illegal component!" );
+ return _desc.xController;
+ }
+ };
+
+ typedef std::vector< SubComponentDescriptor > SubComponents;
+
+ struct SubComponentMatch
+ {
+ public:
+ SubComponentMatch( const OUString& i_rName, const sal_Int32 i_nComponentType,
+ const ElementOpenMode i_eOpenMode )
+ :m_sName( i_rName )
+ ,m_nComponentType( i_nComponentType )
+ ,m_eOpenMode( i_eOpenMode )
+ {
+ }
+
+ bool operator()( const SubComponentDescriptor& i_rCompareWith ) const
+ {
+ return ( m_sName == i_rCompareWith.sName )
+ && ( m_nComponentType == i_rCompareWith.nComponentType )
+ && ( m_eOpenMode == i_rCompareWith.eOpenMode );
+ }
+ private:
+ const OUString m_sName;
+ const sal_Int32 m_nComponentType;
+ const ElementOpenMode m_eOpenMode;
+ };
+ }
+
+ // SubComponentManager_Data
+ struct SubComponentManager_Data
+ {
+ SubComponentManager_Data( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
+ :m_rController( _rController )
+ ,m_aMutex( _rMutex )
+ {
+ }
+
+ OApplicationController& m_rController;
+ mutable ::comphelper::SharedMutex m_aMutex;
+ SubComponents m_aComponents;
+
+ ::osl::Mutex& getMutex() const { return m_aMutex; }
+ };
+
+ // SubComponentManager
+ SubComponentManager::SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
+ :m_pData( new SubComponentManager_Data( _rController, _rMutex ) )
+ {
+ }
+
+ SubComponentManager::~SubComponentManager()
+ {
+ }
+
+ void SubComponentManager::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+ m_pData->m_aComponents.clear();
+ }
+
+ namespace
+ {
+ bool lcl_fallbackToAnotherController( SubComponentDescriptor& _rCompDesc )
+ {
+ Reference< XController > xFallback;
+ OSL_PRECOND( _rCompDesc.xModel.is(), "lcl_fallbackToAnotherController: illegal call!" );
+ if ( !_rCompDesc.xModel.is() )
+ return false;
+
+ xFallback.set( _rCompDesc.xModel->getCurrentController() );
+ if ( xFallback == _rCompDesc.xController )
+ // don't accept the very same controller as fallback
+ xFallback.clear();
+
+ if ( !xFallback.is() )
+ {
+ // perhaps XModel2 can be of help here
+ Reference< XModel2 > xModel2( _rCompDesc.xModel, UNO_QUERY );
+ Reference< XEnumeration > xControllerEnum;
+ if ( xModel2.is() )
+ xControllerEnum = xModel2->getControllers();
+ while ( xControllerEnum.is() && xControllerEnum->hasMoreElements() )
+ {
+ xFallback.set( xControllerEnum->nextElement(), UNO_QUERY );
+ if ( xFallback == _rCompDesc.xController )
+ xFallback.clear();
+ }
+ }
+
+ if ( xFallback.is() )
+ {
+ _rCompDesc.xController = xFallback;
+ _rCompDesc.xFrame.set( xFallback->getFrame(), UNO_SET_THROW );
+ return true;
+ }
+
+ return false;
+ }
+
+ bool lcl_closeComponent( const Reference< XCommandProcessor >& _rxCommandProcessor )
+ {
+ bool bSuccess = false;
+ try
+ {
+ sal_Int32 nCommandIdentifier = _rxCommandProcessor->createCommandIdentifier();
+
+ Command aCommand;
+ aCommand.Name = "close";
+ _rxCommandProcessor->execute( aCommand, nCommandIdentifier, nullptr );
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+ }
+
+ bool lcl_closeComponent( const SubComponentDescriptor& _rComponent )
+ {
+ if ( _rComponent.xComponentCommandProcessor.is() )
+ return lcl_closeComponent( _rComponent.xComponentCommandProcessor );
+
+ Reference< XController > xController( _rComponent.xController );
+ OSL_ENSURE( xController.is(), "lcl_closeComponent: invalid controller!" );
+
+ // suspend the controller in the document
+ if ( xController.is() )
+ if ( !xController->suspend( true ) )
+ return false;
+
+ bool bSuccess = false;
+ try
+ {
+ Reference< XCloseable > xCloseable( _rComponent.xFrame, UNO_QUERY_THROW );
+ xCloseable->close( true );
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+ }
+
+ void lcl_notifySubComponentEvent( const SubComponentManager_Data& _rData, const char* _pAsciiEventName,
+ const SubComponentDescriptor& _rComponent )
+ {
+ try
+ {
+ Reference< XDocumentEventBroadcaster > xBroadcaster( _rData.m_rController.getModel(), UNO_QUERY_THROW );
+ xBroadcaster->notifyDocumentEvent(
+ OUString::createFromAscii( _pAsciiEventName ),
+ &_rData.m_rController,
+ Any( _rComponent.xFrame )
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ void SAL_CALL SubComponentManager::propertyChange( const PropertyChangeEvent& i_rEvent )
+ {
+ if ( i_rEvent.PropertyName != PROPERTY_NAME )
+ // by definition, it's allowed to broadcast more than what we've registered for
+ return;
+
+ // find the sub component whose name changed
+ for (auto & component : m_pData->m_aComponents)
+ {
+ if ( component.xDocumentDefinitionProperties != i_rEvent.Source )
+ continue;
+
+ OUString sNewName;
+ OSL_VERIFY( i_rEvent.NewValue >>= sNewName );
+
+ #if OSL_DEBUG_LEVEL > 0
+ OUString sOldKnownName( component.sName );
+ OUString sOldName;
+ OSL_VERIFY( i_rEvent.OldValue >>= sOldName );
+ OSL_ENSURE( sOldName == sOldKnownName, "SubComponentManager::propertyChange: inconsistency in the old names!" );
+ #endif
+
+ component.sName = sNewName;
+ break;
+ }
+ }
+
+ void SAL_CALL SubComponentManager::disposing( const EventObject& _rSource )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
+
+ SubComponentDescriptor aClosedComponent;
+
+ for ( SubComponents::iterator comp = m_pData->m_aComponents.begin();
+ comp != m_pData->m_aComponents.end();
+ ++comp
+ )
+ {
+ bool bRemove = false;
+
+ if ( comp->xController == _rSource.Source )
+ {
+ if ( !comp->xModel.is() )
+ {
+ bRemove = true;
+ }
+ else
+ {
+ // maybe this is just one view to the sub document, and only this view is closed
+ if ( !lcl_fallbackToAnotherController( *comp ) )
+ {
+ bRemove = true;
+ }
+ }
+ }
+ else if ( comp->xModel == _rSource.Source )
+ {
+ bRemove = true;
+ }
+
+ if ( bRemove )
+ {
+ aClosedComponent = *comp;
+ m_pData->m_aComponents.erase( comp );
+ break;
+ }
+ }
+
+ if ( aClosedComponent.is() )
+ {
+ aGuard.clear();
+ lcl_notifySubComponentEvent( *m_pData, "OnSubComponentClosed", aClosedComponent );
+ }
+ }
+
+ Sequence< Reference< XComponent> > SubComponentManager::getSubComponents() const
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+
+ Sequence< Reference< XComponent > > aComponents( m_pData->m_aComponents.size() );
+ std::transform(
+ m_pData->m_aComponents.begin(),
+ m_pData->m_aComponents.end(),
+ aComponents.getArray(),
+ SelectSubComponent()
+ );
+ return aComponents;
+ }
+
+ bool SubComponentManager::closeSubComponents()
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+
+ try
+ {
+ SubComponents aWorkingCopy( m_pData->m_aComponents );
+ for (auto const& elem : aWorkingCopy)
+ {
+ lcl_closeComponent(elem);
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return empty();
+ }
+
+ bool SubComponentManager::empty() const
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+ return m_pData->m_aComponents.empty();
+ }
+
+ void SubComponentManager::onSubComponentOpened( const OUString& _rName, const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode, const Reference< XComponent >& _rxComponent )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
+
+#if OSL_DEBUG_LEVEL > 0
+ if ( !_rName.isEmpty() )
+ {
+ // check there does not already exist such a component
+ auto subComponentNotExists = std::none_of(
+ m_pData->m_aComponents.begin(),
+ m_pData->m_aComponents.end(),
+ SubComponentMatch( _rName, _nComponentType, _eOpenMode )
+ );
+ OSL_ENSURE( subComponentNotExists, "already existent!" );
+ }
+#endif
+ SubComponentDescriptor aElement( _rName, _nComponentType, _eOpenMode, _rxComponent );
+ ENSURE_OR_THROW( aElement.xModel.is() || aElement.xController.is(), "illegal component" );
+
+ m_pData->m_aComponents.push_back( aElement );
+
+ // add as listener
+ if ( aElement.xController.is() )
+ aElement.xController->addEventListener( this );
+ if ( aElement.xModel.is() )
+ aElement.xModel->addEventListener( this );
+ if ( aElement.xDocumentDefinitionProperties.is() )
+ aElement.xDocumentDefinitionProperties->addPropertyChangeListener( PROPERTY_NAME, this );
+
+ // notify this to interested parties
+ aGuard.clear();
+ lcl_notifySubComponentEvent( *m_pData, "OnSubComponentOpened", aElement );
+ }
+
+ bool SubComponentManager::activateSubFrame( const OUString& _rName, const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode, Reference< XComponent >& o_rComponent ) const
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+
+ SubComponents::const_iterator pos = std::find_if(
+ m_pData->m_aComponents.begin(),
+ m_pData->m_aComponents.end(),
+ SubComponentMatch( _rName, _nComponentType, _eOpenMode )
+ );
+ if ( pos == m_pData->m_aComponents.end() )
+ // no component with this name/type/open mode
+ return false;
+
+ const Reference< XFrame > xFrame( pos->xFrame, UNO_SET_THROW );
+ const Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW );
+ xTopWindow->toFront();
+
+ if ( pos->xModel.is() )
+ o_rComponent = pos->xModel.get();
+ else if ( pos->xController.is() )
+ o_rComponent = pos->xController.get();
+ else
+ o_rComponent = pos->xFrame.get();
+
+ return true;
+ }
+
+ bool SubComponentManager::closeSubFrames( std::u16string_view i_rName, const sal_Int32 _nComponentType )
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+ ENSURE_OR_RETURN_FALSE( !i_rName.empty(), "SubComponentManager::closeSubFrames: illegal name!" );
+
+ SubComponents aWorkingCopy( m_pData->m_aComponents );
+ for (auto const& elem : aWorkingCopy)
+ {
+ if ( ( elem.sName != i_rName ) || ( elem.nComponentType != _nComponentType ) )
+ continue;
+
+ if ( !lcl_closeComponent(elem) )
+ return false;
+ }
+
+ return true;
+ }
+
+ bool SubComponentManager::lookupSubComponent( const Reference< XComponent >& i_rComponent,
+ OUString& o_rName, sal_Int32& o_rComponentType )
+ {
+ for (auto const& component : m_pData->m_aComponents)
+ {
+ if ( ( component.xModel.is()
+ && ( component.xModel == i_rComponent )
+ )
+ || ( component.xController.is()
+ && ( component.xController == i_rComponent )
+ )
+ || ( component.xFrame.is()
+ && ( component.xFrame == i_rComponent )
+ )
+ )
+ {
+ o_rName = component.sName;
+ o_rComponentType = component.nComponentType;
+ return true;
+ }
+ }
+ return false;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/subcomponentmanager.hxx b/dbaccess/source/ui/app/subcomponentmanager.hxx
new file mode 100644
index 000000000..402a3d593
--- /dev/null
+++ b/dbaccess/source/ui/app/subcomponentmanager.hxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <AppElementType.hxx>
+
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+
+#include <comphelper/sharedmutex.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace dbaui
+{
+
+ struct SubComponentManager_Data;
+ class OApplicationController;
+
+ // SubComponentManager
+ typedef ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener
+ > SubComponentManager_Base;
+ class SubComponentManager : public SubComponentManager_Base
+ {
+ public:
+ SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex );
+ virtual ~SubComponentManager() override;
+
+ void disposing();
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XDatabaseDocumentUI helpers
+ css::uno::Sequence< css::uno::Reference< css::lang::XComponent> >
+ getSubComponents() const;
+ bool closeSubComponents();
+
+ // container access
+ void onSubComponentOpened(
+ const OUString& _rName,
+ const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode,
+ const css::uno::Reference< css::lang::XComponent >&
+ _rxComponent
+ );
+ bool empty() const;
+
+ /** activates (i.e. brings to top) the frame in which the given component is loaded, if any
+
+ @return
+ <TRUE/> if any only of such a frame was found, i.e. the component had already been loaded
+ previously
+ */
+ bool activateSubFrame(
+ const OUString& _rName,
+ const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode,
+ css::uno::Reference< css::lang::XComponent >& o_rComponent
+ ) const;
+
+ /** closes all frames of the given component
+
+ If a view for the component (given by name and type) has been loaded into one or more
+ frames (with potentially different OpenModes), then those frames are gracefully closed.
+
+ @return
+ <TRUE/> if and only if closing those frames was successful, or frames for the given sub component
+ exist.
+ */
+ bool closeSubFrames(
+ std::u16string_view _rName,
+ const sal_Int32 _nComponentType
+ );
+
+ /** searches for the given sub component
+
+ @param i_rComponent
+ the sub component to look up
+ @param o_rName
+ contains, upon successful return, the name of the sub component
+ @param o_nComponentType
+ contains, upon successful return, the type of the sub component
+ @return
+ <TRUE/> if and only if the component was found
+ */
+ bool lookupSubComponent(
+ const css::uno::Reference< css::lang::XComponent >& i_rComponent,
+ OUString& o_rName,
+ sal_Int32& o_rComponentType
+ );
+
+ private:
+ std::unique_ptr< SubComponentManager_Data > m_pData;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/templwin.cxx b/dbaccess/source/ui/app/templwin.cxx
new file mode 100644
index 000000000..e9940782d
--- /dev/null
+++ b/dbaccess/source/ui/app/templwin.cxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <templwin.hrc>
+#include "templwin.hxx"
+
+namespace SvtDocInfoTable_Impl
+{
+ OUString GetString(int nId)
+ {
+ for (size_t i = 0; i < SAL_N_ELEMENTS(STRARY_SVT_DOCINFO); ++i)
+ {
+ if (STRARY_SVT_DOCINFO[i].second == nId)
+ return DBA_RES(STRARY_SVT_DOCINFO[i].first);
+ }
+
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/templwin.hxx b/dbaccess/source/ui/app/templwin.hxx
new file mode 100644
index 000000000..8978a6ea3
--- /dev/null
+++ b/dbaccess/source/ui/app/templwin.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+namespace SvtDocInfoTable_Impl
+{
+OUString GetString(int nId);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/window_layout.txt b/dbaccess/source/ui/app/window_layout.txt
new file mode 100644
index 000000000..abb15f00b
--- /dev/null
+++ b/dbaccess/source/ui/app/window_layout.txt
@@ -0,0 +1,49 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+(still unfinished)
+
+OApplicationView
+|
++-OAppBorderWindow
+ |
+ +-OTitleWindow "Database"
+ | |
+ | +-OApplicationSwapWindow
+ | |
+ | +-OApplicationIconControl
+ |
+ +-OApplicationDetailView
+ |
+ +-OTitleWindow "Tasks"
+ | |
+ | +-OTasksWindow
+ | |
+ | +-OCreationList
+ |
+ +-OTitleWindow "Forms" "Tables" "Queries" "Reports"
+ |
+ +-OAppDetailPageHelper
+ |
+ +-SvTreeListBox*
+ |
+ +-FixedLine
+ |
+ +-Window (Border)
+ |
+ +-OPreviewWindow
diff --git a/dbaccess/source/ui/browser/AsynchronousLink.cxx b/dbaccess/source/ui/browser/AsynchronousLink.cxx
new file mode 100644
index 000000000..e4dcdb2f9
--- /dev/null
+++ b/dbaccess/source/ui/browser/AsynchronousLink.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbaccess/AsynchronousLink.hxx>
+#include <vcl/svapp.hxx>
+
+// OAsynchronousLink
+using namespace dbaui;
+OAsynchronousLink::OAsynchronousLink(const Link<void*, void>& _rHandler)
+ : m_aHandler(_rHandler)
+ , m_nEventId(nullptr)
+{
+}
+
+OAsynchronousLink::~OAsynchronousLink()
+{
+ {
+ ::osl::MutexGuard aEventGuard(m_aEventSafety);
+ if (m_nEventId)
+ Application::RemoveUserEvent(m_nEventId);
+ m_nEventId = nullptr;
+ }
+
+ {
+ ::osl::MutexGuard aDestructionGuard(m_aDestructionSafety);
+ // this is just for the case we're deleted while another thread just handled the event :
+ // if this other thread called our link while we were deleting the event here, the
+ // link handler blocked. With leaving the above block it continued, but now we are prevented
+ // to leave this destructor 'til the link handler recognizes that nEvent == 0 and leaves.
+ }
+}
+
+void OAsynchronousLink::Call(void* _pArgument)
+{
+ ::osl::MutexGuard aEventGuard(m_aEventSafety);
+ if (m_nEventId)
+ Application::RemoveUserEvent(m_nEventId);
+ m_nEventId = Application::PostUserEvent(LINK(this, OAsynchronousLink, OnAsyncCall), _pArgument);
+}
+
+void OAsynchronousLink::CancelCall()
+{
+ ::osl::MutexGuard aEventGuard(m_aEventSafety);
+ if (m_nEventId)
+ Application::RemoveUserEvent(m_nEventId);
+ m_nEventId = nullptr;
+}
+
+IMPL_LINK(OAsynchronousLink, OnAsyncCall, void*, _pArg, void)
+{
+ {
+ ::osl::MutexGuard aDestructionGuard(m_aDestructionSafety);
+ {
+ ::osl::MutexGuard aEventGuard(m_aEventSafety);
+ if (!m_nEventId)
+ // our destructor deleted the event just while we are waiting for m_aEventSafety
+ // -> get outta here
+ return;
+ m_nEventId = nullptr;
+ }
+ }
+ m_aHandler.Call(_pArg);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/brwctrlr.cxx b/dbaccess/source/ui/browser/brwctrlr.cxx
new file mode 100644
index 000000000..b8387b203
--- /dev/null
+++ b/dbaccess/source/ui/browser/brwctrlr.cxx
@@ -0,0 +1,2616 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <browserids.hxx>
+#include <brwctrlr.hxx>
+#include <brwview.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <queryfilter.hxx>
+#include <queryorder.hxx>
+#include <sqlmessage.hxx>
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/form/XBoundControl.hpp>
+#include <com/sun/star/form/XDatabaseParameterBroadcaster.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/form/XReset.hpp>
+#include <com/sun/star/form/XResetListener.hpp>
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/form/runtime/FormOperations.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
+#include <com/sun/star/sdb/XSQLErrorBroadcaster.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+#include <svx/fmsearch.hxx>
+#include <svx/svxdlg.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::form::runtime;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::dbtools;
+using namespace ::comphelper;
+using namespace ::svt;
+
+namespace dbaui
+{
+
+namespace {
+
+// OParameterContinuation
+class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
+{
+ Sequence< PropertyValue > m_aValues;
+
+public:
+ OParameterContinuation() { }
+
+ const Sequence< PropertyValue >& getValues() const { return m_aValues; }
+
+// XInteractionSupplyParameters
+ virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) override;
+};
+
+}
+
+void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues )
+{
+ m_aValues = _rValues;
+}
+
+// a helper class implementing a runtime::XFormController, will be aggregated by SbaXDataBrowserController
+// (we can't derive from XFormController as it's base class is XTabController and the XTabController::getModel collides
+// with the XController::getModel implemented in our base class SbaXDataBrowserController)
+class SbaXDataBrowserController::FormControllerImpl
+ : public ::cppu::WeakAggImplHelper2< css::form::runtime::XFormController,
+ css::frame::XFrameActionListener >
+{
+ friend class SbaXDataBrowserController;
+ ::comphelper::OInterfaceContainerHelper3<css::form::XFormControllerListener> m_aActivateListeners;
+ SbaXDataBrowserController* m_pOwner;
+
+public:
+ explicit FormControllerImpl(SbaXDataBrowserController* pOwner);
+
+ // XFormController
+ virtual css::uno::Reference< css::form::runtime::XFormOperations > SAL_CALL getFormOperations() override;
+ virtual css::uno::Reference< css::awt::XControl > SAL_CALL getCurrentControl() override;
+ virtual void SAL_CALL addActivateListener(const css::uno::Reference< css::form::XFormControllerListener > & l) override;
+ virtual void SAL_CALL removeActivateListener(const css::uno::Reference< css::form::XFormControllerListener > & l) override;
+ virtual void SAL_CALL addChildController( const css::uno::Reference< css::form::runtime::XFormController >& ChildController ) override;
+ virtual css::uno::Reference< css::form::runtime::XFormControllerContext > SAL_CALL getContext() override;
+ virtual void SAL_CALL setContext( const css::uno::Reference< css::form::runtime::XFormControllerContext >& _context ) override;
+ virtual css::uno::Reference< css::task::XInteractionHandler > SAL_CALL getInteractionHandler() override;
+ virtual void SAL_CALL setInteractionHandler( const css::uno::Reference< css::task::XInteractionHandler >& _interactionHandler ) override;
+
+ // XChild, base of XFormController
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ // XComponent, base of XFormController
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XIndexAccess, base of XFormController
+ virtual ::sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override;
+
+ // XElementAccess, base of XIndexAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XEnumerationAccess, base of XElementAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+ // XModifyBroadcaster, base of XFormController
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XConfirmDeleteBroadcaster, base of XFormController
+ virtual void SAL_CALL addConfirmDeleteListener( const css::uno::Reference< css::form::XConfirmDeleteListener >& aListener ) override;
+ virtual void SAL_CALL removeConfirmDeleteListener( const css::uno::Reference< css::form::XConfirmDeleteListener >& aListener ) override;
+
+ // XSQLErrorBroadcaster, base of XFormController
+ virtual void SAL_CALL addSQLErrorListener( const css::uno::Reference< css::sdb::XSQLErrorListener >& Listener ) override;
+ virtual void SAL_CALL removeSQLErrorListener( const css::uno::Reference< css::sdb::XSQLErrorListener >& Listener ) override;
+
+ // XRowSetApproveBroadcaster, base of XFormController
+ virtual void SAL_CALL addRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override;
+ virtual void SAL_CALL removeRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override;
+
+ // XDatabaseParameterBroadcaster2, base of XFormController
+ virtual void SAL_CALL addDatabaseParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override;
+ virtual void SAL_CALL removeDatabaseParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override;
+
+ // XDatabaseParameterBroadcaster, base of XDatabaseParameterBroadcaster2
+ virtual void SAL_CALL addParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override;
+ virtual void SAL_CALL removeParameterListener( const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener ) override;
+
+ // XModeSelector, base of XFormController
+ virtual void SAL_CALL setMode( const OUString& aMode ) override;
+ virtual OUString SAL_CALL getMode( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedModes( ) override;
+ virtual sal_Bool SAL_CALL supportsMode( const OUString& aMode ) override;
+
+ // XTabController, base of XFormController
+ virtual void SAL_CALL setModel(const css::uno::Reference< css::awt::XTabControllerModel > & Model) override;
+ virtual css::uno::Reference< css::awt::XTabControllerModel > SAL_CALL getModel() override;
+ virtual void SAL_CALL setContainer(const css::uno::Reference< css::awt::XControlContainer > & Container) override;
+ virtual css::uno::Reference< css::awt::XControlContainer > SAL_CALL getContainer() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::awt::XControl > > SAL_CALL getControls() override;
+ virtual void SAL_CALL autoTabOrder() override;
+ virtual void SAL_CALL activateTabOrder() override;
+ virtual void SAL_CALL activateFirst() override;
+ virtual void SAL_CALL activateLast() override;
+
+ // XFrameActionListener
+ virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent& aEvent) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+protected:
+ virtual ~FormControllerImpl() override;
+};
+
+SbaXDataBrowserController::FormControllerImpl::FormControllerImpl(SbaXDataBrowserController* _pOwner)
+ :m_aActivateListeners(_pOwner->getMutex())
+ ,m_pOwner(_pOwner)
+{
+
+ OSL_ENSURE(m_pOwner, "SbaXDataBrowserController::FormControllerImpl::FormControllerImpl : invalid Owner !");
+}
+
+SbaXDataBrowserController::FormControllerImpl::~FormControllerImpl()
+{
+
+}
+
+Reference< runtime::XFormOperations > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getFormOperations()
+{
+ return FormOperations::createWithFormController( m_pOwner->m_xContext, this );
+}
+
+Reference< css::awt::XControl > SbaXDataBrowserController::FormControllerImpl::getCurrentControl()
+{
+ return m_pOwner->getBrowserView() ? m_pOwner->getBrowserView()->getGridControl() : Reference< css::awt::XControl > ();
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addActivateListener(const Reference< css::form::XFormControllerListener > & l)
+{
+ m_aActivateListeners.addInterface(l);
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeActivateListener(const Reference< css::form::XFormControllerListener > & l)
+{
+ m_aActivateListeners.removeInterface(l);
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addChildController( const Reference< runtime::XFormController >& )
+{
+ // not supported
+ throw IllegalArgumentException( OUString(), *this, 1 );
+}
+
+Reference< runtime::XFormControllerContext > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getContext()
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::getContext: no support!!" );
+ return nullptr;
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setContext( const Reference< runtime::XFormControllerContext >& /*_context*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::setContext: no support!!" );
+}
+
+Reference< XInteractionHandler > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getInteractionHandler()
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::getInteractionHandler: no support!!" );
+ return nullptr;
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setInteractionHandler( const Reference< XInteractionHandler >& /*_interactionHandler*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::setInteractionHandler: no support!!" );
+}
+
+Reference< XInterface > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getParent( )
+{
+ // don't have any parent form controllers
+ return nullptr;
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setParent( const Reference< XInterface >& /*Parent*/ )
+{
+ throw NoSupportException( OUString(), *this );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::dispose( )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::dispose: no, you do *not* want to do this!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addEventListener( const Reference< XEventListener >& /*xListener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addEventListener: no support!!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeEventListener( const Reference< XEventListener >& /*aListener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeEventListener: no support!!" );
+}
+
+::sal_Int32 SAL_CALL SbaXDataBrowserController::FormControllerImpl::getCount( )
+{
+ // no sub controllers, never
+ return 0;
+}
+
+Any SAL_CALL SbaXDataBrowserController::FormControllerImpl::getByIndex( ::sal_Int32 /*Index*/ )
+{
+ // no sub controllers, never
+ throw IndexOutOfBoundsException( OUString(), *this );
+}
+
+Type SAL_CALL SbaXDataBrowserController::FormControllerImpl::getElementType( )
+{
+ return ::cppu::UnoType< runtime::XFormController >::get();
+}
+
+sal_Bool SAL_CALL SbaXDataBrowserController::FormControllerImpl::hasElements( )
+{
+ // no sub controllers, never
+ return false;
+}
+
+Reference< XEnumeration > SAL_CALL SbaXDataBrowserController::FormControllerImpl::createEnumeration( )
+{
+ return new ::comphelper::OEnumerationByIndex( this );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addModifyListener( const Reference< XModifyListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addModifyListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeModifyListener( const Reference< XModifyListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeModifyListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addConfirmDeleteListener( const Reference< XConfirmDeleteListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addConfirmDeleteListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeConfirmDeleteListener( const Reference< XConfirmDeleteListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeConfirmDeleteListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addSQLErrorListener( const Reference< XSQLErrorListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addSQLErrorListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeSQLErrorListener( const Reference< XSQLErrorListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeSQLErrorListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addRowSetApproveListener( const Reference< XRowSetApproveListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addRowSetApproveListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeRowSetApproveListener( const Reference< XRowSetApproveListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeRowSetApproveListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addDatabaseParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addDatabaseParameterListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeDatabaseParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeDatabaseParameterListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::addParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::addParameterListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::removeParameterListener( const Reference< XDatabaseParameterListener >& /*_Listener*/ )
+{
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::FormControllerImpl::removeParameterListener: no support!" );
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setMode( const OUString& _rMode )
+{
+ if ( !supportsMode( _rMode ) )
+ throw NoSupportException();
+}
+
+OUString SAL_CALL SbaXDataBrowserController::FormControllerImpl::getMode( )
+{
+ return "DataMode";
+}
+
+Sequence< OUString > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getSupportedModes( )
+{
+ Sequence< OUString > aModes { "DataMode" };
+ return aModes;
+}
+
+sal_Bool SAL_CALL SbaXDataBrowserController::FormControllerImpl::supportsMode( const OUString& aMode )
+{
+ return aMode == "DataMode";
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setModel(const Reference< css::awt::XTabControllerModel > & /*Model*/)
+{
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::setModel : invalid call, can't change my model !");
+}
+
+Reference< css::awt::XTabControllerModel > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getModel()
+{
+ return Reference< XTabControllerModel >(m_pOwner->getRowSet(), UNO_QUERY);
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::setContainer(const Reference< css::awt::XControlContainer > &)
+{
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::setContainer : invalid call, can't change my container !");
+}
+
+Reference< css::awt::XControlContainer > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getContainer()
+{
+ if (m_pOwner->getBrowserView())
+ return m_pOwner->getBrowserView()->getContainer();
+ return Reference< css::awt::XControlContainer > ();
+}
+
+Sequence< Reference< css::awt::XControl > > SAL_CALL SbaXDataBrowserController::FormControllerImpl::getControls()
+{
+ if (m_pOwner->getBrowserView())
+ {
+ Reference< css::awt::XControl > xGrid = m_pOwner->getBrowserView()->getGridControl();
+ return Sequence< Reference< css::awt::XControl > >(&xGrid, 1);
+ }
+ return Sequence< Reference< css::awt::XControl > >();
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::autoTabOrder()
+{
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::autoTabOrder : nothing to do (always have only one control) !");
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::activateTabOrder()
+{
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::FormControllerImpl::activateTabOrder : nothing to do (always have only one control) !");
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::activateFirst()
+{
+ if (m_pOwner->getBrowserView())
+ m_pOwner->getBrowserView()->getVclControl()->ActivateCell();
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::activateLast()
+{
+ if (m_pOwner->getBrowserView())
+ m_pOwner->getBrowserView()->getVclControl()->ActivateCell();
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::frameAction(const css::frame::FrameActionEvent& /*aEvent*/)
+{
+}
+
+void SAL_CALL SbaXDataBrowserController::FormControllerImpl::disposing(const css::lang::EventObject& /*Source*/)
+{
+ // nothing to do
+ // we don't add ourself as listener to any broadcasters, so we are not responsible for removing us
+}
+
+// SbaXDataBrowserController
+Sequence< Type > SAL_CALL SbaXDataBrowserController::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ SbaXDataBrowserController_Base::getTypes(),
+ m_xFormControllerImpl->getTypes()
+ );
+}
+
+Sequence< sal_Int8 > SAL_CALL SbaXDataBrowserController::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any SAL_CALL SbaXDataBrowserController::queryInterface(const Type& _rType)
+{
+ // check for our additional interfaces
+ Any aRet = SbaXDataBrowserController_Base::queryInterface(_rType);
+
+ // check for our aggregate (implementing the XFormController)
+ if (!aRet.hasValue())
+ aRet = m_xFormControllerImpl->queryAggregation(_rType);
+
+ // no more to offer
+ return aRet;
+}
+
+SbaXDataBrowserController::SbaXDataBrowserController(const Reference< css::uno::XComponentContext >& _rM)
+ :SbaXDataBrowserController_Base(_rM)
+ ,m_nRowSetPrivileges(0)
+ ,m_aInvalidateClipboard("dbaui::SbaXDataBrowserController m_aInvalidateClipboard")
+ ,m_aAsyncGetCellFocus(LINK(this, SbaXDataBrowserController, OnAsyncGetCellFocus))
+ ,m_aAsyncDisplayError( LINK( this, SbaXDataBrowserController, OnAsyncDisplayError ) )
+ ,m_sStateSaveRecord(DBA_RES(RID_STR_SAVE_CURRENT_RECORD))
+ ,m_sStateUndoRecord(DBA_RES(RID_STR_UNDO_MODIFY_RECORD))
+ ,m_sModuleIdentifier( OUString( "com.sun.star.sdb.DataSourceBrowser" ) )
+ ,m_nFormActionNestingLevel(0)
+ ,m_bLoadCanceled( false )
+ ,m_bCannotSelectUnfiltered( true )
+{
+ // create the form controller aggregate
+ osl_atomic_increment(&m_refCount);
+ {
+ m_xFormControllerImpl = new FormControllerImpl(this);
+ m_xFormControllerImpl->setDelegator(*this);
+ }
+ osl_atomic_decrement(&m_refCount);
+
+ m_aInvalidateClipboard.SetInvokeHandler(LINK(this, SbaXDataBrowserController, OnInvalidateClipboard));
+ m_aInvalidateClipboard.SetTimeout(300);
+}
+
+SbaXDataBrowserController::~SbaXDataBrowserController()
+{
+ // deleteView();
+ // release the aggregated form controller
+ if (m_xFormControllerImpl.is())
+ {
+ Reference< XInterface > xEmpty;
+ m_xFormControllerImpl->setDelegator(xEmpty);
+ }
+
+}
+
+void SbaXDataBrowserController::startFrameListening( const Reference< XFrame >& _rxFrame )
+{
+ SbaXDataBrowserController_Base::startFrameListening( _rxFrame );
+
+ Reference< XFrameActionListener > xAggListener;
+ if ( m_xFormControllerImpl.is() )
+ m_xFormControllerImpl->queryAggregation( cppu::UnoType<XFrameActionListener>::get() ) >>= xAggListener;
+
+ if ( _rxFrame.is() && xAggListener.is() )
+ _rxFrame->addFrameActionListener( xAggListener );
+}
+
+void SbaXDataBrowserController::stopFrameListening( const Reference< XFrame >& _rxFrame )
+{
+ SbaXDataBrowserController_Base::stopFrameListening( _rxFrame );
+
+ Reference< XFrameActionListener > xAggListener;
+ if ( m_xFormControllerImpl.is() )
+ m_xFormControllerImpl->queryAggregation( cppu::UnoType<XFrameActionListener>::get() ) >>= xAggListener;
+
+ if ( _rxFrame.is() && xAggListener.is() )
+ _rxFrame->removeFrameActionListener( xAggListener );
+}
+
+void SbaXDataBrowserController::onStartLoading( const Reference< XLoadable >& _rxLoadable )
+{
+ m_bLoadCanceled = false;
+ m_bCannotSelectUnfiltered = false;
+
+ Reference< XWarningsSupplier > xWarnings( _rxLoadable, UNO_QUERY );
+ if ( xWarnings.is() )
+ {
+ try
+ {
+ xWarnings->clearWarnings();
+ }
+ catch(const SQLException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void SbaXDataBrowserController::impl_checkForCannotSelectUnfiltered( const SQLExceptionInfo& _rError )
+{
+ ::connectivity::ErrorCode nErrorCode( connectivity::SQLError::getErrorCode( sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED ) );
+ if ( static_cast<const SQLException*>(_rError)->ErrorCode == nErrorCode )
+ {
+ m_bCannotSelectUnfiltered = true;
+ InvalidateFeature( ID_BROWSER_FILTERCRIT );
+ }
+}
+
+bool SbaXDataBrowserController::reloadForm( const Reference< XLoadable >& _rxLoadable )
+{
+ weld::WaitObject aWO(getFrameWeld());
+
+ onStartLoading( _rxLoadable );
+
+ FormErrorHelper aReportError(this);
+ if (_rxLoadable->isLoaded())
+ _rxLoadable->reload();
+ else
+ _rxLoadable->load();
+
+ m_xParser.clear();
+ const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)))
+ xFormSet->getPropertyValue(PROPERTY_SINGLESELECTQUERYCOMPOSER) >>= m_xParser;
+#if 0
+ {
+ const Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY );
+ const Reference< XSingleSelectQueryAnalyzer > xAnalyzer( xRowSetProps->getPropertyValue( PROPERTY_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY );
+ if ( xAnalyzer.is() )
+ {
+ const Reference< XIndexAccess > xOrderColumns( xAnalyzer->getOrderColumns(), UNO_SET_THROW );
+ const sal_Int32 nOrderColumns( xOrderColumns->getCount() );
+ for ( sal_Int32 c=0; c<nOrderColumns; ++c )
+ {
+ const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW );
+ OUString sColumnName;
+ OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName);
+ OUString sTableName;
+ OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName);
+ (void)sColumnName;
+ (void)sTableName;
+ }
+ }
+ }
+#endif
+
+ Reference< XWarningsSupplier > xWarnings( _rxLoadable, UNO_QUERY );
+ if ( xWarnings.is() )
+ {
+ try
+ {
+ SQLExceptionInfo aInfo( xWarnings->getWarnings() );
+ if ( aInfo.isValid() )
+ {
+ showError( aInfo );
+ impl_checkForCannotSelectUnfiltered( aInfo );
+ }
+ }
+ catch(const SQLException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ return _rxLoadable->isLoaded();
+}
+
+void SbaXDataBrowserController::initFormatter()
+{
+ // create a formatter working with the connections format supplier
+ Reference< css::util::XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(::dbtools::getConnection(m_xRowSet), true, getORB()));
+
+ if(xSupplier.is())
+ {
+ // create a new formatter
+ m_xFormatter.set(util::NumberFormatter::create(getORB()), UNO_QUERY_THROW);
+ m_xFormatter->attachNumberFormatsSupplier(xSupplier);
+ }
+ else // clear the formatter
+ m_xFormatter = nullptr;
+}
+
+void SbaXDataBrowserController::describeSupportedFeatures()
+{
+ SbaXDataBrowserController_Base::describeSupportedFeatures();
+ implDescribeSupportedFeature( ".uno:FormSlots/undoRecord", ID_BROWSER_UNDORECORD, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:FormController/undoRecord", ID_BROWSER_UNDORECORD, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:RecUndo", ID_BROWSER_UNDORECORD, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:FormSlots/saveRecord", ID_BROWSER_SAVERECORD, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:FormController/saveRecord", ID_BROWSER_SAVERECORD, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:RecSave", ID_BROWSER_SAVERECORD, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVERECORD, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:RecSearch", SID_FM_SEARCH, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:AutoFilter", SID_FM_AUTOFILTER, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:Refresh", SID_FM_REFRESH, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:OrderCrit", SID_FM_ORDERCRIT, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:RemoveFilterSort", SID_FM_REMOVE_FILTER_SORT,CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:FormFiltered", SID_FM_FORM_FILTERED, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:FilterCrit", SID_FM_FILTERCRIT, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:Sortup", ID_BROWSER_SORTUP, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:SortDown", ID_BROWSER_SORTDOWN, CommandGroup::CONTROLS );
+ implDescribeSupportedFeature( ".uno:FormSlots/deleteRecord", SID_FM_DELETEROWS, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:FormSlots/insertRecord", ID_BROWSER_INSERT_ROW, CommandGroup::INSERT );
+}
+
+bool SbaXDataBrowserController::Construct(vcl::Window* pParent)
+{
+ // create/initialize the form and the grid model
+ m_xRowSet = CreateForm();
+ if (!m_xRowSet.is())
+ return false;
+
+ m_xColumnsSupplier.set(m_xRowSet,UNO_QUERY);
+ m_xLoadable.set(m_xRowSet,UNO_QUERY);
+
+ Reference< XPropertySet > xFormProperties( m_xRowSet, UNO_QUERY );
+ if ( !InitializeForm( xFormProperties ) )
+ return false;
+
+ m_xGridModel = CreateGridModel();
+ if (!m_xGridModel.is())
+ return false;
+
+ // set the formatter if available
+ initFormatter();
+
+ // we want to have a grid with a "flat" border
+ Reference< XPropertySet > xGridSet(m_xGridModel, UNO_QUERY);
+ if ( xGridSet.is() )
+ xGridSet->setPropertyValue(PROPERTY_BORDER, Any(sal_Int16(2)));
+
+
+ // marry them
+ Reference< css::container::XNameContainer > xNameCont(m_xRowSet, UNO_QUERY);
+ {
+ OUString sText(DBA_RES(STR_DATASOURCE_GRIDCONTROL_NAME));
+ xNameCont->insertByName(sText, Any(m_xGridModel));
+ }
+
+ // create the view
+ setView( VclPtr<UnoDataBrowserView>::Create( pParent, *this, getORB() ) );
+ if (!getBrowserView())
+ return false;
+
+ // late construction
+ bool bSuccess = false;
+ try
+ {
+ getBrowserView()->Construct(getControlModel());
+ bSuccess = true;
+ }
+ catch(SQLException&)
+ {
+ }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::Construct : the construction of UnoDataBrowserView failed !");
+ }
+
+ if (!bSuccess)
+ {
+ // deleteView();
+ return false;
+ }
+
+ // now that we have a view we can create the clipboard listener
+ m_aSystemClipboard = TransferableDataHelper::CreateFromSystemClipboard( getView() );
+ m_aSystemClipboard.StartClipboardListening( );
+
+ m_pClipboardNotifier = new TransferableClipboardListener( LINK( this, SbaXDataBrowserController, OnClipboardChanged ) );
+ m_pClipboardNotifier->AddListener( getView() );
+
+ // this call create the toolbox
+ SbaXDataBrowserController_Base::Construct(pParent);
+
+ getBrowserView()->Show();
+
+ // set the callbacks for the grid control
+ SbaGridControl* pVclGrid = getBrowserView()->getVclControl();
+ OSL_ENSURE(pVclGrid, "SbaXDataBrowserController::Construct : have no VCL control !");
+ pVclGrid->SetMasterListener(this);
+
+ // add listeners...
+
+ // ... to the form model
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if (xFormSet.is())
+ {
+ xFormSet->addPropertyChangeListener(PROPERTY_ISNEW, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->addPropertyChangeListener(PROPERTY_ISMODIFIED, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->addPropertyChangeListener(PROPERTY_ROWCOUNT, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->addPropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->addPropertyChangeListener(PROPERTY_ORDER, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->addPropertyChangeListener(PROPERTY_FILTER, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->addPropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->addPropertyChangeListener(PROPERTY_APPLYFILTER, static_cast<XPropertyChangeListener*>(this));
+ }
+ Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY);
+ if (xFormError.is())
+ xFormError->addSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this));
+
+ if (m_xLoadable.is())
+ m_xLoadable->addLoadListener(this);
+
+ Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(getRowSet(), UNO_QUERY);
+ if (xFormParameter.is())
+ xFormParameter->addParameterListener(static_cast<css::form::XDatabaseParameterListener*>(this));
+
+ addModelListeners(getControlModel());
+ addControlListeners(getBrowserView()->getGridControl());
+
+ // load the form
+ return LoadForm();
+}
+
+bool SbaXDataBrowserController::LoadForm()
+{
+ reloadForm( m_xLoadable );
+ return true;
+}
+
+void SbaXDataBrowserController::AddColumnListener(const Reference< XPropertySet > & /*xCol*/)
+{
+ // we're not interested in any column properties...
+}
+
+void SbaXDataBrowserController::RemoveColumnListener(const Reference< XPropertySet > & /*xCol*/)
+{
+}
+
+Reference< XRowSet > SbaXDataBrowserController::CreateForm()
+{
+ return Reference< XRowSet > (
+ getORB()->getServiceManager()->createInstanceWithContext("com.sun.star.form.component.Form", getORB()),
+ UNO_QUERY);
+}
+
+Reference< css::form::XFormComponent > SbaXDataBrowserController::CreateGridModel()
+{
+ return Reference< css::form::XFormComponent > (
+ getORB()->getServiceManager()->createInstanceWithContext("com.sun.star.form.component.GridControl", getORB()),
+ UNO_QUERY);
+}
+
+void SbaXDataBrowserController::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
+{
+ // ... all the grid columns
+ addColumnListeners(_xGridControlModel);
+
+ // (we are interested in all columns the grid has (and only in these) so we have to listen to the container, too)
+ Reference< css::container::XContainer > xColContainer(_xGridControlModel, UNO_QUERY);
+ if (xColContainer.is())
+ xColContainer->addContainerListener(static_cast<css::container::XContainerListener*>(this));
+
+ Reference< css::form::XReset > xReset(_xGridControlModel, UNO_QUERY);
+ if (xReset.is())
+ xReset->addResetListener(static_cast<css::form::XResetListener*>(this));
+}
+
+void SbaXDataBrowserController::removeModelListeners(const Reference< XControlModel > & _xGridControlModel)
+{
+ // every single column model
+ Reference< XIndexContainer > xColumns(_xGridControlModel, UNO_QUERY);
+ if (xColumns.is())
+ {
+ sal_Int32 nCount = xColumns->getCount();
+ for (sal_Int32 i=0; i < nCount; ++i)
+ {
+ Reference< XPropertySet > xCol(xColumns->getByIndex(i),UNO_QUERY);
+ RemoveColumnListener(xCol);
+ }
+ }
+
+ Reference< XContainer > xColContainer(_xGridControlModel, UNO_QUERY);
+ if (xColContainer.is())
+ xColContainer->removeContainerListener( this );
+
+ Reference< XReset > xReset(_xGridControlModel, UNO_QUERY);
+ if (xReset.is())
+ xReset->removeResetListener( this );
+}
+
+void SbaXDataBrowserController::addControlListeners(const Reference< css::awt::XControl > & _xGridControl)
+{
+ // to ge the 'modified' for the current cell
+ Reference< XModifyBroadcaster > xBroadcaster(getBrowserView()->getGridControl(), UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addModifyListener(static_cast<XModifyListener*>(this));
+
+ // introduce ourself as dispatch provider for the grid
+ Reference< XDispatchProviderInterception > xInterception(getBrowserView()->getGridControl(), UNO_QUERY);
+ if (xInterception.is())
+ xInterception->registerDispatchProviderInterceptor(static_cast<XDispatchProviderInterceptor*>(this));
+
+ // add as focus listener to the control (needed for the form controller functionality)
+ Reference< XWindow > xWindow(_xGridControl, UNO_QUERY);
+ if (xWindow.is())
+ xWindow->addFocusListener(this);
+}
+
+void SbaXDataBrowserController::removeControlListeners(const Reference< css::awt::XControl > & _xGridControl)
+{
+ Reference< XModifyBroadcaster > xBroadcaster(_xGridControl, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeModifyListener(static_cast<XModifyListener*>(this));
+
+ Reference< XDispatchProviderInterception > xInterception(_xGridControl, UNO_QUERY);
+ if (xInterception.is())
+ xInterception->releaseDispatchProviderInterceptor(static_cast<XDispatchProviderInterceptor*>(this));
+
+ Reference< XWindow > xWindow(_xGridControl, UNO_QUERY);
+ if (xWindow.is())
+ xWindow->removeFocusListener(this);
+}
+
+void SAL_CALL SbaXDataBrowserController::focusGained(const FocusEvent& /*e*/)
+{
+ // notify our activate listeners (registered on the form controller aggregate)
+ EventObject aEvt(*this);
+ m_xFormControllerImpl->m_aActivateListeners.notifyEach( &css::form::XFormControllerListener::formActivated, aEvt );
+}
+
+void SAL_CALL SbaXDataBrowserController::focusLost(const FocusEvent& e)
+{
+ // some general checks
+ if (!getBrowserView() || !getBrowserView()->getGridControl().is())
+ return;
+ Reference< XVclWindowPeer > xMyGridPeer(getBrowserView()->getGridControl()->getPeer(), UNO_QUERY);
+ if (!xMyGridPeer.is())
+ return;
+ Reference< XWindowPeer > xNextControlPeer(e.NextFocus, UNO_QUERY);
+ if (!xNextControlPeer.is())
+ return;
+
+ // don't do a notification if it remains in the family (i.e. a child of the grid control gets the focus)
+ if (xMyGridPeer->isChild(xNextControlPeer))
+ return;
+
+ if (xMyGridPeer == xNextControlPeer)
+ return;
+
+ // notify the listeners that the "form" we represent has been deactivated
+ EventObject aEvt(*this);
+ m_xFormControllerImpl->m_aActivateListeners.notifyEach( &css::form::XFormControllerListener::formDeactivated, aEvt );
+
+ // commit the changes of the grid control (as we're deactivated)
+ Reference< XBoundComponent > xCommitable(getBrowserView()->getGridControl(), UNO_QUERY);
+ if (xCommitable.is())
+ xCommitable->commit();
+ else
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::focusLost : why is my control not committable?");
+}
+
+void SbaXDataBrowserController::disposingFormModel(const css::lang::EventObject& Source)
+{
+ Reference< XPropertySet > xSourceSet(Source.Source, UNO_QUERY);
+ if (xSourceSet.is())
+ {
+ xSourceSet->removePropertyChangeListener(PROPERTY_ISNEW, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_ISMODIFIED, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_ROWCOUNT, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_ORDER, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_FILTER, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_APPLYFILTER, static_cast<XPropertyChangeListener*>(this));
+ }
+
+ Reference< css::sdb::XSQLErrorBroadcaster > xFormError(Source.Source, UNO_QUERY);
+ if (xFormError.is())
+ xFormError->removeSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this));
+
+ if (m_xLoadable.is())
+ m_xLoadable->removeLoadListener(this);
+
+ Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(Source.Source, UNO_QUERY);
+ if (xFormParameter.is())
+ xFormParameter->removeParameterListener(static_cast<css::form::XDatabaseParameterListener*>(this));
+}
+
+void SbaXDataBrowserController::disposingColumnModel(const css::lang::EventObject& Source)
+{
+ RemoveColumnListener(Reference< XPropertySet > (Source.Source, UNO_QUERY));
+}
+
+void SbaXDataBrowserController::disposing(const EventObject& Source)
+{
+ // if it's a component other than our aggregate, forward it to the aggregate
+ if ( uno::Reference<XInterface>(static_cast<cppu::OWeakObject*>(m_xFormControllerImpl.get()), UNO_QUERY) != Source.Source )
+ {
+ Reference< XEventListener > xAggListener;
+ m_xFormControllerImpl->queryAggregation( cppu::UnoType<decltype(xAggListener)>::get() ) >>= xAggListener;
+ if ( xAggListener.is( ))
+ xAggListener->disposing( Source );
+ }
+
+ // is it the grid control ?
+ if (getBrowserView())
+ {
+ Reference< css::awt::XControl > xSourceControl(Source.Source, UNO_QUERY);
+ if (xSourceControl == getBrowserView()->getGridControl())
+ removeControlListeners(getBrowserView()->getGridControl());
+ }
+
+ // its model (the container of the columns) ?
+ if (getControlModel() == Source.Source)
+ removeModelListeners(getControlModel());
+
+ // the form's model ?
+ if (getRowSet() == Source.Source)
+ disposingFormModel(Source);
+
+ // from a single column model ?
+ Reference< XPropertySet > xSourceSet(Source.Source, UNO_QUERY);
+ if (xSourceSet.is())
+ {
+ Reference< XPropertySetInfo > xInfo = xSourceSet->getPropertySetInfo();
+ // we assume that columns have a Width property and all other sets we are listening to don't have
+ if (xInfo->hasPropertyByName(PROPERTY_WIDTH))
+ disposingColumnModel(Source);
+ }
+ SbaXDataBrowserController_Base::OGenericUnoController::disposing( Source );
+}
+
+void SAL_CALL SbaXDataBrowserController::setIdentifier( const OUString& Identifier )
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ m_sModuleIdentifier = Identifier;
+}
+
+OUString SAL_CALL SbaXDataBrowserController::getIdentifier( )
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_sModuleIdentifier;
+}
+
+void SbaXDataBrowserController::propertyChange(const PropertyChangeEvent& evt)
+{
+ Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
+ if (!xSource.is())
+ return;
+
+ SolarMutexGuard aGuard;
+ // the IsModified changed to sal_False ?
+ if ( evt.PropertyName == PROPERTY_ISMODIFIED
+ && !::comphelper::getBOOL(evt.NewValue)
+ )
+ { // -> the current field isn't modified anymore, too
+ setCurrentModified( false );
+ }
+
+ // switching to a new record ?
+ if ( evt.PropertyName == PROPERTY_ISNEW
+ && ::comphelper::getBOOL(evt.NewValue)
+ )
+ {
+ if (::comphelper::getINT32(xSource->getPropertyValue(PROPERTY_ROWCOUNT)) == 0)
+ // if we're switching to a new record and didn't have any records before we need to invalidate
+ // all slots (as the cursor was invalid before the mode change and so the slots were disabled)
+ InvalidateAll();
+ }
+
+ if (evt.PropertyName == PROPERTY_FILTER)
+ {
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+ }
+ else if (evt.PropertyName == PROPERTY_HAVING_CLAUSE)
+ {
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+ }
+ else if (evt.PropertyName == PROPERTY_ORDER)
+ {
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+ }
+
+ // a new record count ? -> may be our search availability has changed
+ if (evt.PropertyName == PROPERTY_ROWCOUNT)
+ {
+ sal_Int32 nNewValue = 0, nOldValue = 0;
+ evt.NewValue >>= nNewValue;
+ evt.OldValue >>= nOldValue;
+ if((nOldValue == 0 && nNewValue != 0) || (nOldValue != 0 && nNewValue == 0))
+ InvalidateAll();
+ }
+}
+
+void SbaXDataBrowserController::modified(const css::lang::EventObject& /*aEvent*/)
+{
+ setCurrentModified( true );
+}
+
+void SbaXDataBrowserController::elementInserted(const css::container::ContainerEvent& evt)
+{
+ OSL_ENSURE(Reference< XInterface >(evt.Source, UNO_QUERY).get() == Reference< XInterface >(getControlModel(), UNO_QUERY).get(),
+ "SbaXDataBrowserController::elementInserted: where did this come from (not from the grid model)?!");
+ Reference< XPropertySet > xNewColumn(evt.Element,UNO_QUERY);
+ if ( xNewColumn.is() )
+ AddColumnListener(xNewColumn);
+}
+
+void SbaXDataBrowserController::elementRemoved(const css::container::ContainerEvent& evt)
+{
+ OSL_ENSURE(Reference< XInterface >(evt.Source, UNO_QUERY).get() == Reference< XInterface >(getControlModel(), UNO_QUERY).get(),
+ "SbaXDataBrowserController::elementRemoved: where did this come from (not from the grid model)?!");
+ Reference< XPropertySet > xOldColumn(evt.Element,UNO_QUERY);
+ if ( xOldColumn.is() )
+ RemoveColumnListener(xOldColumn);
+}
+
+void SbaXDataBrowserController::elementReplaced(const css::container::ContainerEvent& evt)
+{
+ OSL_ENSURE(Reference< XInterface >(evt.Source, UNO_QUERY).get() == Reference< XInterface >(getControlModel(), UNO_QUERY).get(),
+ "SbaXDataBrowserController::elementReplaced: where did this come from (not from the grid model)?!");
+ Reference< XPropertySet > xOldColumn(evt.ReplacedElement,UNO_QUERY);
+ if ( xOldColumn.is() )
+ RemoveColumnListener(xOldColumn);
+
+ Reference< XPropertySet > xNewColumn(evt.Element,UNO_QUERY);
+ if ( xNewColumn.is() )
+ AddColumnListener(xNewColumn);
+}
+
+sal_Bool SbaXDataBrowserController::suspend(sal_Bool /*bSuspend*/)
+{
+ m_aAsyncGetCellFocus.CancelCall();
+ m_aAsyncDisplayError.CancelCall();
+ m_aAsyncInvalidateAll.CancelCall();
+
+ bool bSuccess = SaveModified();
+ return bSuccess;
+}
+
+void SbaXDataBrowserController::disposing()
+{
+ // the base class
+ SbaXDataBrowserController_Base::OGenericUnoController::disposing();
+
+ // the data source
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if (xFormSet.is())
+ {
+ xFormSet->removePropertyChangeListener(PROPERTY_ISNEW, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->removePropertyChangeListener(PROPERTY_ISMODIFIED, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->removePropertyChangeListener(PROPERTY_ROWCOUNT, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->removePropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->removePropertyChangeListener(PROPERTY_ORDER, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->removePropertyChangeListener(PROPERTY_FILTER, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->removePropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast<XPropertyChangeListener*>(this));
+ xFormSet->removePropertyChangeListener(PROPERTY_APPLYFILTER, static_cast<XPropertyChangeListener*>(this));
+ }
+
+ Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY);
+ if (xFormError.is())
+ xFormError->removeSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this));
+
+ if (m_xLoadable.is())
+ m_xLoadable->removeLoadListener(this);
+
+ Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(getRowSet(), UNO_QUERY);
+ if (xFormParameter.is())
+ xFormParameter->removeParameterListener(static_cast<css::form::XDatabaseParameterListener*>(this));
+
+ removeModelListeners(getControlModel());
+
+ if ( getView() && m_pClipboardNotifier.is() )
+ {
+ m_pClipboardNotifier->ClearCallbackLink();
+ m_pClipboardNotifier->RemoveListener( getView() );
+ m_pClipboardNotifier.clear();
+ }
+
+ if (getBrowserView())
+ {
+ removeControlListeners(getBrowserView()->getGridControl());
+ // don't delete explicitly, this is done by the owner (and user) of this controller (me hopes ...)
+ clearView();
+ }
+
+ if(m_aInvalidateClipboard.IsActive())
+ m_aInvalidateClipboard.Stop();
+
+ // dispose the row set
+ try
+ {
+ ::comphelper::disposeComponent(m_xRowSet);
+
+ m_xRowSet = nullptr;
+ m_xColumnsSupplier = nullptr;
+ m_xLoadable = nullptr;
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xParser.clear();
+ // don't dispose, just reset - it's owned by the RowSet
+}
+
+void SbaXDataBrowserController::frameAction(const css::frame::FrameActionEvent& aEvent)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ SbaXDataBrowserController_Base::frameAction( aEvent );
+
+ if ( aEvent.Source != getFrame() )
+ return;
+
+ switch ( aEvent.Action )
+ {
+ case FrameAction_FRAME_ACTIVATED:
+ case FrameAction_FRAME_UI_ACTIVATED:
+ // ensure that the active cell (if any) has the focus
+ m_aAsyncGetCellFocus.Call();
+ // start the clipboard timer
+ if (getBrowserView() && getBrowserView()->getVclControl() && !m_aInvalidateClipboard.IsActive())
+ {
+ m_aInvalidateClipboard.Start();
+ OnInvalidateClipboard( nullptr );
+ }
+ break;
+ case FrameAction_FRAME_DEACTIVATING:
+ case FrameAction_FRAME_UI_DEACTIVATING:
+ // stop the clipboard invalidator
+ if (getBrowserView() && getBrowserView()->getVclControl() && m_aInvalidateClipboard.IsActive())
+ {
+ m_aInvalidateClipboard.Stop();
+ OnInvalidateClipboard( nullptr );
+ }
+ // remove the "get cell focus"-event
+ m_aAsyncGetCellFocus.CancelCall();
+ break;
+ default:
+ break;
+ }
+}
+
+IMPL_LINK_NOARG( SbaXDataBrowserController, OnAsyncDisplayError, void*, void )
+{
+ if ( m_aCurrentError.isValid() )
+ {
+ OSQLMessageBox aDlg(getFrameWeld(), m_aCurrentError);
+ aDlg.run();
+ }
+}
+
+void SbaXDataBrowserController::errorOccured(const css::sdb::SQLErrorEvent& aEvent)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ SQLExceptionInfo aInfo( aEvent.Reason );
+ if ( !aInfo.isValid() )
+ return;
+
+ if ( m_nFormActionNestingLevel )
+ {
+ OSL_ENSURE( !m_aCurrentError.isValid(), "SbaXDataBrowserController::errorOccurred: can handle one error per transaction only!" );
+ m_aCurrentError = aInfo;
+ }
+ else
+ {
+ m_aCurrentError = aInfo;
+ m_aAsyncDisplayError.Call();
+ }
+}
+
+sal_Bool SbaXDataBrowserController::approveParameter(const css::form::DatabaseParameterEvent& aEvent)
+{
+ if (aEvent.Source != getRowSet())
+ {
+ // not my data source -> allow anything
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::approveParameter : invalid event source !");
+ return true;
+ }
+
+ Reference< css::container::XIndexAccess > xParameters = aEvent.Parameters;
+ SolarMutexGuard aSolarGuard;
+
+ // default handling: instantiate an interaction handler and let it handle the parameter request
+ try
+ {
+ // two continuations allowed: OK and Cancel
+ rtl::Reference<OParameterContinuation> pParamValues = new OParameterContinuation;
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ // the request
+ ParametersRequest aRequest;
+ aRequest.Parameters = xParameters;
+ aRequest.Connection = getConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
+ rtl::Reference<OInteractionRequest> pParamRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ pParamRequest->addContinuation(pParamValues);
+ pParamRequest->addContinuation(pAbort);
+
+ // create the handler, let it handle the request
+ Reference< XInteractionHandler2 > xHandler(InteractionHandler::createWithParent(getORB(), getComponentWindow()));
+ xHandler->handle(pParamRequest);
+
+ if (!pParamValues->wasSelected())
+ { // canceled
+ setLoadingCancelled();
+ return false;
+ }
+
+ // transfer the values into the parameter supplier
+ Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
+ if (aFinalValues.getLength() != aRequest.Parameters->getCount())
+ {
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::approveParameter: the InteractionHandler returned nonsense!");
+ setLoadingCancelled();
+ return false;
+ }
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
+ {
+ Reference< XPropertySet > xParam(
+ aRequest.Parameters->getByIndex(i), css::uno::UNO_QUERY);
+ OSL_ENSURE(xParam.is(), "SbaXDataBrowserController::approveParameter: one of the parameters is no property set!");
+ if (xParam.is())
+ {
+#ifdef DBG_UTIL
+ OUString sName;
+ xParam->getPropertyValue(PROPERTY_NAME) >>= sName;
+ OSL_ENSURE(sName == pFinalValues->Name, "SbaXDataBrowserController::approveParameter: suspicious value names!");
+#endif
+ try { xParam->setPropertyValue(PROPERTY_VALUE, pFinalValues->Value); }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::approveParameter: setting one of the properties failed!");
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return true;
+}
+
+sal_Bool SbaXDataBrowserController::approveReset(const css::lang::EventObject& /*rEvent*/)
+{
+ return true;
+}
+
+void SbaXDataBrowserController::resetted(const css::lang::EventObject& rEvent)
+{
+ OSL_ENSURE(rEvent.Source == getControlModel(), "SbaXDataBrowserController::resetted : where did this come from ?");
+ setCurrentModified( false );
+}
+
+sal_Bool SbaXDataBrowserController::confirmDelete(const css::sdb::RowChangeEvent& /*aEvent*/)
+{
+ std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ DBA_RES(STR_QUERY_BRW_DELETE_ROWS)));
+ if (xQuery->run() != RET_YES)
+ return false;
+ return true;
+}
+
+FeatureState SbaXDataBrowserController::GetState(sal_uInt16 nId) const
+{
+ FeatureState aReturn;
+ // (disabled automatically)
+
+ try
+ {
+ // no chance without a view
+ if (!getBrowserView() || !getBrowserView()->getVclControl())
+ return aReturn;
+
+ switch (nId)
+ {
+ case ID_BROWSER_REMOVEFILTER:
+ if (!m_xParser.is())
+ {
+ aReturn.bEnabled = false;
+ return aReturn;
+ }
+ // any filter or sort order set ?
+ aReturn.bEnabled = m_xParser->getFilter().getLength() || m_xParser->getHavingClause().getLength() || m_xParser->getOrder().getLength();
+ return aReturn;
+ }
+ // no chance without valid models
+ if (isValid() && !isValidCursor())
+ return aReturn;
+
+ switch (nId)
+ {
+ case ID_BROWSER_SEARCH:
+ {
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ sal_Int32 nCount = ::comphelper::getINT32(xFormSet->getPropertyValue(PROPERTY_ROWCOUNT));
+ aReturn.bEnabled = nCount != 0;
+ }
+ break;
+ case ID_BROWSER_INSERT_ROW:
+ {
+ // check if it is available
+ bool bInsertPrivilege = ( m_nRowSetPrivileges & Privilege::INSERT) != 0;
+ bool bAllowInsertions = true;
+ try
+ {
+ Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW );
+ OSL_VERIFY( xRowSetProps->getPropertyValue("AllowInserts") >>= bAllowInsertions );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ aReturn.bEnabled = bInsertPrivilege && bAllowInsertions;
+ }
+ break;
+ case SID_FM_DELETEROWS:
+ {
+ // check if it is available
+ bool bDeletePrivilege = ( m_nRowSetPrivileges & Privilege::INSERT) != 0;
+ bool bAllowDeletions = true;
+ sal_Int32 nRowCount = 0;
+ bool bInsertionRow = false;
+ try
+ {
+ Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW );
+ OSL_VERIFY( xRowSetProps->getPropertyValue("AllowDeletes") >>= bAllowDeletions );
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ROWCOUNT ) >>= nRowCount );
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ISNEW ) >>= bInsertionRow );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ aReturn.bEnabled = bDeletePrivilege && bAllowDeletions && ( nRowCount != 0 ) && !bInsertionRow;
+ }
+ break;
+
+ case ID_BROWSER_COPY:
+ if ( getBrowserView()->getVclControl()->GetSelectRowCount() )
+ {
+ aReturn.bEnabled = m_aCurrentFrame.isActive();
+ break;
+ }
+ [[fallthrough]];
+ case ID_BROWSER_PASTE:
+ case ID_BROWSER_CUT:
+ {
+ CellControllerRef xCurrentController = getBrowserView()->getVclControl()->Controller();
+ if (const EditCellController* pController = dynamic_cast<const EditCellController*>(xCurrentController.get()))
+ {
+ const IEditImplementation* pEditImplementation = pController->GetEditImplementation();
+ bool bHasLen = pEditImplementation->GetSelection().Len() != 0;
+ bool bIsReadOnly = pEditImplementation->IsReadOnly();
+ switch (nId)
+ {
+ case ID_BROWSER_CUT: aReturn.bEnabled = m_aCurrentFrame.isActive() && bHasLen && !bIsReadOnly; break;
+ case SID_COPY : aReturn.bEnabled = m_aCurrentFrame.isActive() && bHasLen; break;
+ case ID_BROWSER_PASTE:
+ aReturn.bEnabled = m_aCurrentFrame.isActive() && !bIsReadOnly;
+ if(aReturn.bEnabled)
+ {
+ aReturn.bEnabled = IsFormatSupported( m_aSystemClipboard.GetDataFlavorExVector(), SotClipboardFormatId::STRING );
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case ID_BROWSER_SORTUP:
+ case ID_BROWSER_SORTDOWN:
+ case ID_BROWSER_AUTOFILTER:
+ {
+ // a native statement can't be filtered or sorted
+ const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if ( !::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) || !m_xParser.is() )
+ break;
+
+ Reference< XPropertySet > xCurrentField = getBoundField();
+ if (!xCurrentField.is())
+ break;
+
+ aReturn.bEnabled = ::comphelper::getBOOL(xCurrentField->getPropertyValue(PROPERTY_ISSEARCHABLE));
+ const Reference< XRowSet > xRow = getRowSet();
+ aReturn.bEnabled = aReturn.bEnabled
+ && xRow.is()
+ && !xRow->isBeforeFirst()
+ && !xRow->isAfterLast()
+ && !xRow->rowDeleted()
+ && ( ::comphelper::getINT32( xFormSet->getPropertyValue( PROPERTY_ROWCOUNT ) ) != 0 );
+ }
+ break;
+
+ case ID_BROWSER_FILTERCRIT:
+ if ( m_bCannotSelectUnfiltered && m_xParser.is() )
+ {
+ aReturn.bEnabled = true;
+ break;
+ }
+ [[fallthrough]];
+ case ID_BROWSER_ORDERCRIT:
+ {
+ const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if ( !::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) || !m_xParser.is() )
+ break;
+
+ aReturn.bEnabled = getRowSet().is()
+ && ( ::comphelper::getINT32( xFormSet->getPropertyValue( PROPERTY_ROWCOUNT ) ) != 0 );
+ }
+ break;
+
+ case ID_BROWSER_REFRESH:
+ aReturn.bEnabled = true;
+ break;
+
+ case ID_BROWSER_REDO:
+ aReturn.bEnabled = false; // simply forget it ;). no redo possible.
+ break;
+
+ case ID_BROWSER_UNDORECORD:
+ case ID_BROWSER_SAVERECORD:
+ {
+ if (!m_bCurrentlyModified)
+ {
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if (xFormSet.is())
+ aReturn.bEnabled = ::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ISMODIFIED));
+ }
+ else
+ aReturn.bEnabled = true;
+
+ aReturn.sTitle = (ID_BROWSER_UNDORECORD == nId) ? m_sStateUndoRecord : m_sStateSaveRecord;
+ }
+ break;
+ case ID_BROWSER_EDITDOC:
+ {
+ // check if it is available
+ Reference< XPropertySet > xDataSourceSet(getRowSet(), UNO_QUERY);
+ if (!xDataSourceSet.is())
+ break; // no datasource -> no edit mode
+
+ sal_Int32 nDataSourcePrivileges = ::comphelper::getINT32(xDataSourceSet->getPropertyValue(PROPERTY_PRIVILEGES));
+ bool bInsertAllowedAndPossible = ((nDataSourcePrivileges & css::sdbcx::Privilege::INSERT) != 0) && ::comphelper::getBOOL(xDataSourceSet->getPropertyValue("AllowInserts"));
+ bool bUpdateAllowedAndPossible = ((nDataSourcePrivileges & css::sdbcx::Privilege::UPDATE) != 0) && ::comphelper::getBOOL(xDataSourceSet->getPropertyValue("AllowUpdates"));
+ bool bDeleteAllowedAndPossible = ((nDataSourcePrivileges & css::sdbcx::Privilege::DELETE) != 0) && ::comphelper::getBOOL(xDataSourceSet->getPropertyValue("AllowDeletes"));
+ if (!bInsertAllowedAndPossible && !bUpdateAllowedAndPossible && !bDeleteAllowedAndPossible)
+ break; // no insert/update/delete -> no edit mode
+
+ if (!isValidCursor() || !isLoaded())
+ break; // no cursor -> no edit mode
+
+ aReturn.bEnabled = true;
+
+ DbGridControlOptions nGridMode = getBrowserView()->getVclControl()->GetOptions();
+ aReturn.bChecked = nGridMode > DbGridControlOptions::Readonly;
+ }
+ break;
+ case ID_BROWSER_FILTERED:
+ {
+ aReturn.bEnabled = false;
+ Reference< XPropertySet > xActiveSet(getRowSet(), UNO_QUERY);
+ OUString aFilter = ::comphelper::getString(xActiveSet->getPropertyValue(PROPERTY_FILTER));
+ OUString aHaving = ::comphelper::getString(xActiveSet->getPropertyValue(PROPERTY_HAVING_CLAUSE));
+ if ( !(aFilter.isEmpty() && aHaving.isEmpty()) )
+ {
+ xActiveSet->getPropertyValue( PROPERTY_APPLYFILTER ) >>= aReturn.bChecked;
+ aReturn.bEnabled = true;
+ }
+ else
+ {
+ aReturn.bChecked = false;
+ aReturn.bEnabled = false;
+ }
+ }
+ break;
+ default:
+ return SbaXDataBrowserController_Base::GetState(nId);
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return aReturn;
+}
+
+void SbaXDataBrowserController::applyParserOrder(const OUString& _rOldOrder,const Reference< XSingleSelectQueryComposer >& _xParser)
+{
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if (!m_xLoadable.is())
+ {
+ SAL_WARN("dbaccess.ui","SbaXDataBrowserController::applyParserOrder: invalid row set!");
+ return;
+ }
+
+ sal_uInt16 nPos = getCurrentColumnPosition();
+ bool bSuccess = false;
+ try
+ {
+ xFormSet->setPropertyValue(PROPERTY_ORDER, Any(_xParser->getOrder()));
+ bSuccess = reloadForm(m_xLoadable);
+ }
+ catch(Exception&)
+ {
+ }
+
+ if (!bSuccess)
+ {
+ xFormSet->setPropertyValue(PROPERTY_ORDER, Any(_rOldOrder));
+
+ try
+ {
+ if (loadingCancelled() || !reloadForm(m_xLoadable))
+ criticalFail();
+ }
+ catch(Exception&)
+ {
+ criticalFail();
+ }
+ InvalidateAll();
+ }
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+
+ setCurrentColumnPosition(nPos);
+}
+
+void SbaXDataBrowserController::applyParserFilter(const OUString& _rOldFilter, bool _bOldFilterApplied,const ::OUString& _sOldHaving,const Reference< XSingleSelectQueryComposer >& _xParser)
+{
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if (!m_xLoadable.is())
+ {
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::applyParserFilter: invalid row set!");
+ return;
+ }
+
+ sal_uInt16 nPos = getCurrentColumnPosition();
+
+ bool bSuccess = false;
+ try
+ {
+ FormErrorHelper aError(this);
+ xFormSet->setPropertyValue(PROPERTY_FILTER, Any(_xParser->getFilter()));
+ xFormSet->setPropertyValue(PROPERTY_HAVING_CLAUSE, Any(_xParser->getHavingClause()));
+ xFormSet->setPropertyValue(PROPERTY_APPLYFILTER, css::uno::Any(true));
+
+ bSuccess = reloadForm(m_xLoadable);
+ }
+ catch(Exception&)
+ {
+ }
+
+ if (!bSuccess)
+ {
+ xFormSet->setPropertyValue(PROPERTY_FILTER, Any(_rOldFilter));
+ xFormSet->setPropertyValue(PROPERTY_HAVING_CLAUSE, Any(_sOldHaving));
+ xFormSet->setPropertyValue(PROPERTY_APPLYFILTER, css::uno::Any(_bOldFilterApplied));
+
+ try
+ {
+ if (loadingCancelled() || !reloadForm(m_xLoadable))
+ criticalFail();
+ }
+ catch(Exception&)
+ {
+ criticalFail();
+ }
+ InvalidateAll();
+ }
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+
+ setCurrentColumnPosition(nPos);
+}
+
+Reference< XSingleSelectQueryComposer > SbaXDataBrowserController::createParser_nothrow()
+{
+ Reference< XSingleSelectQueryComposer > xComposer;
+ try
+ {
+ const Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW );
+ const Reference< XMultiServiceFactory > xFactory(
+ xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
+ xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+
+ OUString sActiveCommand;
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand );
+ if ( !sActiveCommand.isEmpty() )
+ {
+ xComposer->setElementaryQuery( sActiveCommand );
+ }
+ else
+ {
+ OUString sCommand;
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand );
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_COMMAND_TYPE ) >>= nCommandType );
+ xComposer->setCommand( sCommand, nCommandType );
+ }
+
+ OUString sFilter;
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_FILTER ) >>= sFilter );
+ xComposer->setFilter( sFilter );
+
+ OUString sHavingClause;
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_HAVING_CLAUSE ) >>= sHavingClause );
+ xComposer->setHavingClause( sHavingClause );
+
+ OUString sOrder;
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ORDER ) >>= sOrder );
+ xComposer->setOrder( sOrder );
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xComposer;
+}
+
+void SbaXDataBrowserController::ExecuteFilterSortCrit(bool bFilter)
+{
+ if (!SaveModified())
+ return;
+
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+
+ const OUString sOldVal = bFilter ? m_xParser->getFilter() : m_xParser->getOrder();
+ const OUString sOldHaving = m_xParser->getHavingClause();
+ Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow();
+ try
+ {
+ Reference< XConnection> xCon(xFormSet->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
+ if(bFilter)
+ {
+ DlgFilterCrit aDlg(getFrameWeld(), getORB(), xCon, xParser, m_xColumnsSupplier->getColumns());
+ if (!aDlg.run())
+ return; // if so we don't need to update the grid
+ aDlg.BuildWherePart();
+ }
+ else
+ {
+ DlgOrderCrit aDlg(getFrameWeld(), xCon, xParser, m_xColumnsSupplier->getColumns());
+ if (!aDlg.run())
+ {
+ return; // if so we don't need to actualize the grid
+ }
+ aDlg.BuildOrderPart();
+ }
+ }
+ catch(const SQLException& )
+ {
+ SQLExceptionInfo aError( ::cppu::getCaughtException() );
+ showError( aError );
+ return;
+ }
+ catch(Exception&)
+ {
+ return;
+ }
+
+ OUString sNewVal = bFilter ? xParser->getFilter() : xParser->getOrder();
+ bool bOldFilterApplied(false);
+ if (bFilter)
+ {
+ try { bOldFilterApplied = ::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_APPLYFILTER)); } catch(Exception&) { } ;
+ }
+
+ OUString sNewHaving = xParser->getHavingClause();
+ if ( sOldVal == sNewVal && (!bFilter || sOldHaving == sNewHaving) )
+ // nothing to be done
+ return;
+
+ if (bFilter)
+ applyParserFilter(sOldVal, bOldFilterApplied,sOldHaving,xParser);
+ else
+ applyParserOrder(sOldVal,xParser);
+
+ ::comphelper::disposeComponent(xParser);
+}
+
+void SbaXDataBrowserController::ExecuteSearch()
+{
+ // calculate the control source of the active field
+ Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY);
+ OSL_ENSURE(xGrid.is(), "SbaXDataBrowserController::ExecuteSearch : the control should have a css::form::XGrid interface !");
+
+ Reference< css::form::XGridPeer > xGridPeer(getBrowserView()->getGridControl()->getPeer(), UNO_QUERY);
+ Reference< css::container::XIndexContainer > xColumns = xGridPeer->getColumns();
+ OSL_ENSURE(xGridPeer.is() && xColumns.is(), "SbaXDataBrowserController::ExecuteSearch : invalid peer !");
+
+ sal_Int16 nViewCol = xGrid->getCurrentColumnPosition();
+ sal_Int16 nModelCol = getBrowserView()->View2ModelPos(nViewCol);
+
+ Reference< XPropertySet > xCurrentCol(xColumns->getByIndex(nModelCol),UNO_QUERY);
+ OUString sActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(PROPERTY_CONTROLSOURCE));
+
+ // the text within the current cell
+ OUString sInitialText;
+ Reference< css::container::XIndexAccess > xColControls(xGridPeer, UNO_QUERY);
+ Reference< XInterface > xCurControl(xColControls->getByIndex(nViewCol),UNO_QUERY);
+ OUString aInitialText;
+ if (IsSearchableControl(xCurControl, &aInitialText))
+ sInitialText = aInitialText;
+
+ // prohibit the synchronization of the grid's display with the cursor's position
+ Reference< XPropertySet > xModelSet(getControlModel(), UNO_QUERY);
+ OSL_ENSURE(xModelSet.is(), "SbaXDataBrowserController::ExecuteSearch : no model set ?!");
+ xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(false));
+ xModelSet->setPropertyValue("AlwaysShowCursor", css::uno::Any(true));
+ xModelSet->setPropertyValue("CursorColor", Any(COL_LIGHTRED));
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<AbstractFmSearchDialog> pDialog;
+ std::vector< OUString > aContextNames;
+ aContextNames.emplace_back("Standard" );
+ pDialog = pFact->CreateFmSearchDialog(getFrameWeld(), sInitialText, aContextNames, 0, LINK(this, SbaXDataBrowserController, OnSearchContextRequest));
+ pDialog->SetActiveField( sActiveField );
+ pDialog->SetFoundHandler( LINK( this, SbaXDataBrowserController, OnFoundData ) );
+ pDialog->SetCanceledNotFoundHdl( LINK( this, SbaXDataBrowserController, OnCanceledNotFound ) );
+ pDialog->Execute();
+ pDialog.disposeAndClear();
+
+ // restore the grid's normal operating state
+ xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(true));
+ xModelSet->setPropertyValue("AlwaysShowCursor", css::uno::Any(false));
+ xModelSet->setPropertyValue("CursorColor", Any());
+}
+
+void SbaXDataBrowserController::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& _rArgs)
+{
+ bool bSortUp = true;
+
+ switch (nId)
+ {
+ default:
+ SbaXDataBrowserController_Base::Execute( nId, _rArgs );
+ return;
+
+ case ID_BROWSER_INSERT_ROW:
+ try
+ {
+ if (SaveModified())
+ {
+ getRowSet()->afterLast();
+ // check if it is available
+ Reference< XResultSetUpdate > xUpdateCursor(getRowSet(), UNO_QUERY_THROW);
+ xUpdateCursor->moveToInsertRow();
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.ui", "" );
+ }
+ break;
+ case SID_FM_DELETEROWS:
+
+ if (SaveModified())
+ {
+ SbaGridControl* pVclGrid = getBrowserView()->getVclControl();
+ if ( pVclGrid )
+ {
+ if( !pVclGrid->GetSelectRowCount() )
+ {
+ pVclGrid->DeactivateCell();
+ pVclGrid->SelectRow(pVclGrid->GetCurRow());
+ }
+ pVclGrid->DeleteSelectedRows();
+ }
+ }
+ break;
+
+ case ID_BROWSER_FILTERED:
+ if (SaveModified())
+ {
+ Reference< XPropertySet > xActiveSet(getRowSet(), UNO_QUERY);
+ bool bApplied = ::comphelper::getBOOL(xActiveSet->getPropertyValue(PROPERTY_APPLYFILTER));
+ xActiveSet->setPropertyValue(PROPERTY_APPLYFILTER, css::uno::Any(!bApplied));
+ reloadForm(m_xLoadable);
+ }
+ InvalidateFeature(ID_BROWSER_FILTERED);
+ break;
+ case ID_BROWSER_EDITDOC:
+ {
+ DbGridControlOptions nGridMode = getBrowserView()->getVclControl()->GetOptions();
+ if (nGridMode == DbGridControlOptions::Readonly)
+ getBrowserView()->getVclControl()->SetOptions(DbGridControlOptions::Update | DbGridControlOptions::Insert | DbGridControlOptions::Delete);
+ // the options not supported by the data source will be removed automatically
+ else
+ {
+ if ( !SaveModified( ) )
+ // give the user a chance to save the current record (if necessary)
+ break;
+
+ // maybe the user wanted to reject the modified record ?
+ if (GetState(ID_BROWSER_UNDORECORD).bEnabled)
+ Execute(ID_BROWSER_UNDORECORD,Sequence<PropertyValue>());
+
+ getBrowserView()->getVclControl()->SetOptions(DbGridControlOptions::Readonly);
+ }
+ InvalidateFeature(ID_BROWSER_EDITDOC);
+ }
+ break;
+
+ case ID_BROWSER_SEARCH:
+ if ( SaveModified( ) )
+ ExecuteSearch();
+ break;
+
+ case ID_BROWSER_COPY:
+ if ( getBrowserView()->getVclControl()->GetSelectRowCount() > 0 )
+ {
+ getBrowserView()->getVclControl()->CopySelectedRowsToClipboard();
+ break;
+ }
+ [[fallthrough]];
+ case ID_BROWSER_CUT:
+ case ID_BROWSER_PASTE:
+ {
+ CellControllerRef xCurrentController = getBrowserView()->getVclControl()->Controller();
+ if (EditCellController* pController = dynamic_cast<EditCellController*>(xCurrentController.get()))
+ {
+ IEditImplementation* pEditImplementation = pController->GetEditImplementation();
+ switch (nId)
+ {
+ case ID_BROWSER_CUT:
+ pEditImplementation->Cut();
+ break;
+ case SID_COPY:
+ pEditImplementation->Copy();
+ break;
+ case ID_BROWSER_PASTE:
+ pEditImplementation->Paste();
+ break;
+ }
+ if (ID_BROWSER_CUT == nId || ID_BROWSER_PASTE == nId)
+ pController->Modify();
+ }
+ }
+ break;
+
+ case ID_BROWSER_SORTDOWN:
+ bSortUp = false;
+ [[fallthrough]];
+ case ID_BROWSER_SORTUP:
+ {
+ if (!SaveModified())
+ break;
+
+ if (!isValidCursor())
+ break;
+
+ // only one sort order
+ Reference< XPropertySet > xField = getBoundField();
+ if (!xField.is())
+ break;
+
+ Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow();
+ const OUString sOldSort = xParser->getOrder();
+ bool bParserSuccess = false;
+ try
+ {
+ bParserSuccess = false;
+ xParser->setOrder(OUString());
+ xParser->appendOrderByColumn(xField, bSortUp);
+ bParserSuccess = true;
+ }
+ catch(SQLException& e)
+ {
+ SQLException aError = ::dbtools::prependErrorInfo(e, *this, DBA_RES(SBA_BROWSER_SETTING_ORDER));
+ css::sdb::SQLErrorEvent aEvent;
+ aEvent.Reason <<= aError;
+ errorOccured(aEvent);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess", "SbaXDataBrowserController::Execute : caught an exception while composing the new filter !");
+ }
+
+ if (bParserSuccess)
+ applyParserOrder(sOldSort,xParser);
+ }
+ break;
+
+ case ID_BROWSER_AUTOFILTER:
+ {
+ if (!SaveModified())
+ break;
+
+ if (!isValidCursor())
+ break;
+
+ Reference< XPropertySet > xField = getBoundField();
+ if (!xField.is())
+ break;
+
+ // check if the column is an aggregate function
+ const bool bHaving(isAggregateColumn(m_xParser, xField));
+
+ Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow();
+ const OUString sOldFilter = xParser->getFilter();
+ const OUString sOldHaving = xParser->getHavingClause();
+
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ bool bApplied = ::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_APPLYFILTER));
+ // do we have a filter but it's not applied ?
+ // -> completely overwrite it, else append one
+ if (!bApplied)
+ {
+ try
+ {
+ xParser->setFilter(OUString());
+ }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied filter !");
+ }
+ try
+ {
+ xParser->setHavingClause(OUString());
+ }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied HAVING clause !");
+ }
+ }
+
+ bool bParserSuccess = false;
+
+ const sal_Int32 nOp = SQLFilterOperator::EQUAL;
+
+ if ( bHaving )
+ {
+ try
+ {
+ bParserSuccess = false;
+ xParser->appendHavingClauseByColumn(xField,true,nOp);
+ bParserSuccess = true;
+ }
+ catch(SQLException& e)
+ {
+ SQLException aError = ::dbtools::prependErrorInfo(e, *this, DBA_RES(SBA_BROWSER_SETTING_FILTER));
+ css::sdb::SQLErrorEvent aEvent;
+ aEvent.Reason <<= aError;
+ errorOccured(aEvent);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess", "SbaXDataBrowserController::Execute : caught an exception while composing the new filter !");
+ }
+ }
+ else
+ {
+ try
+ {
+ bParserSuccess = false;
+ xParser->appendFilterByColumn(xField,true,nOp);
+ bParserSuccess = true;
+ }
+ catch(SQLException& e)
+ {
+ SQLException aError = ::dbtools::prependErrorInfo(e, *this, DBA_RES(SBA_BROWSER_SETTING_FILTER));
+ css::sdb::SQLErrorEvent aEvent;
+ aEvent.Reason <<= aError;
+ errorOccured(aEvent);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess", "SbaXDataBrowserController::Execute : caught an exception while composing the new filter !");
+ }
+ }
+
+ if (bParserSuccess)
+ applyParserFilter(sOldFilter, bApplied,sOldHaving,xParser);
+
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+ InvalidateFeature(ID_BROWSER_FILTERED);
+ }
+ break;
+
+ case ID_BROWSER_ORDERCRIT:
+ ExecuteFilterSortCrit(false);
+ break;
+
+ case ID_BROWSER_FILTERCRIT:
+ ExecuteFilterSortCrit(true);
+ InvalidateFeature(ID_BROWSER_FILTERED);
+ break;
+
+ case ID_BROWSER_REMOVEFILTER:
+ {
+ if (!SaveModified())
+ break;
+
+ bool bNeedPostReload = preReloadForm();
+ // reset the filter and the sort property simultaneously so only _one_ new statement has to be
+ // sent
+ Reference< XPropertySet > xSet(getRowSet(), UNO_QUERY);
+ if ( xSet.is() )
+ {
+ xSet->setPropertyValue(PROPERTY_FILTER,Any(OUString()));
+ xSet->setPropertyValue(PROPERTY_HAVING_CLAUSE,Any(OUString()));
+ xSet->setPropertyValue(PROPERTY_ORDER,Any(OUString()));
+ }
+ try
+ {
+ reloadForm(m_xLoadable);
+ if ( bNeedPostReload )
+ postReloadForm();
+ }
+ catch(Exception&)
+ {
+ }
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+ InvalidateFeature(ID_BROWSER_FILTERED);
+ }
+ break;
+
+ case ID_BROWSER_REFRESH:
+ if ( SaveModified( ) )
+ {
+ if (!reloadForm(m_xLoadable))
+ criticalFail();
+ }
+ break;
+
+ case ID_BROWSER_SAVERECORD:
+ if ( SaveModified( false ) )
+ setCurrentModified( false );
+ break;
+
+ case ID_BROWSER_UNDORECORD:
+ {
+ try
+ {
+ // restore the cursor state
+ Reference< XResultSetUpdate > xCursor(getRowSet(), UNO_QUERY);
+ Reference< XPropertySet > xSet(xCursor, UNO_QUERY);
+ Any aVal = xSet->getPropertyValue(PROPERTY_ISNEW);
+ if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
+ {
+ xCursor->moveToInsertRow();
+ // no need to reset the grid model after we moved to the insert row, this is done implicitly by the
+ // form
+ // (and in some cases it may be deadly to do the reset explicitly after the form did it implicitly,
+ // cause the form's reset may be async, and this leads to some nice deadlock scenarios...)
+ }
+ else
+ {
+ xCursor->cancelRowUpdates();
+
+ // restore the grids state
+ Reference< css::form::XReset > xReset(getControlModel(), UNO_QUERY);
+ if (xReset.is())
+ xReset->reset();
+ }
+ }
+ catch(SQLException&)
+ {
+ }
+
+ setCurrentModified( false );
+ }
+ }
+}
+
+bool SbaXDataBrowserController::SaveModified(bool bAskFor)
+{
+ if ( bAskFor && GetState(ID_BROWSER_SAVERECORD).bEnabled )
+ {
+ getBrowserView()->getVclControl()->GrabFocus();
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/savemodifieddialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQry(xBuilder->weld_message_dialog("SaveModifiedDialog"));
+ switch (xQry->run())
+ {
+ case RET_NO:
+ Execute(ID_BROWSER_UNDORECORD,Sequence<PropertyValue>());
+ return true;
+ case RET_CANCEL:
+ return false;
+ }
+ }
+
+ if ( !CommitCurrent() ) // Commit the current control
+ return false;
+
+ Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ bool bResult = false;
+ try
+ {
+ if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ISMODIFIED)))
+ {
+ Reference< XResultSetUpdate > xCursor(getRowSet(), UNO_QUERY);
+ if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ISNEW)))
+ xCursor->insertRow();
+ else
+ xCursor->updateRow();
+ }
+ bResult = true;
+ }
+ catch(SQLException&)
+ {
+ }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaXDataBrowserController::SaveModified : could not save the current record !");
+ bResult = false;
+ }
+
+ InvalidateFeature(ID_BROWSER_SAVERECORD);
+ InvalidateFeature(ID_BROWSER_UNDORECORD);
+ return bResult;
+}
+
+bool SbaXDataBrowserController::CommitCurrent()
+{
+ if (!getBrowserView())
+ return true;
+
+ Reference< css::awt::XControl > xActiveControl(getBrowserView()->getGridControl());
+ Reference< css::form::XBoundControl > xLockingTest(xActiveControl, UNO_QUERY);
+ bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
+ if (xActiveControl.is() && !bControlIsLocked)
+ {
+ // At first check Control if it supports the IFace
+ Reference< css::form::XBoundComponent > xBoundControl(xActiveControl, UNO_QUERY);
+ if (!xBoundControl.is())
+ xBoundControl.set(xActiveControl->getModel(), UNO_QUERY);
+ if (xBoundControl.is() && !xBoundControl->commit())
+ return false;
+ }
+ return true;
+}
+
+void SbaXDataBrowserController::setCurrentModified( bool _bSet )
+{
+ m_bCurrentlyModified = _bSet;
+ InvalidateFeature( ID_BROWSER_SAVERECORD );
+ InvalidateFeature( ID_BROWSER_UNDORECORD );
+}
+
+void SbaXDataBrowserController::RowChanged()
+{
+ setCurrentModified( false );
+}
+
+void SbaXDataBrowserController::ColumnChanged()
+{
+ InvalidateFeature(ID_BROWSER_SORTUP);
+ InvalidateFeature(ID_BROWSER_SORTDOWN);
+ InvalidateFeature(ID_BROWSER_ORDERCRIT);
+ InvalidateFeature(ID_BROWSER_FILTERCRIT);
+ InvalidateFeature(ID_BROWSER_AUTOFILTER);
+ InvalidateFeature(ID_BROWSER_REMOVEFILTER);
+
+ setCurrentModified( false );
+}
+
+void SbaXDataBrowserController::SelectionChanged()
+{
+ // not interested in
+}
+
+void SbaXDataBrowserController::CellActivated()
+{
+ m_aInvalidateClipboard.Start();
+ OnInvalidateClipboard( nullptr );
+}
+
+void SbaXDataBrowserController::CellDeactivated()
+{
+ m_aInvalidateClipboard.Stop();
+ OnInvalidateClipboard( nullptr );
+}
+
+IMPL_LINK_NOARG(SbaXDataBrowserController, OnClipboardChanged, TransferableDataHelper*, void)
+{
+ SolarMutexGuard aGuard;
+ OnInvalidateClipboard( nullptr );
+}
+
+IMPL_LINK(SbaXDataBrowserController, OnInvalidateClipboard, Timer*, _pTimer, void)
+{
+ InvalidateFeature(ID_BROWSER_CUT);
+ InvalidateFeature(ID_BROWSER_COPY);
+
+ // if the invalidation was triggered by the timer, we do not need to invalidate PASTE.
+ // The timer is only for checking the CUT/COPY slots regularly, which depend on the
+ // selection state of the active cell
+ // TODO: get a callback at the Edit which allows to be notified when the selection
+ // changes. This would be much better than this cycle-eating polling mechanism here...
+ if ( _pTimer != &m_aInvalidateClipboard )
+ InvalidateFeature(ID_BROWSER_PASTE);
+}
+
+Reference< XPropertySet > SbaXDataBrowserController::getBoundField() const
+{
+ Reference< XPropertySet > xEmptyReturn;
+
+ // get the current column from the grid
+ Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY);
+ if (!xGrid.is())
+ return xEmptyReturn;
+ sal_uInt16 nViewPos = xGrid->getCurrentColumnPosition();
+ sal_uInt16 nCurrentCol = getBrowserView()->View2ModelPos(nViewPos);
+ if (nCurrentCol == sal_uInt16(-1))
+ return xEmptyReturn;
+
+ // get the according column from the model
+ Reference< css::container::XIndexContainer > xCols(getControlModel(), UNO_QUERY);
+ Reference< XPropertySet > xCurrentCol(xCols->getByIndex(nCurrentCol),UNO_QUERY);
+ if (!xCurrentCol.is())
+ return xEmptyReturn;
+
+ xEmptyReturn.set(xCurrentCol->getPropertyValue(PROPERTY_BOUNDFIELD) ,UNO_QUERY);
+ return xEmptyReturn;
+}
+
+IMPL_LINK(SbaXDataBrowserController, OnSearchContextRequest, FmSearchContext&, rContext, sal_uInt32)
+{
+ Reference< css::container::XIndexAccess > xPeerContainer(getBrowserView()->getGridControl(), UNO_QUERY);
+
+ // check all grid columns for their control source
+ Reference< css::container::XIndexAccess > xModelColumns(getFormComponent(), UNO_QUERY);
+ OSL_ENSURE(xModelColumns.is(), "SbaXDataBrowserController::OnSearchContextRequest : there is a grid control without columns !");
+ // the case 'no columns' should be indicated with an empty container, I think ...
+ OSL_ENSURE(xModelColumns->getCount() >= xPeerContainer->getCount(), "SbaXDataBrowserController::OnSearchContextRequest : impossible : have more view than model columns !");
+
+ OUString sFieldList;
+ for (sal_Int32 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos)
+ {
+ Reference< XInterface > xCurrentColumn(xPeerContainer->getByIndex(nViewPos),UNO_QUERY);
+ if (!xCurrentColumn.is())
+ continue;
+
+ // can we use this column control for searching ?
+ if (!IsSearchableControl(xCurrentColumn))
+ continue;
+
+ sal_uInt16 nModelPos = getBrowserView()->View2ModelPos(static_cast<sal_uInt16>(nViewPos));
+ Reference< XPropertySet > xCurrentColModel(xModelColumns->getByIndex(nModelPos),UNO_QUERY);
+ OUString aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(PROPERTY_CONTROLSOURCE));
+
+ sFieldList += aName + ";";
+
+ rContext.arrFields.push_back(xCurrentColumn);
+ }
+ sFieldList = comphelper::string::stripEnd(sFieldList, ';');
+
+ rContext.xCursor = getRowSet();
+ rContext.strUsedFields = sFieldList;
+
+ // if the cursor is in a mode other than STANDARD -> reset
+ Reference< XPropertySet > xCursorSet(rContext.xCursor, UNO_QUERY);
+ OSL_ENSURE(xCursorSet.is() && !::comphelper::getBOOL(xCursorSet->getPropertyValue(PROPERTY_ISMODIFIED)),
+ "SbaXDataBrowserController::OnSearchContextRequest : please do not call for cursors with modified rows !");
+ if (xCursorSet.is() && ::comphelper::getBOOL(xCursorSet->getPropertyValue(PROPERTY_ISNEW)))
+ {
+ Reference< XResultSetUpdate > xUpdateCursor(rContext.xCursor, UNO_QUERY);
+ xUpdateCursor->moveToCurrentRow();
+ }
+ return rContext.arrFields.size();
+}
+
+IMPL_LINK(SbaXDataBrowserController, OnFoundData, FmFoundRecordInformation&, rInfo, void)
+{
+ Reference< css::sdbcx::XRowLocate > xCursor(getRowSet(), UNO_QUERY);
+ OSL_ENSURE(xCursor.is(), "SbaXDataBrowserController::OnFoundData : xCursor is empty");
+
+ // move the cursor
+ xCursor->moveToBookmark(rInfo.aPosition);
+
+ // let the grid sync its display with the cursor
+ Reference< XPropertySet > xModelSet(getControlModel(), UNO_QUERY);
+ OSL_ENSURE(xModelSet.is(), "SbaXDataBrowserController::OnFoundData : no model set ?!");
+ Any aOld = xModelSet->getPropertyValue("DisplayIsSynchron");
+ xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(true));
+ xModelSet->setPropertyValue("DisplayIsSynchron", aOld);
+
+ // and move to the field
+ Reference< css::container::XIndexAccess > aColumnControls(getBrowserView()->getGridControl()->getPeer(), UNO_QUERY);
+ sal_Int32 nViewPos;
+
+ for ( nViewPos = 0; nViewPos < aColumnControls->getCount(); ++nViewPos )
+ {
+ Reference< XInterface > xCurrent(aColumnControls->getByIndex(nViewPos),UNO_QUERY);
+ if (IsSearchableControl(xCurrent))
+ {
+ if (rInfo.nFieldPos)
+ --rInfo.nFieldPos;
+ else
+ break;
+ }
+ }
+
+ Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY);
+ xGrid->setCurrentColumnPosition(nViewPos); //TODO: sal_Int32 -> sal_Int16!
+}
+
+IMPL_LINK(SbaXDataBrowserController, OnCanceledNotFound, FmFoundRecordInformation&, rInfo, void)
+{
+ Reference< css::sdbcx::XRowLocate > xCursor(getRowSet(), UNO_QUERY);
+
+ try
+ {
+ OSL_ENSURE(xCursor.is(), "SbaXDataBrowserController::OnCanceledNotFound : xCursor is empty");
+ // move the cursor
+ xCursor->moveToBookmark(rInfo.aPosition);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ try
+ {
+ // let the grid sync its display with the cursor
+ Reference< XPropertySet > xModelSet(getControlModel(), UNO_QUERY);
+ OSL_ENSURE(xModelSet.is(), "SbaXDataBrowserController::OnCanceledNotFound : no model set ?!");
+ Any aOld = xModelSet->getPropertyValue("DisplayIsSynchron");
+ xModelSet->setPropertyValue("DisplayIsSynchron", css::uno::Any(true));
+ xModelSet->setPropertyValue("DisplayIsSynchron", aOld);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+IMPL_LINK_NOARG(SbaXDataBrowserController, OnAsyncGetCellFocus, void*, void)
+{
+ SbaGridControl* pVclGrid = getBrowserView() ? getBrowserView()->getVclControl() : nullptr;
+ // if we have a controller, but the window for the controller doesn't have the focus, we correct this
+ if (pVclGrid && pVclGrid->IsEditing() && pVclGrid->HasChildPathFocus())
+ pVclGrid->Controller()->GetWindow().GrabFocus();
+}
+
+void SbaXDataBrowserController::criticalFail()
+{
+ InvalidateAll();
+ m_nRowSetPrivileges = 0;
+}
+
+void SbaXDataBrowserController::LoadFinished(bool /*bWasSynch*/)
+{
+ m_nRowSetPrivileges = 0;
+
+ if (!isValid() || loadingCancelled())
+ return;
+
+ // obtain cached values
+ try
+ {
+ Reference< XPropertySet > xFormProps( m_xLoadable, UNO_QUERY_THROW );
+ OSL_VERIFY( xFormProps->getPropertyValue( PROPERTY_PRIVILEGES ) >>= m_nRowSetPrivileges );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // switch the control to alive mode
+ getBrowserView()->getGridControl()->setDesignMode(false);
+
+ initializeParser();
+
+ InvalidateAll();
+
+ m_aAsyncGetCellFocus.Call();
+}
+
+void SbaXDataBrowserController::initializeParser() const
+{
+ if ( m_xParser.is() )
+ return;
+
+ // create a parser (needed for filtering/sorting)
+ try
+ {
+ const Reference< XPropertySet > xFormSet(getRowSet(), UNO_QUERY);
+ if (::comphelper::getBOOL(xFormSet->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)))
+ { // (only if the statement isn't native)
+ // (it is allowed to use the PROPERTY_ISPASSTHROUGH : _after_ loading a form it is valid)
+ xFormSet->getPropertyValue(PROPERTY_SINGLESELECTQUERYCOMPOSER) >>= m_xParser;
+ }
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ m_xParser = nullptr;
+ // no further handling, we ignore the error
+ }
+}
+
+void SbaXDataBrowserController::loaded(const EventObject& /*aEvent*/)
+{
+ // not interested in
+ // we're loading within a separated thread and have a handling for its "finished event"
+}
+
+void SbaXDataBrowserController::unloading(const EventObject& /*aEvent*/)
+{
+ // not interested in
+}
+
+void SbaXDataBrowserController::unloaded(const EventObject& /*aEvent*/)
+{
+ m_xParser.clear();
+ InvalidateAll();
+ // do this asynchronously, there are other listeners reacting on this message ...
+ // (it's a little hack : the grid columns are listening to this event, too, and their bound field may
+ // change as a reaction on that event. as we have no chance to be notified of this change (which is
+ // the one we're interested in) we give them time to do what they want to before invalidating our
+ // bound-field-dependent slots...
+}
+
+void SbaXDataBrowserController::reloading(const EventObject& /*aEvent*/)
+{
+ // not interested in
+}
+
+void SbaXDataBrowserController::reloaded(const EventObject& /*aEvent*/)
+{
+ InvalidateAll();
+ // do this asynchronously, there are other listeners reacting on this message ...
+ // (it's a little hack : the grid columns are listening to this event, too, and their bound field may
+ // change as a reaction on that event. as we have no chance to be notified of this change (which is
+ // the one we're interested in) we give them time to do what they want to before invalidating our
+ // bound-field-dependent slots...
+}
+
+void SbaXDataBrowserController::enterFormAction()
+{
+ if ( !m_nFormActionNestingLevel )
+ // first action -> reset
+ m_aCurrentError.clear();
+
+ ++m_nFormActionNestingLevel;
+}
+
+void SbaXDataBrowserController::leaveFormAction()
+{
+ OSL_ENSURE( m_nFormActionNestingLevel > 0, "SbaXDataBrowserController::leaveFormAction : invalid call !" );
+ if ( --m_nFormActionNestingLevel > 0 )
+ return;
+
+ if ( !m_aCurrentError.isValid() )
+ return;
+
+ m_aAsyncDisplayError.Call();
+}
+
+bool SbaXDataBrowserController::isLoaded() const
+{
+ return m_xLoadable.is() && m_xLoadable->isLoaded();
+}
+
+bool SbaXDataBrowserController::isValidCursor() const
+{
+ if (!m_xColumnsSupplier.is())
+ return false;
+ Reference< css::container::XNameAccess > xCols = m_xColumnsSupplier->getColumns();
+ if (!xCols.is() || !xCols->hasElements())
+ return false;
+
+ bool bIsValid = !(m_xRowSet->isBeforeFirst() || m_xRowSet->isAfterLast());
+ if ( !bIsValid )
+ {
+ Reference<XPropertySet> xProp(m_xRowSet,UNO_QUERY);
+ bIsValid = ::cppu::any2bool(xProp->getPropertyValue(PROPERTY_ISNEW));
+ if ( !bIsValid )
+ {
+ bIsValid = m_xParser.is();
+ }
+ }
+ return bIsValid;
+}
+
+sal_Int16 SbaXDataBrowserController::getCurrentColumnPosition() const
+{
+ Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY);
+ sal_Int16 nViewPos = -1;
+ try
+ {
+ if ( xGrid.is() )
+ nViewPos = xGrid->getCurrentColumnPosition();
+ }
+ catch(Exception&) {}
+ return nViewPos;
+}
+
+void SbaXDataBrowserController::setCurrentColumnPosition( sal_Int16 _nPos )
+{
+ Reference< css::form::XGrid > xGrid(getBrowserView()->getGridControl(), UNO_QUERY);
+ try
+ {
+ if ( -1 != _nPos )
+ xGrid->setCurrentColumnPosition(_nPos);
+ }
+ catch(Exception&) {}
+}
+
+void SbaXDataBrowserController::BeforeDrop()
+{
+ Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY);
+ if (xFormError.is())
+ xFormError->removeSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this));
+}
+
+void SbaXDataBrowserController::AfterDrop()
+{
+ Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY);
+ if (xFormError.is())
+ xFormError->addSQLErrorListener(static_cast<css::sdb::XSQLErrorListener*>(this));
+}
+
+void SbaXDataBrowserController::addColumnListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
+{
+// ... all the grid columns
+ Reference< css::container::XIndexContainer > xColumns(_xGridControlModel, UNO_QUERY);
+ if (xColumns.is())
+ {
+ sal_Int32 nCount = xColumns->getCount();
+ for (sal_Int32 i=0; i < nCount; ++i)
+ {
+ Reference< XPropertySet > xCol(xColumns->getByIndex(i),UNO_QUERY);
+ AddColumnListener(xCol);
+ }
+ }
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/brwview.cxx b/dbaccess/source/ui/browser/brwview.cxx
new file mode 100644
index 000000000..b68819d67
--- /dev/null
+++ b/dbaccess/source/ui/browser/brwview.cxx
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <brwview.hxx>
+#include <sbagrid.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/types.hxx>
+#include <vcl/split.hxx>
+#include <strings.hxx>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <osl/diagnose.h>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace
+{
+ bool isGrabVclControlFocusAllowed(const UnoDataBrowserView* _pView)
+ {
+ bool bGrabFocus = false;
+ SbaGridControl* pVclControl = _pView->getVclControl();
+ const Reference< css::awt::XControl >& xGrid = _pView->getGridControl();
+ if (pVclControl && xGrid.is())
+ {
+ bGrabFocus = true;
+ if(!pVclControl->HasChildPathFocus())
+ {
+ Reference<XChild> xChild(xGrid->getModel(),UNO_QUERY);
+ Reference<XLoadable> xLoad;
+ if(xChild.is())
+ xLoad.set(xChild->getParent(),UNO_QUERY);
+ bGrabFocus = xLoad.is() && xLoad->isLoaded();
+ }
+ }
+ return bGrabFocus;
+ }
+}
+
+// UnoDataBrowserView
+
+UnoDataBrowserView::UnoDataBrowserView( vcl::Window* pParent,
+ IController& _rController,
+ const Reference< css::uno::XComponentContext >& _rxContext)
+ :ODataView(pParent,_rController,_rxContext)
+ ,m_pTreeView(nullptr)
+ ,m_pSplitter(nullptr)
+ ,m_pVclControl(nullptr)
+{
+
+}
+
+void UnoDataBrowserView::Construct(const Reference< css::awt::XControlModel >& xModel)
+{
+ try
+ {
+ ODataView::Construct();
+
+ // our UNO representation
+ m_xMe = VCLUnoHelper::CreateControlContainer(this);
+
+ // create the (UNO-) control
+ m_xGrid = new SbaXGridControl( getORB() );
+ OSL_ENSURE(m_xGrid.is(), "UnoDataBrowserView::Construct : could not create a grid control !");
+ // in design mode (for the moment)
+ m_xGrid->setDesignMode(true);
+
+ Reference< css::awt::XWindow > xGridWindow(m_xGrid, UNO_QUERY);
+ xGridWindow->setVisible(true);
+ xGridWindow->setEnable(true);
+
+ // introduce the model to the grid
+ m_xGrid->setModel(xModel);
+ // introduce the container (me) to the grid
+ Reference< css::beans::XPropertySet > xModelSet(xModel, UNO_QUERY);
+ getContainer()->addControl(::comphelper::getString(xModelSet->getPropertyValue(PROPERTY_NAME)), m_xGrid);
+
+ // get the VCL-control
+ m_pVclControl = nullptr;
+ getVclControl();
+
+ OSL_ENSURE(m_pVclControl != nullptr, "UnoDataBrowserView::Construct : no real grid control !");
+ }
+ catch(const Exception&)
+ {
+ ::comphelper::disposeComponent(m_xGrid);
+ throw;
+ }
+}
+
+UnoDataBrowserView::~UnoDataBrowserView()
+{
+ disposeOnce();
+}
+
+void UnoDataBrowserView::dispose()
+{
+ m_pSplitter.disposeAndClear();
+ setTreeView(nullptr);
+
+ try
+ {
+ ::comphelper::disposeComponent(m_xGrid);
+ ::comphelper::disposeComponent(m_xMe);
+ }
+ catch(const Exception&)
+ {}
+ m_pTreeView.clear();
+ m_pVclControl.clear();
+ ODataView::dispose();
+}
+
+IMPL_LINK_NOARG( UnoDataBrowserView, SplitHdl, Splitter*, void )
+{
+ tools::Long nYPos = m_pSplitter->GetPosPixel().Y();
+ m_pSplitter->SetPosPixel( Point( m_pSplitter->GetSplitPosPixel(), nYPos ) );
+ Resize();
+}
+
+void UnoDataBrowserView::setSplitter(Splitter* _pSplitter)
+{
+ m_pSplitter = _pSplitter;
+ m_pSplitter->SetSplitHdl( LINK( this, UnoDataBrowserView, SplitHdl ) );
+ LINK( this, UnoDataBrowserView, SplitHdl ).Call(m_pSplitter);
+}
+
+void UnoDataBrowserView::setTreeView(InterimDBTreeListBox* pTreeView)
+{
+ if (m_pTreeView.get() != pTreeView)
+ {
+ m_pTreeView.disposeAndClear();
+ m_pTreeView = pTreeView;
+ }
+}
+
+void UnoDataBrowserView::showStatus( const OUString& _rStatus )
+{
+ if (_rStatus.isEmpty())
+ hideStatus();
+ else
+ {
+ if (!m_pTreeView)
+ return;
+ weld::Label& rLabel = m_pTreeView->GetStatusBar();
+ rLabel.set_label(_rStatus);
+ rLabel.show();
+ Resize();
+ PaintImmediately();
+ }
+}
+
+void UnoDataBrowserView::hideStatus()
+{
+ if (!m_pTreeView)
+ return;
+ weld::Label& rLabel = m_pTreeView->GetStatusBar();
+ if (!rLabel.get_visible())
+ {
+ // nothing to do
+ return;
+ }
+ rLabel.hide();
+ Resize();
+ PaintImmediately();
+}
+
+void UnoDataBrowserView::resizeDocumentView(tools::Rectangle& _rPlayground)
+{
+ Point aSplitPos;
+ Size aSplitSize;
+ Point aPlaygroundPos( _rPlayground.TopLeft() );
+ Size aPlaygroundSize( _rPlayground.GetSize() );
+
+ if (m_pTreeView && m_pTreeView->IsVisible() && m_pSplitter)
+ {
+ // calculate the splitter pos and size
+ aSplitPos = m_pSplitter->GetPosPixel();
+ aSplitPos.setY( aPlaygroundPos.Y() );
+ aSplitSize = m_pSplitter->GetOutputSizePixel();
+ aSplitSize.setHeight( aPlaygroundSize.Height() );
+
+ if( ( aSplitPos.X() + aSplitSize.Width() ) > ( aPlaygroundSize.Width() ))
+ aSplitPos.setX( aPlaygroundSize.Width() - aSplitSize.Width() );
+
+ if( aSplitPos.X() <= aPlaygroundPos.X() )
+ aSplitPos.setX( aPlaygroundPos.X() + sal_Int32(aPlaygroundSize.Width() * 0.2) );
+
+ // the tree pos and size
+ Point aTreeViewPos( aPlaygroundPos );
+ Size aTreeViewSize( aSplitPos.X(), aPlaygroundSize.Height() );
+
+ // set the size of treelistbox
+ m_pTreeView->SetPosSizePixel( aTreeViewPos, aTreeViewSize );
+ // Call this to trigger InterimItemWindow::Layout immediately, and
+ // not later on idle so the statusbar will be shown to explain
+ // a long delay on opening databases
+ m_pTreeView->Resize();
+
+ //set the size of the splitter
+ m_pSplitter->SetPosSizePixel( aSplitPos, Size( aSplitSize.Width(), aPlaygroundSize.Height() ) );
+ m_pSplitter->SetDragRectPixel( _rPlayground );
+ }
+
+ // set the size of grid control
+ Reference< css::awt::XWindow > xGridAsWindow(m_xGrid, UNO_QUERY);
+ if (xGridAsWindow.is())
+ xGridAsWindow->setPosSize( aSplitPos.X() + aSplitSize.Width(), aPlaygroundPos.Y(),
+ aPlaygroundSize.Width() - aSplitSize.Width() - aSplitPos.X(), aPlaygroundSize.Height(), css::awt::PosSize::POSSIZE);
+
+ // just for completeness: there is no space left, we occupied it all ...
+ _rPlayground.SetPos( _rPlayground.BottomRight() );
+ _rPlayground.SetSize( Size( 0, 0 ) );
+}
+
+sal_uInt16 UnoDataBrowserView::View2ModelPos(sal_uInt16 nPos) const
+{
+ return m_pVclControl ? m_pVclControl->GetModelColumnPos(m_pVclControl->GetColumnIdFromViewPos(nPos)) : -1;
+}
+
+SbaGridControl* UnoDataBrowserView::getVclControl() const
+{
+ if ( !m_pVclControl )
+ {
+ OSL_ENSURE(m_xGrid.is(),"Grid not set!");
+ if ( m_xGrid.is() )
+ {
+ Reference< css::awt::XWindowPeer > xPeer = m_xGrid->getPeer();
+ if ( xPeer.is() )
+ {
+ SbaXGridPeer* pPeer = comphelper::getFromUnoTunnel<SbaXGridPeer>(xPeer);
+ UnoDataBrowserView* pTHIS = const_cast<UnoDataBrowserView*>(this);
+ if ( pPeer )
+ {
+ m_pVclControl = static_cast<SbaGridControl*>(pPeer->GetWindow());
+ pTHIS->startComponentListening(VCLUnoHelper::GetInterface(m_pVclControl));
+ }
+ }
+ }
+ }
+ return m_pVclControl;
+}
+
+void UnoDataBrowserView::GetFocus()
+{
+ ODataView::GetFocus();
+ if( m_pTreeView && m_pTreeView->IsVisible() && !m_pTreeView->HasChildPathFocus())
+ m_pTreeView->GrabFocus();
+ else if (m_pVclControl && m_xGrid.is())
+ {
+ bool bGrabFocus = false;
+ if(!m_pVclControl->HasChildPathFocus())
+ {
+ bGrabFocus = isGrabVclControlFocusAllowed(this);
+ if( bGrabFocus )
+ m_pVclControl->GrabFocus();
+ }
+ if(!bGrabFocus && m_pTreeView && m_pTreeView->IsVisible() )
+ m_pTreeView->GrabFocus();
+ }
+}
+
+void UnoDataBrowserView::_disposing( const css::lang::EventObject& /*_rSource*/ )
+{
+ stopComponentListening(VCLUnoHelper::GetInterface(m_pVclControl));
+ m_pVclControl = nullptr;
+}
+
+bool UnoDataBrowserView::PreNotify( NotifyEvent& rNEvt )
+{
+ bool bDone = false;
+ if(rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
+ {
+ bool bGrabAllowed = isGrabVclControlFocusAllowed(this);
+ if ( bGrabAllowed )
+ {
+ const KeyEvent* pKeyEvt = rNEvt.GetKeyEvent();
+ const vcl::KeyCode& rKeyCode = pKeyEvt->GetKeyCode();
+ if ( ( rKeyCode == vcl::KeyCode( KEY_E, true, true, false, false ) )
+ || ( rKeyCode == vcl::KeyCode( KEY_TAB, true, false, false, false ) )
+ )
+ {
+ if ( m_pTreeView && m_pVclControl && m_pTreeView->HasChildPathFocus() )
+ m_pVclControl->GrabFocus();
+ else if ( m_pTreeView && m_pVclControl && m_pVclControl->HasChildPathFocus() )
+ m_pTreeView->GrabFocus();
+
+ bDone = true;
+ }
+ }
+ }
+ return bDone || ODataView::PreNotify(rNEvt);
+}
+
+BrowserViewStatusDisplay::BrowserViewStatusDisplay( UnoDataBrowserView* _pView, const OUString& _rStatus )
+ :m_pView(_pView)
+{
+
+ if (m_pView)
+ m_pView->showStatus(_rStatus);
+}
+
+BrowserViewStatusDisplay::~BrowserViewStatusDisplay( )
+{
+ if (m_pView)
+ m_pView->showStatus(OUString());
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/dataview.cxx b/dbaccess/source/ui/browser/dataview.cxx
new file mode 100644
index 000000000..74ceea688
--- /dev/null
+++ b/dbaccess/source/ui/browser/dataview.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <dbaccess/dataview.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <dbaccess/IController.hxx>
+#include <svtools/acceleratorexecute.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::frame;
+
+ ODataView::ODataView( vcl::Window* pParent,
+ IController& _rController,
+ const Reference< XComponentContext >& _rxContext,
+ WinBits nStyle)
+ :Window(pParent,nStyle)
+ ,m_xContext(_rxContext)
+ ,m_xController( &_rController )
+ {
+ m_pAccel = ::svt::AcceleratorExecute::createAcceleratorHelper();
+ }
+
+ void ODataView::Construct()
+ {
+ }
+
+ ODataView::~ODataView()
+ {
+ disposeOnce();
+ }
+
+ void ODataView::dispose()
+ {
+ m_xController.clear();
+ m_pAccel.reset();
+ vcl::Window::dispose();
+ }
+
+ void ODataView::resizeDocumentView(tools::Rectangle& /*_rPlayground*/)
+ {
+ }
+
+ void ODataView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect)
+ {
+ // draw the background
+ {
+ rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
+ rRenderContext.SetLineColor(COL_TRANSPARENT);
+ rRenderContext.SetFillColor(GetSettings().GetStyleSettings().GetFaceColor());
+ rRenderContext.DrawRect(_rRect);
+ rRenderContext.Pop();
+ }
+
+ // let the base class do anything it needs
+ Window::Paint(rRenderContext, _rRect);
+ }
+
+ void ODataView::resizeAll(const tools::Rectangle& rPlayground)
+ {
+ // position the controls of the document's view
+ tools::Rectangle aPlayground(rPlayground);
+ resizeDocumentView(aPlayground);
+ }
+
+ void ODataView::Resize()
+ {
+ Window::Resize();
+ resizeAll( tools::Rectangle( Point( 0, 0), GetSizePixel() ) );
+ }
+ bool ODataView::PreNotify( NotifyEvent& _rNEvt )
+ {
+ bool bHandled = false;
+ switch ( _rNEvt.GetType() )
+ {
+ case MouseNotifyEvent::KEYINPUT:
+ {
+ const KeyEvent* pKeyEvent = _rNEvt.GetKeyEvent();
+ const vcl::KeyCode& aKeyCode = pKeyEvent->GetKeyCode();
+ if ( m_pAccel && m_pAccel->execute( aKeyCode ) )
+ // the accelerator consumed the event
+ return true;
+ [[fallthrough]];
+ }
+ case MouseNotifyEvent::KEYUP:
+ case MouseNotifyEvent::MOUSEBUTTONDOWN:
+ case MouseNotifyEvent::MOUSEBUTTONUP:
+ bHandled = m_xController->interceptUserInput( _rNEvt );
+ break;
+ default:
+ break;
+ }
+ return bHandled || Window::PreNotify( _rNEvt );
+ }
+ void ODataView::StateChanged( StateChangedType nType )
+ {
+ Window::StateChanged( nType );
+
+ if ( nType != StateChangedType::InitShow )
+ return;
+
+ // now that there's a view which is finally visible, remove the "Hidden" value from the
+ // model's arguments.
+ try
+ {
+ Reference< XController > xController( m_xController->getXController(), UNO_SET_THROW );
+ Reference< XModel > xModel = xController->getModel();
+ if ( xModel.is() )
+ {
+ ::comphelper::NamedValueCollection aArgs( xModel->getArgs() );
+ aArgs.remove( "Hidden" );
+ xModel->attachResource( xModel->getURL(), aArgs.getPropertyValues() );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void ODataView::attachFrame(const Reference< XFrame >& _xFrame)
+ {
+ m_pAccel->init(m_xContext, _xFrame);
+ }
+}
+
+// namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/dbexchange.cxx b/dbaccess/source/ui/browser/dbexchange.cxx
new file mode 100644
index 000000000..dc6398f48
--- /dev/null
+++ b/dbaccess/source/ui/browser/dbexchange.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbexchange.hxx>
+#include <sot/formats.hxx>
+#include <sot/storage.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <TokenWriter.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <UITools.hxx>
+
+namespace dbaui
+{
+ constexpr sal_uInt32 FORMAT_OBJECT_ID_RTF = 1;
+ constexpr sal_uInt32 FORMAT_OBJECT_ID_HTML = 2;
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::datatransfer;
+ using namespace ::svx;
+
+ namespace
+ {
+ template<class T > void lcl_setListener(const Reference<T>& _xComponent, const Reference< XEventListener >& i_rListener, const bool i_bAdd )
+ {
+ if ( !_xComponent.is() )
+ return;
+
+ Reference< XComponent> xCom( _xComponent, UNO_QUERY );
+ OSL_ENSURE( xCom.is(), "lcl_setListener: no component!" );
+ if ( !xCom.is() )
+ return;
+
+ i_bAdd ? xCom->addEventListener( i_rListener ) : xCom->removeEventListener( i_rListener );
+ }
+ }
+
+ ODataClipboard::ODataClipboard()
+ {
+ }
+
+ void ODataClipboard::Update(
+ const OUString& rDatasource,
+ const sal_Int32 nCommandType,
+ const OUString& rCommand,
+ const Reference< XConnection >& rxConnection,
+ const Reference< XNumberFormatter >& rxFormatter,
+ const Reference< XComponentContext >& rxORB)
+ {
+ ClearFormats();
+
+ ODataAccessObjectTransferable::Update(rDatasource, nCommandType, rCommand, rxConnection);
+
+ lcl_setListener(rxConnection, this, true);
+
+ m_pHtml.set(new OHTMLImportExport(getDescriptor(), rxORB, rxFormatter));
+ m_pRtf.set(new ORTFImportExport(getDescriptor(), rxORB, rxFormatter));
+
+ AddSupportedFormats();
+ }
+
+ void ODataClipboard::Update(
+ const OUString& rDatasource,
+ const sal_Int32 nCommandType,
+ const OUString& rCommand,
+ const Reference< XNumberFormatter >& rxFormatter,
+ const Reference< XComponentContext >& rxORB)
+ {
+ ClearFormats();
+
+ ODataAccessObjectTransferable::Update(rDatasource, nCommandType, rCommand);
+
+ m_pHtml.set(new OHTMLImportExport(getDescriptor(), rxORB, rxFormatter));
+ m_pRtf.set(new ORTFImportExport(getDescriptor(), rxORB, rxFormatter));
+
+ AddSupportedFormats();
+ }
+
+ ODataClipboard::ODataClipboard( const Reference< XPropertySet >& i_rAliveForm,
+ const Sequence< Any >& i_rSelectedRows,
+ const bool i_bBookmarkSelection,
+ const Reference< XComponentContext >& i_rORB )
+ :ODataAccessObjectTransferable( i_rAliveForm )
+ {
+ OSL_PRECOND( i_rORB.is(), "ODataClipboard::ODataClipboard: having no factory is not good ..." );
+
+ osl_atomic_increment( &m_refCount );
+
+ Reference<XConnection> xConnection;
+ getDescriptor()[ DataAccessDescriptorProperty::Connection ] >>= xConnection;
+ lcl_setListener( xConnection, this, true );
+
+ // do not pass the form itself as source result set, since the client might operate on the form, which
+ // might lead to undesired effects. Instead, use a clone.
+ Reference< XResultSet > xResultSetClone;
+ Reference< XResultSetAccess > xResultSetAccess( i_rAliveForm, UNO_QUERY );
+ if ( xResultSetAccess.is() )
+ xResultSetClone = xResultSetAccess->createResultSet();
+ OSL_ENSURE( xResultSetClone.is(), "ODataClipboard::ODataClipboard: could not clone the form's result set" );
+ lcl_setListener( xResultSetClone, this, true );
+
+ getDescriptor()[DataAccessDescriptorProperty::Cursor] <<= xResultSetClone;
+ getDescriptor()[DataAccessDescriptorProperty::Selection] <<= i_rSelectedRows;
+ getDescriptor()[DataAccessDescriptorProperty::BookmarkSelection]<<= i_bBookmarkSelection;
+ addCompatibleSelectionDescription( i_rSelectedRows );
+
+ if ( xConnection.is() && i_rORB.is() )
+ {
+ Reference< XNumberFormatter > xFormatter( getNumberFormatter( xConnection, i_rORB ) );
+ if ( xFormatter.is() )
+ {
+ m_pHtml.set( new OHTMLImportExport( getDescriptor(), i_rORB, xFormatter ) );
+ m_pRtf.set( new ORTFImportExport( getDescriptor(), i_rORB, xFormatter ) );
+ }
+ }
+
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ bool ODataClipboard::WriteObject( ::tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& /*rFlavor*/ )
+ {
+ if (nUserObjectId == FORMAT_OBJECT_ID_RTF || nUserObjectId == FORMAT_OBJECT_ID_HTML )
+ {
+ ODatabaseImportExport* pExport = static_cast<ODatabaseImportExport*>(pUserObject);
+ if ( pExport && rxOStm.is() )
+ {
+ pExport->setStream(rxOStm.get());
+ return pExport->Write();
+ }
+ }
+ return false;
+ }
+
+ void ODataClipboard::AddSupportedFormats()
+ {
+ if ( m_pRtf.is() )
+ AddFormat( SotClipboardFormatId::RTF );
+
+ if ( m_pHtml.is() )
+ AddFormat( SotClipboardFormatId::HTML );
+
+ ODataAccessObjectTransferable::AddSupportedFormats();
+ }
+
+ bool ODataClipboard::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
+ {
+ const SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor);
+ switch (nFormat)
+ {
+ case SotClipboardFormatId::RTF:
+ if ( m_pRtf.is() )
+ m_pRtf->initialize(getDescriptor());
+ return m_pRtf.is() && SetObject( m_pRtf.get(), FORMAT_OBJECT_ID_RTF, rFlavor );
+
+ case SotClipboardFormatId::HTML:
+ if ( m_pHtml.is() )
+ m_pHtml->initialize(getDescriptor());
+ return m_pHtml.is() && SetObject( m_pHtml.get(), FORMAT_OBJECT_ID_HTML, rFlavor );
+
+ default: break;
+ }
+
+ return ODataAccessObjectTransferable::GetData(rFlavor, rDestDoc);
+ }
+
+ void ODataClipboard::ObjectReleased()
+ {
+ if ( m_pHtml.is() )
+ {
+ m_pHtml->dispose();
+ m_pHtml.clear();
+ }
+
+ if ( m_pRtf.is() )
+ {
+ m_pRtf->dispose();
+ m_pRtf.clear();
+ }
+
+ if ( getDescriptor().has( DataAccessDescriptorProperty::Connection ) )
+ {
+ Reference<XConnection> xConnection( getDescriptor()[DataAccessDescriptorProperty::Connection], UNO_QUERY );
+ lcl_setListener( xConnection, this, false );
+ }
+
+ if ( getDescriptor().has( DataAccessDescriptorProperty::Cursor ) )
+ {
+ Reference< XResultSet > xResultSet( getDescriptor()[ DataAccessDescriptorProperty::Cursor ], UNO_QUERY );
+ lcl_setListener( xResultSet, this, false );
+ }
+
+ ODataAccessObjectTransferable::ObjectReleased( );
+ }
+
+ void SAL_CALL ODataClipboard::disposing( const css::lang::EventObject& i_rSource )
+ {
+ ODataAccessDescriptor& rDescriptor( getDescriptor() );
+
+ if ( rDescriptor.has( DataAccessDescriptorProperty::Connection ) )
+ {
+ Reference< XConnection > xConnection( rDescriptor[DataAccessDescriptorProperty::Connection], UNO_QUERY );
+ if ( xConnection == i_rSource.Source )
+ {
+ rDescriptor.erase( DataAccessDescriptorProperty::Connection );
+ }
+ }
+
+ if ( rDescriptor.has( DataAccessDescriptorProperty::Cursor ) )
+ {
+ Reference< XResultSet > xResultSet( rDescriptor[ DataAccessDescriptorProperty::Cursor ], UNO_QUERY );
+ if ( xResultSet == i_rSource.Source )
+ {
+ rDescriptor.erase( DataAccessDescriptorProperty::Cursor );
+ // Selection and BookmarkSelection are meaningless without a result set
+ if ( rDescriptor.has( DataAccessDescriptorProperty::Selection ) )
+ rDescriptor.erase( DataAccessDescriptorProperty::Selection );
+ if ( rDescriptor.has( DataAccessDescriptorProperty::BookmarkSelection ) )
+ rDescriptor.erase( DataAccessDescriptorProperty::BookmarkSelection );
+ }
+ }
+
+ // no matter whether it was the source connection or the source result set which died,
+ // we cannot provide the data anymore.
+ ClearFormats();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/dbloader.cxx b/dbaccess/source/ui/browser/dbloader.cxx
new file mode 100644
index 000000000..330d23a12
--- /dev/null
+++ b/dbaccess/source/ui/browser/dbloader.cxx
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hxx>
+#include <UITools.hxx>
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XFrameLoader.hpp>
+#include <com/sun/star/frame/XLoadEventListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdb/ReportDesign.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/frame/XModule.hpp>
+
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace dbaui;
+
+namespace {
+
+class DBContentLoader : public ::cppu::WeakImplHelper< XFrameLoader, XServiceInfo>
+{
+private:
+ Sequence< PropertyValue> m_aArgs;
+ Reference< XLoadEventListener > m_xListener;
+ Reference< XComponentContext > m_xContext;
+public:
+ explicit DBContentLoader(const Reference< XComponentContext >&);
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XLoader
+ virtual void SAL_CALL load( const Reference< XFrame > & _rFrame, const OUString& _rURL,
+ const Sequence< PropertyValue >& _rArgs,
+ const Reference< XLoadEventListener > & _rListener) override;
+ virtual void SAL_CALL cancel() override;
+};
+
+}
+
+DBContentLoader::DBContentLoader(const Reference< XComponentContext >& _rxContext)
+ :m_xContext(_rxContext)
+{
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_DBContentLoader_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new DBContentLoader(context));
+}
+
+// XServiceInfo
+OUString SAL_CALL DBContentLoader::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.DBContentLoader";
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.FrameLoader", "com.sun.star.sdb.ContentLoader" };
+}
+
+void SAL_CALL DBContentLoader::load(const Reference< XFrame > & rFrame, const OUString& rURL,
+ const Sequence< PropertyValue >& rArgs,
+ const Reference< XLoadEventListener > & rListener)
+{
+ m_xListener = rListener;
+ m_aArgs = rArgs;
+
+ static constexpr struct ServiceNameToImplName
+ {
+ rtl::OUStringConstExpr sServiceName;
+ const char* pAsciiImplementationName;
+ } aImplementations[] = {
+ { URL_COMPONENT_FORMGRIDVIEW, "org.openoffice.comp.dbu.OFormGridView" },
+ { URL_COMPONENT_DATASOURCEBROWSER, "org.openoffice.comp.dbu.ODatasourceBrowser" },
+ { URL_COMPONENT_QUERYDESIGN, "org.openoffice.comp.dbu.OQueryDesign" },
+ { URL_COMPONENT_TABLEDESIGN, "org.openoffice.comp.dbu.OTableDesign" },
+ { URL_COMPONENT_RELATIONDESIGN, "org.openoffice.comp.dbu.ORelationDesign" },
+ { URL_COMPONENT_VIEWDESIGN, "org.openoffice.comp.dbu.OViewDesign" }
+ };
+
+ INetURLObject aParser( rURL );
+ Reference< XController2 > xController;
+
+ const OUString sComponentURL( aParser.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ) );
+ for (const ServiceNameToImplName& aImplementation : aImplementations)
+ {
+ if ( sComponentURL == aImplementation.sServiceName )
+ {
+ xController.set( m_xContext->getServiceManager()->
+ createInstanceWithContext( OUString::createFromAscii( aImplementation.pAsciiImplementationName ), m_xContext), UNO_QUERY_THROW );
+ break;
+ }
+ }
+
+ // if a data source browser is loaded without its tree pane, then we assume it to be a
+ // table data view, effectively. In this case, we need to adjust the module identifier.
+ // #i85879#
+ ::comphelper::NamedValueCollection aLoadArgs( rArgs );
+
+ if ( sComponentURL == URL_COMPONENT_DATASOURCEBROWSER )
+ {
+ bool bDisableBrowser = !aLoadArgs.getOrDefault( "ShowTreeViewButton", true ) // compatibility name
+ || !aLoadArgs.getOrDefault( PROPERTY_ENABLE_BROWSER, true );
+
+ if ( bDisableBrowser )
+ {
+ try
+ {
+ Reference< XModule > xModule( xController, UNO_QUERY_THROW );
+ xModule->setIdentifier( "com.sun.star.sdb.TableDataView" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ if ( sComponentURL == URL_COMPONENT_REPORTDESIGN )
+ {
+ bool bPreview = aLoadArgs.getOrDefault( "Preview", false );
+ if ( bPreview )
+ { // report designs cannot be previewed
+ if ( rListener.is() )
+ rListener->loadCancelled( this );
+ return;
+ }
+ Reference< XModel > xReportModel( aLoadArgs.getOrDefault( "Model", Reference< XModel >() ) );
+ if ( xReportModel.is() )
+ {
+ xController.set( ReportDesign::create( m_xContext ) );
+ xController->attachModel( xReportModel );
+ xReportModel->connectController( xController );
+ xReportModel->setCurrentController( xController );
+ }
+ }
+
+ bool bSuccess = xController.is();
+ Reference< XModel > xDatabaseDocument;
+ if ( bSuccess )
+ {
+ Reference< XDataSource > xDataSource ( aLoadArgs.getOrDefault( "DataSource", Reference< XDataSource >() ) );
+ OUString sDataSourceName( aLoadArgs.getOrDefault( "DataSourceName", OUString() ) );
+ Reference< XConnection > xConnection ( aLoadArgs.getOrDefault( "ActiveConnection", Reference< XConnection >() ) );
+ if ( xDataSource.is() )
+ {
+ xDatabaseDocument.set( getDataSourceOrModel( xDataSource ), UNO_QUERY );
+ }
+ else if ( !sDataSourceName.isEmpty() )
+ {
+ ::dbtools::SQLExceptionInfo aError;
+ xDataSource.set( getDataSourceByName( sDataSourceName, nullptr, m_xContext, &aError ) );
+ xDatabaseDocument.set( getDataSourceOrModel( xDataSource ), UNO_QUERY );
+ }
+ else if ( xConnection.is() )
+ {
+ Reference< XChild > xAsChild( xConnection, UNO_QUERY );
+ if ( xAsChild.is() )
+ {
+ OSL_ENSURE( Reference< XDataSource >( xAsChild->getParent(), UNO_QUERY ).is(),
+ "DBContentLoader::load: a connection whose parent is no data source?" );
+ xDatabaseDocument.set( getDataSourceOrModel( xAsChild->getParent() ), UNO_QUERY );
+ }
+ }
+
+ // init controller
+ SolarMutexGuard aGuard;
+ try
+ {
+ Reference<XInitialization > xIni(xController,UNO_QUERY);
+ PropertyValue aFrame("Frame",0,Any(rFrame),PropertyState_DIRECT_VALUE);
+ Sequence< Any > aInitArgs(m_aArgs.getLength()+1);
+
+ Any* pBegin = aInitArgs.getArray();
+ Any* pEnd = pBegin + aInitArgs.getLength();
+ *pBegin <<= aFrame;
+ const PropertyValue* pIter = m_aArgs.getConstArray();
+ for(++pBegin;pBegin != pEnd;++pBegin,++pIter)
+ {
+ *pBegin <<= *pIter;
+ }
+
+ xIni->initialize(aInitArgs);
+ }
+ catch(const Exception&)
+ {
+ // Does this need to be shown to the user?
+ bSuccess = false;
+ try
+ {
+ ::comphelper::disposeComponent( xController );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ // assign controller and frame
+ if ( bSuccess )
+ {
+ if ( xController.is() && rFrame.is() )
+ {
+ rFrame->setComponent( xController->getComponentWindow(), xController );
+ xController->attachFrame(rFrame);
+ }
+
+ if ( rListener.is() )
+ rListener->loadFinished( this );
+ }
+ else
+ if ( rListener.is() )
+ rListener->loadCancelled( this );
+}
+
+void DBContentLoader::cancel()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/dbtreemodel.cxx b/dbaccess/source/ui/browser/dbtreemodel.cxx
new file mode 100644
index 000000000..88a9faeb0
--- /dev/null
+++ b/dbaccess/source/ui/browser/dbtreemodel.cxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "dbtreemodel.hxx"
+
+namespace dbaui
+{
+ DBTreeListUserData::DBTreeListUserData()
+ :eType(SbaTableQueryBrowser::etQuery)
+ {
+ }
+ DBTreeListUserData::~DBTreeListUserData()
+ {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/dbtreemodel.hxx b/dbaccess/source/ui/browser/dbtreemodel.hxx
new file mode 100644
index 000000000..2ea11b900
--- /dev/null
+++ b/dbaccess/source/ui/browser/dbtreemodel.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unodatbr.hxx>
+#include <commontypes.hxx>
+
+// syntax of the tree userdata
+// datasource holds the connection
+// queries holds the nameaccess for the queries
+// query holds the query
+// tables holds the nameaccess for the tables
+// table holds the table
+
+#define CONTAINER_QUERIES sal_uLong( 0 )
+#define CONTAINER_TABLES sal_uLong( 1 )
+
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+
+namespace dbaui
+{
+ struct DBTreeListUserData
+ {
+ /// if the entry denotes a table or query, this is the respective UNO object
+ css::uno::Reference< css::beans::XPropertySet >
+ xObjectProperties;
+ /// if the entry denotes an object container, this is the UNO interface for this container
+ css::uno::Reference< css::uno::XInterface >
+ xContainer;
+ /// if the entry denotes a data source, this is the connection for this data source (if already connection)
+ SharedConnection xConnection;
+ SbaTableQueryBrowser::EntryType eType;
+ OUString sAccessor;
+
+ DBTreeListUserData();
+ ~DBTreeListUserData();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/dsEntriesNoExp.cxx b/dbaccess/source/ui/browser/dsEntriesNoExp.cxx
new file mode 100644
index 000000000..b31261df1
--- /dev/null
+++ b/dbaccess/source/ui/browser/dsEntriesNoExp.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <unodatbr.hxx>
+#include <browserids.hxx>
+#include <osl/diagnose.h>
+#include <dbtreelistbox.hxx>
+#include "dbtreemodel.hxx"
+
+using namespace ::com::sun::star::frame;
+using namespace ::dbtools;
+using namespace ::svx;
+
+namespace dbaui
+{
+SbaTableQueryBrowser::EntryType SbaTableQueryBrowser::getChildType(const weld::TreeIter& rEntry) const
+{
+ OSL_ENSURE(isContainer(rEntry), "SbaTableQueryBrowser::getChildType: invalid entry!");
+ switch (getEntryType(rEntry))
+ {
+ case etTableContainer:
+ return etTableOrView;
+ case etQueryContainer:
+ return etQuery;
+ default:
+ break;
+ }
+ return etUnknown;
+}
+
+OUString SbaTableQueryBrowser::GetEntryText(const weld::TreeIter& rEntry) const
+{
+ return m_pTreeView->GetWidget().get_text(rEntry);
+}
+
+SbaTableQueryBrowser::EntryType SbaTableQueryBrowser::getEntryType(const weld::TreeIter& rEntry) const
+{
+ const weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntry));
+ return pEntryData ? pEntryData->eType : etUnknown;
+}
+
+void SbaTableQueryBrowser::select(const weld::TreeIter* pEntry, bool bSelect)
+{
+ if (pEntry)
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ rTreeView.set_text_emphasis(*pEntry, bSelect, 0);
+ }
+ else
+ {
+ OSL_FAIL("SbaTableQueryBrowser::select: invalid entry!");
+ }
+}
+
+void SbaTableQueryBrowser::selectPath(const weld::TreeIter* pEntry, bool bSelect)
+{
+ if (!pEntry)
+ return;
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(pEntry));
+ do
+ {
+ select(xEntry.get(), bSelect);
+ }
+ while (rTreeView.iter_parent(*xEntry));
+}
+
+bool SbaTableQueryBrowser::isSelected(const weld::TreeIter& rEntry) const
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ return rTreeView.get_text_emphasis(rEntry, 0);
+}
+
+void SbaTableQueryBrowser::SelectionChanged()
+{
+ if ( !m_bShowMenu )
+ {
+ InvalidateFeature(ID_BROWSER_INSERTCOLUMNS);
+ InvalidateFeature(ID_BROWSER_INSERTCONTENT);
+ InvalidateFeature(ID_BROWSER_FORMLETTER);
+ }
+ InvalidateFeature(ID_BROWSER_COPY);
+ InvalidateFeature(ID_BROWSER_CUT);
+}
+
+void SbaTableQueryBrowser::describeSupportedFeatures()
+{
+ SbaXDataBrowserController::describeSupportedFeatures();
+
+ implDescribeSupportedFeature( ".uno:Title", ID_BROWSER_TITLE );
+ if ( !m_bShowMenu )
+ {
+ implDescribeSupportedFeature( ".uno:DSBEditDB", ID_TREE_EDIT_DATABASE );
+ implDescribeSupportedFeature( ".uno:DSBCloseConnection", ID_TREE_CLOSE_CONN );
+ implDescribeSupportedFeature( ".uno:DSBAdministrate", ID_TREE_ADMINISTRATE );
+
+ implDescribeSupportedFeature( ".uno:DSBrowserExplorer", ID_BROWSER_EXPLORER, CommandGroup::VIEW );
+
+ implDescribeSupportedFeature( ".uno:DSBFormLetter", ID_BROWSER_FORMLETTER, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DSBInsertColumns", ID_BROWSER_INSERTCOLUMNS, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DSBInsertContent", ID_BROWSER_INSERTCONTENT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DSBDocumentDataSource", ID_BROWSER_DOCUMENT_DATASOURCE, CommandGroup::VIEW );
+
+ implDescribeSupportedFeature( ".uno:DataSourceBrowser/FormLetter", ID_BROWSER_FORMLETTER );
+ implDescribeSupportedFeature( ".uno:DataSourceBrowser/InsertColumns", ID_BROWSER_INSERTCOLUMNS );
+ implDescribeSupportedFeature( ".uno:DataSourceBrowser/InsertContent", ID_BROWSER_INSERTCONTENT );
+ implDescribeSupportedFeature( ".uno:DataSourceBrowser/DocumentDataSource", ID_BROWSER_DOCUMENT_DATASOURCE );
+ }
+
+ implDescribeSupportedFeature( ".uno:CloseWin", ID_BROWSER_CLOSE, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBRebuildData", ID_BROWSER_REFRESH_REBUILD, CommandGroup::DATA );
+}
+
+sal_Int32 SbaTableQueryBrowser::getDatabaseObjectType( EntryType _eType )
+{
+ switch ( _eType )
+ {
+ case etQuery:
+ case etQueryContainer:
+ return css::sdb::application::DatabaseObject::QUERY;
+ case etTableOrView:
+ case etTableContainer:
+ return css::sdb::application::DatabaseObject::TABLE;
+ default:
+ break;
+ }
+ OSL_FAIL( "SbaTableQueryBrowser::getDatabaseObjectType: folder types and 'Unknown' not allowed here!" );
+ return css::sdb::application::DatabaseObject::TABLE;
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/dsbrowserDnD.cxx b/dbaccess/source/ui/browser/dsbrowserDnD.cxx
new file mode 100644
index 000000000..961fd731a
--- /dev/null
+++ b/dbaccess/source/ui/browser/dsbrowserDnD.cxx
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbexchange.hxx>
+#include <dbtreelistbox.hxx>
+#include "dbtreemodel.hxx"
+#include <UITools.hxx>
+#include <unodatbr.hxx>
+
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+
+#include <algorithm>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::io;
+ using namespace ::com::sun::star::i18n;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::datatransfer;
+ using namespace ::dbtools;
+ using namespace ::svx;
+
+ bool SbaTableQueryBrowser::implCopyObject(ODataClipboard& rExchange, const weld::TreeIter& rApplyTo, sal_Int32 nCommandType)
+ {
+ try
+ {
+ OUString aName = GetEntryText(rApplyTo);
+ std::unique_ptr<weld::TreeIter> xRootEntry(m_pTreeView->GetRootLevelParent(&rApplyTo));
+ OUString aDSName = getDataSourceAccessor(*xRootEntry);
+
+ SharedConnection xConnection;
+ if ( CommandType::QUERY != nCommandType )
+ {
+ if (!ensureConnection(&rApplyTo, xConnection))
+ return false;
+ rExchange.Update(aDSName, nCommandType, aName, xConnection, getNumberFormatter(), getORB());
+ }
+ else
+ rExchange.Update(aDSName, nCommandType, aName, getNumberFormatter(), getORB());
+
+ // the ownership goes to ODataClipboards
+ return true;
+ }
+ catch(const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return false;
+ }
+
+ sal_Int8 SbaTableQueryBrowser::queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors )
+ {
+ // check if we're a table or query container
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xHitEntry(rTreeView.make_iterator());
+ // get_dest_row_at_pos with false cause no drop if no entry was hit exactly
+ if (rTreeView.get_dest_row_at_pos(_rEvt.maPosPixel, xHitEntry.get(), false))
+ {
+ // it must be a container
+ EntryType eEntryType = getEntryType(*xHitEntry);
+ SharedConnection xConnection;
+ if ( eEntryType == etTableContainer && ensureConnection(xHitEntry.get(), xConnection ) && xConnection.is())
+ {
+ Reference<XChild> xChild(xConnection,UNO_QUERY);
+ Reference<XStorable> xStore;
+ if ( xChild.is() )
+ xStore.set( getDataSourceOrModel(xChild->getParent()), UNO_QUERY );
+ // check for the concrete type
+ if ( xStore.is() && !xStore->isReadonly() && std::any_of(_rFlavors.begin(),_rFlavors.end(),TAppSupportedSotFunctor(E_TABLE)) )
+ return DND_ACTION_COPY;
+ }
+ }
+
+ return DND_ACTION_NONE;
+ }
+ sal_Int8 SbaTableQueryBrowser::executeDrop( const ExecuteDropEvent& _rEvt )
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xHitEntry(rTreeView.make_iterator());
+ // get_dest_row_at_pos with false cause no drop if no entry was hit exactly
+ if (!rTreeView.get_dest_row_at_pos(_rEvt.maPosPixel, xHitEntry.get(), false))
+ return DND_ACTION_NONE;
+ EntryType eEntryType = getEntryType(*xHitEntry);
+ if (!isContainer(eEntryType))
+ {
+ OSL_FAIL("SbaTableQueryBrowser::executeDrop: what the hell did queryDrop do?");
+ // queryDrop should not have allowed us to reach this situation...
+ return DND_ACTION_NONE;
+ }
+ // a TransferableDataHelper for accessing the dropped data
+ TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable);
+
+ // reset the data of the previous async drop (if any)
+ if ( m_nAsyncDrop )
+ Application::RemoveUserEvent(m_nAsyncDrop);
+
+ m_nAsyncDrop = nullptr;
+ m_aAsyncDrop.aDroppedData.clear();
+ m_aAsyncDrop.nType = E_TABLE;
+ m_aAsyncDrop.nAction = _rEvt.mnAction;
+ m_aAsyncDrop.bError = false;
+ m_aAsyncDrop.bHtml = false;
+ m_aAsyncDrop.xDroppedAt.reset();
+ m_aAsyncDrop.aUrl.clear();
+
+ // loop through the available formats and see what we can do ...
+ // first we have to check if it is our own format, if not we have to copy the stream :-(
+ if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(aDroppedData.GetDataFlavorExVector()) )
+ {
+ m_aAsyncDrop.aDroppedData = ODataAccessObjectTransferable::extractObjectDescriptor(aDroppedData);
+ m_aAsyncDrop.xDroppedAt = std::move(xHitEntry);
+
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, SbaTableQueryBrowser, OnAsyncDrop));
+ return DND_ACTION_COPY;
+ }
+ else
+ {
+ SharedConnection xDestConnection;
+ if ( ensureConnection( xHitEntry.get(), xDestConnection )
+ && xDestConnection.is()
+ && m_aTableCopyHelper.copyTagTable( aDroppedData, m_aAsyncDrop, xDestConnection )
+ )
+ {
+ m_aAsyncDrop.xDroppedAt = std::move(xHitEntry);
+
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, SbaTableQueryBrowser, OnAsyncDrop));
+ return DND_ACTION_COPY;
+ }
+ }
+
+ return DND_ACTION_NONE;
+ }
+
+ bool SbaTableQueryBrowser::requestDrag(const weld::TreeIter& rEntry)
+ {
+ // it must be a query/table
+ EntryType eEntryType = getEntryType(rEntry);
+ if (!isObject(eEntryType))
+ return false;
+
+ ODataClipboard& rExchange = static_cast<ODataClipboard&>(m_pTreeView->GetDataTransfer());
+ return implCopyObject(rExchange, rEntry, (etTableOrView == eEntryType) ? CommandType::TABLE : CommandType::QUERY);
+ }
+
+ IMPL_LINK_NOARG(SbaTableQueryBrowser, OnCopyEntry, LinkParamNone*, void)
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xSelected = rTreeView.make_iterator();
+ if (rTreeView.get_selected(xSelected.get()) && isEntryCopyAllowed(*xSelected))
+ copyEntry(*xSelected);
+ }
+
+ bool SbaTableQueryBrowser::isEntryCopyAllowed(const weld::TreeIter& rEntry) const
+ {
+ EntryType eType = getEntryType(rEntry);
+ return ( eType == etTableOrView || eType == etQuery );
+ }
+
+ void SbaTableQueryBrowser::copyEntry(const weld::TreeIter& rEntry)
+ {
+ EntryType eType = getEntryType(rEntry);
+ rtl::Reference<ODataClipboard> xTransfer(new ODataClipboard);
+ if (implCopyObject(*xTransfer, rEntry, eType == etQuery ? CommandType::QUERY : CommandType::TABLE))
+ xTransfer->CopyToClipboard(getView());
+ }
+
+ IMPL_LINK_NOARG( SbaTableQueryBrowser, OnAsyncDrop, void*, void )
+ {
+ m_nAsyncDrop = nullptr;
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( m_aAsyncDrop.nType == E_TABLE )
+ {
+ SharedConnection xDestConnection;
+ if ( ensureConnection(m_aAsyncDrop.xDroppedAt.get(), xDestConnection) && xDestConnection.is())
+ {
+ std::unique_ptr<weld::TreeIter> xDataSourceEntry =
+ m_pTreeView->GetRootLevelParent(m_aAsyncDrop.xDroppedAt.get());
+ m_aTableCopyHelper.asyncCopyTagTable(m_aAsyncDrop, getDataSourceAccessor(*xDataSourceEntry), xDestConnection);
+ }
+ }
+
+ m_aAsyncDrop.aDroppedData.clear();
+ }
+
+ void SbaTableQueryBrowser::clearTreeModel()
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ rTreeView.all_foreach([this, &rTreeView](weld::TreeIter& rEntryLoop){
+ // clear the user data of the tree model
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntryLoop));
+ if (pData)
+ {
+ rTreeView.set_id(rEntryLoop, OUString());
+ Reference<XContainer> xContainer(pData->xContainer, UNO_QUERY);
+ if (xContainer.is())
+ xContainer->removeContainerListener(this);
+
+ if (pData->xConnection.is())
+ {
+ // connections are to be stored *only* at the data source entries
+ impl_releaseConnection(pData->xConnection);
+ }
+
+ delete pData;
+ }
+ return false;
+ });
+
+ m_xCurrentlyDisplayed.reset();
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/exsrcbrw.cxx b/dbaccess/source/ui/browser/exsrcbrw.cxx
new file mode 100644
index 000000000..1dd47e73a
--- /dev/null
+++ b/dbaccess/source/ui/browser/exsrcbrw.cxx
@@ -0,0 +1,413 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <exsrcbrw.hxx>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <formadapter.hxx>
+#include <strings.hxx>
+#include <o3tl/any.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::frame;
+using namespace dbaui;
+
+// SbaExternalSourceBrowser
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OFormGridView_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new SbaExternalSourceBrowser(context));
+}
+
+Any SAL_CALL SbaExternalSourceBrowser::queryInterface(const Type& _rType)
+{
+ Any aRet = SbaXDataBrowserController::queryInterface(_rType);
+ if(!aRet.hasValue())
+ aRet = ::cppu::queryInterface(_rType,
+ static_cast<css::util::XModifyBroadcaster*>(this),
+ static_cast<css::form::XLoadListener*>(this));
+
+ return aRet;
+}
+
+SbaExternalSourceBrowser::SbaExternalSourceBrowser(const Reference< css::uno::XComponentContext >& _rM)
+ :SbaXDataBrowserController(_rM)
+ ,m_aModifyListeners(getMutex())
+ ,m_bInQueryDispatch( false )
+{
+
+}
+
+SbaExternalSourceBrowser::~SbaExternalSourceBrowser()
+{
+}
+
+css::uno::Sequence<OUString> SAL_CALL SbaExternalSourceBrowser::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.FormGridView" };
+}
+
+OUString SAL_CALL SbaExternalSourceBrowser::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.OFormGridView";
+}
+
+Reference< XRowSet > SbaExternalSourceBrowser::CreateForm()
+{
+ m_pDataSourceImpl = new SbaXFormAdapter();
+ return m_pDataSourceImpl;
+}
+
+bool SbaExternalSourceBrowser::InitializeForm(const Reference< XPropertySet > & /*i_formProperties*/)
+{
+ return true;
+}
+
+bool SbaExternalSourceBrowser::LoadForm()
+{
+ // as we don't have a main form (yet), we have nothing to do
+ // we don't call FormLoaded, because this expects a working data source
+ return true;
+}
+
+void SbaExternalSourceBrowser::modified(const css::lang::EventObject& aEvent)
+{
+ SbaXDataBrowserController::modified(aEvent);
+
+ // multiplex this event to all my listeners
+ css::lang::EventObject aEvt(*this);
+ m_aModifyListeners.notifyEach( &css::util::XModifyListener::modified, aEvt );
+}
+
+void SAL_CALL SbaExternalSourceBrowser::dispatch(const css::util::URL& aURL, const Sequence< css::beans::PropertyValue>& aArgs)
+{
+ if ( aURL.Complete == ".uno:FormSlots/AddGridColumn" )
+ {
+ // search the argument describing the column to create
+ OUString sControlType;
+ sal_Int32 nControlPos = -1;
+ Sequence< css::beans::PropertyValue> aControlProps;
+ for ( const css::beans::PropertyValue& rArgument : aArgs )
+ {
+ if ( rArgument.Name == "ColumnType" )
+ {
+ auto s = o3tl::tryAccess<OUString>(rArgument.Value);
+ OSL_ENSURE(s, "invalid type for argument \"ColumnType\" !");
+ if (s)
+ sControlType = *s;
+ }
+ else if ( rArgument.Name == "ColumnPosition" )
+ {
+ auto n = o3tl::tryAccess<sal_Int16>(rArgument.Value);
+ OSL_ENSURE(n, "invalid type for argument \"ColumnPosition\" !");
+ if (n)
+ nControlPos = *n;
+ }
+ else if ( rArgument.Name == "ColumnProperties" )
+ {
+ auto s = o3tl::tryAccess<Sequence<css::beans::PropertyValue>>(
+ rArgument.Value);
+ OSL_ENSURE(s, "invalid type for argument \"ColumnProperties\" !");
+ if (s)
+ aControlProps = *s;
+ }
+ else
+ SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch(AddGridColumn) : unknown argument (" << rArgument.Name << ") !");
+ }
+ if (sControlType.isEmpty())
+ {
+ SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch(AddGridColumn) : missing argument (ColumnType) !");
+ sControlType = "TextField";
+ }
+ OSL_ENSURE(aControlProps.hasElements(), "SbaExternalSourceBrowser::dispatch(AddGridColumn) : missing argument (ColumnProperties) !");
+
+ // create the col
+ Reference< css::form::XGridColumnFactory > xColFactory(getControlModel(), UNO_QUERY);
+ Reference< css::beans::XPropertySet > xNewCol = xColFactory->createColumn(sControlType);
+ Reference< XPropertySetInfo > xNewColProperties;
+ if (xNewCol.is())
+ xNewColProperties = xNewCol->getPropertySetInfo();
+ // set its properties
+ if (xNewColProperties.is())
+ {
+ for (const css::beans::PropertyValue& rControlProp : std::as_const(aControlProps))
+ {
+ try
+ {
+ if (xNewColProperties->hasPropertyByName(rControlProp.Name))
+ xNewCol->setPropertyValue(rControlProp.Name, rControlProp.Value);
+ }
+ catch (const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch : could not set a column property (" << rControlProp.Name << ")!");
+ }
+ }
+ }
+
+ // correct the position
+ Reference< css::container::XIndexContainer > xColContainer(getControlModel(), UNO_QUERY);
+
+ if (nControlPos > xColContainer->getCount())
+ nControlPos = xColContainer->getCount();
+ if (nControlPos < 0)
+ nControlPos = 0;
+
+ // append the column
+ xColContainer->insertByIndex(nControlPos, Any(xNewCol));
+ }
+ else if ( aURL.Complete == ".uno:FormSlots/ClearView" )
+ {
+ ClearView();
+ }
+ else if ( aURL.Complete == ".uno:FormSlots/AttachToForm" )
+ {
+ if (!m_pDataSourceImpl)
+ return;
+
+ Reference< XRowSet > xMasterForm;
+ // search the arguments for the master form
+ for (const css::beans::PropertyValue& rArgument : aArgs)
+ {
+ if ( (rArgument.Name == "MasterForm") && (rArgument.Value.getValueTypeClass() == TypeClass_INTERFACE) )
+ {
+ xMasterForm.set(rArgument.Value, UNO_QUERY);
+ break;
+ }
+ }
+ if (!xMasterForm.is())
+ {
+ SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::dispatch(FormSlots/AttachToForm) : please specify a form to attach to as argument !");
+ return;
+ }
+
+ Attach(xMasterForm);
+ }
+ else
+ SbaXDataBrowserController::dispatch(aURL, aArgs);
+}
+
+Reference< css::frame::XDispatch > SAL_CALL SbaExternalSourceBrowser::queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags)
+{
+ Reference< css::frame::XDispatch > xReturn;
+ if (m_bInQueryDispatch)
+ return xReturn;
+
+ m_bInQueryDispatch = true;
+
+ if ( ( aURL.Complete == ".uno:FormSlots/AttachToForm" )
+ // attach a new external form
+ || ( aURL.Complete == ".uno:FormSlots/AddGridColumn" )
+ // add a column to the grid
+ || ( aURL.Complete == ".uno:FormSlots/ClearView" )
+ // clear the grid
+ )
+ xReturn = static_cast<css::frame::XDispatch*>(this);
+
+ if ( !xReturn.is()
+ && ( (aURL.Complete == ".uno:FormSlots/moveToFirst" ) || (aURL.Complete == ".uno:FormSlots/moveToPrev" )
+ || (aURL.Complete == ".uno:FormSlots/moveToNext" ) || (aURL.Complete == ".uno:FormSlots/moveToLast" )
+ || (aURL.Complete == ".uno:FormSlots/moveToNew" ) || (aURL.Complete == ".uno:FormSlots/undoRecord" )
+ )
+ )
+ {
+ OSL_ENSURE(aURL.Mark.isEmpty(), "SbaExternalSourceBrowser::queryDispatch : the css::util::URL shouldn't have a mark !");
+ css::util::URL aNewUrl = aURL;
+
+ // split the css::util::URL
+ OSL_ENSURE( m_xUrlTransformer.is(), "SbaExternalSourceBrowser::queryDispatch : could not create a URLTransformer !" );
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aNewUrl );
+
+ // set a new mark
+ aNewUrl.Mark = "DB/FormGridView";
+ // this controller is instantiated when somebody dispatches the ".component:DB/FormGridView" in any
+ // frame, so we use "FormGridView" as mark that a dispatch request came from this view
+
+ if (m_xUrlTransformer.is())
+ m_xUrlTransformer->assemble(aNewUrl);
+
+ Reference< XDispatchProvider > xFrameDispatcher( getFrame(), UNO_QUERY );
+ if (xFrameDispatcher.is())
+ xReturn = xFrameDispatcher->queryDispatch(aNewUrl, aTargetFrameName, FrameSearchFlag::PARENT);
+
+ }
+
+ if (!xReturn.is())
+ xReturn = SbaXDataBrowserController::queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+
+ m_bInQueryDispatch = false;
+ return xReturn;
+}
+
+void SAL_CALL SbaExternalSourceBrowser::disposing()
+{
+ // say our modify listeners goodbye
+ css::lang::EventObject aEvt;
+ aEvt.Source = static_cast<XWeak*>(this);
+ m_aModifyListeners.disposeAndClear(aEvt);
+
+ stopListening();
+
+ SbaXDataBrowserController::disposing();
+}
+
+void SAL_CALL SbaExternalSourceBrowser::addModifyListener(const Reference< css::util::XModifyListener > & aListener)
+{
+ m_aModifyListeners.addInterface(aListener);
+}
+
+void SAL_CALL SbaExternalSourceBrowser::removeModifyListener(const Reference< css::util::XModifyListener > & aListener)
+{
+ m_aModifyListeners.removeInterface(aListener);
+}
+
+void SAL_CALL SbaExternalSourceBrowser::unloading(const css::lang::EventObject& aEvent)
+{
+ if (m_pDataSourceImpl && (m_pDataSourceImpl->getAttachedForm() == aEvent.Source))
+ {
+ ClearView();
+ }
+
+ SbaXDataBrowserController::unloading(aEvent);
+}
+
+void SbaExternalSourceBrowser::Attach(const Reference< XRowSet > & xMaster)
+{
+ Any aOldPos;
+ bool bWasInsertRow = false;
+ bool bBeforeFirst = true;
+ bool bAfterLast = true;
+ Reference< XRowLocate > xCursor(xMaster, UNO_QUERY);
+ Reference< XPropertySet > xMasterProps(xMaster, UNO_QUERY);
+
+ try
+ {
+ // switch the control to design mode
+ if (getBrowserView() && getBrowserView()->getGridControl().is())
+ getBrowserView()->getGridControl()->setDesignMode(true);
+
+ // the grid will move the form's cursor to the first record, but we want the form to remain unchanged
+ // restore the old position
+ if (xCursor.is() && xMaster.is())
+ {
+ bBeforeFirst = xMaster->isBeforeFirst();
+ bAfterLast = xMaster->isAfterLast();
+ if(!bBeforeFirst && !bAfterLast)
+ aOldPos = xCursor->getBookmark();
+ }
+
+ if (xMasterProps.is())
+ xMasterProps->getPropertyValue(PROPERTY_ISNEW) >>= bWasInsertRow;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ onStartLoading( Reference< XLoadable >( xMaster, UNO_QUERY ) );
+
+ stopListening();
+ m_pDataSourceImpl->AttachForm(xMaster);
+ startListening();
+
+ if (!xMaster.is())
+ return;
+
+ // at this point we have to reset the formatter for the new form
+ initFormatter();
+ // assume that the master form is already loaded
+#if OSL_DEBUG_LEVEL > 0
+ {
+ Reference< XLoadable > xLoadable( xMaster, UNO_QUERY );
+ OSL_ENSURE( xLoadable.is() && xLoadable->isLoaded(), "SbaExternalSourceBrowser::Attach: master is not loaded!" );
+ }
+#endif
+
+ LoadFinished(true);
+
+ Reference< XResultSetUpdate > xUpdate(xMaster, UNO_QUERY);
+ try
+ {
+ if (bWasInsertRow && xUpdate.is())
+ xUpdate->moveToInsertRow();
+ else if (xCursor.is() && aOldPos.hasValue())
+ xCursor->moveToBookmark(aOldPos);
+ else if(bBeforeFirst && xMaster.is())
+ xMaster->beforeFirst();
+ else if(bAfterLast && xMaster.is())
+ xMaster->afterLast();
+ }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaExternalSourceBrowser::Attach : couldn't restore the cursor position !");
+ }
+}
+
+void SbaExternalSourceBrowser::ClearView()
+{
+ // set a new (empty) datasource
+ Attach(Reference< XRowSet > ());
+
+ // clear all cols in the grid
+ Reference< css::container::XIndexContainer > xColContainer(getControlModel(), UNO_QUERY);
+ while (xColContainer->getCount() > 0)
+ xColContainer->removeByIndex(0);
+}
+
+void SAL_CALL SbaExternalSourceBrowser::disposing(const css::lang::EventObject& Source)
+{
+ if (m_pDataSourceImpl && (m_pDataSourceImpl->getAttachedForm() == Source.Source))
+ {
+ ClearView();
+ }
+
+ SbaXDataBrowserController::disposing(Source);
+}
+
+void SbaExternalSourceBrowser::startListening()
+{
+ if (m_pDataSourceImpl && m_pDataSourceImpl->getAttachedForm().is())
+ {
+ Reference< css::form::XLoadable > xLoadable(m_pDataSourceImpl->getAttachedForm(), UNO_QUERY);
+ xLoadable->addLoadListener(static_cast<css::form::XLoadListener*>(this));
+ }
+}
+
+void SbaExternalSourceBrowser::stopListening()
+{
+ if (m_pDataSourceImpl && m_pDataSourceImpl->getAttachedForm().is())
+ {
+ Reference< css::form::XLoadable > xLoadable(m_pDataSourceImpl->getAttachedForm(), UNO_QUERY);
+ xLoadable->removeLoadListener(static_cast<css::form::XLoadListener*>(this));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/formadapter.cxx b/dbaccess/source/ui/browser/formadapter.cxx
new file mode 100644
index 000000000..9f439acd2
--- /dev/null
+++ b/dbaccess/source/ui/browser/formadapter.cxx
@@ -0,0 +1,1877 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <formadapter.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/types.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <strings.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/sequence.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+// SbaXFormAdapter
+
+SbaXFormAdapter::SbaXFormAdapter()
+ :m_aLoadListeners(*this, m_aMutex)
+ ,m_aRowSetListeners(*this, m_aMutex)
+ ,m_aRowSetApproveListeners(*this, m_aMutex)
+ ,m_aErrorListeners(*this, m_aMutex)
+ ,m_aParameterListeners(*this, m_aMutex)
+ ,m_aSubmitListeners(*this, m_aMutex)
+ ,m_aResetListeners(*this, m_aMutex)
+ ,m_aPropertyChangeListeners(*this, m_aMutex)
+ ,m_aVetoablePropertyChangeListeners(*this, m_aMutex)
+ ,m_aPropertiesChangeListeners(*this, m_aMutex)
+ ,m_aDisposeListeners(m_aMutex)
+ ,m_aContainerListeners(m_aMutex)
+ ,m_nNamePropHandle(-1)
+{
+
+}
+
+SbaXFormAdapter::~SbaXFormAdapter()
+{
+
+}
+
+Sequence< Type > SAL_CALL SbaXFormAdapter::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ SbaXFormAdapter_BASE1::getTypes(),
+ SbaXFormAdapter_BASE2::getTypes(),
+ SbaXFormAdapter_BASE3::getTypes()
+ );
+}
+
+Sequence< sal_Int8 > SAL_CALL SbaXFormAdapter::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any SAL_CALL SbaXFormAdapter::queryInterface(const Type& _rType)
+{
+ Any aReturn = SbaXFormAdapter_BASE1::queryInterface( _rType );
+
+ if (!aReturn.hasValue())
+ aReturn = SbaXFormAdapter_BASE2::queryInterface( _rType );
+
+ if (!aReturn.hasValue())
+ aReturn = SbaXFormAdapter_BASE3::queryInterface( _rType );
+
+ return aReturn;
+}
+
+void SbaXFormAdapter::StopListening()
+{
+ // log off all our multiplexers
+ if (m_aLoadListeners.getLength())
+ {
+ css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeLoadListener(&m_aLoadListeners);
+ }
+ if (m_aRowSetListeners.getLength())
+ {
+ css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeRowSetListener(&m_aRowSetListeners);
+ }
+ if (m_aRowSetApproveListeners.getLength())
+ {
+ css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeRowSetApproveListener(&m_aRowSetApproveListeners);
+ }
+ if (m_aErrorListeners.getLength())
+ {
+ css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeSQLErrorListener(&m_aErrorListeners);
+ }
+ if (m_aSubmitListeners.getLength())
+ {
+ css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeSubmitListener(&m_aSubmitListeners);
+ }
+ if (m_aResetListeners.getLength())
+ {
+ css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeResetListener(&m_aResetListeners);
+ }
+ if (m_aParameterListeners.getLength())
+ {
+ Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeParameterListener(&m_aParameterListeners);
+ }
+
+ if (m_aPropertyChangeListeners.getOverallLen())
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removePropertyChangeListener(OUString(), &m_aPropertyChangeListeners);
+ }
+
+ if (m_aVetoablePropertyChangeListeners.getOverallLen())
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners);
+ }
+
+ if (m_aPropertiesChangeListeners.getLength())
+ {
+ Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removePropertiesChangeListener(&m_aPropertiesChangeListeners);
+ }
+
+ // log off ourself
+ Reference< css::lang::XComponent > xComp(m_xMainForm, UNO_QUERY);
+ if (xComp.is())
+ xComp->removeEventListener(static_cast<css::lang::XEventListener*>(static_cast<css::beans::XPropertyChangeListener*>(this)));
+}
+
+void SbaXFormAdapter::StartListening()
+{
+ // log off all our multiplexers
+ if (m_aLoadListeners.getLength())
+ {
+ css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addLoadListener(&m_aLoadListeners);
+ }
+ if (m_aRowSetListeners.getLength())
+ {
+ css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addRowSetListener(&m_aRowSetListeners);
+ }
+ if (m_aRowSetApproveListeners.getLength())
+ {
+ css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addRowSetApproveListener(&m_aRowSetApproveListeners);
+ }
+ if (m_aErrorListeners.getLength())
+ {
+ css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addSQLErrorListener(&m_aErrorListeners);
+ }
+ if (m_aSubmitListeners.getLength())
+ {
+ css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addSubmitListener(&m_aSubmitListeners);
+ }
+ if (m_aResetListeners.getLength())
+ {
+ css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addResetListener(&m_aResetListeners);
+ }
+
+ if (m_aParameterListeners.getLength())
+ {
+ Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addParameterListener(&m_aParameterListeners);
+ }
+
+ if (m_aPropertyChangeListeners.getOverallLen())
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addPropertyChangeListener(OUString(), &m_aPropertyChangeListeners);
+ }
+
+ if (m_aVetoablePropertyChangeListeners.getOverallLen())
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners);
+ }
+
+ if (m_aPropertiesChangeListeners.getLength())
+ {
+ Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addPropertiesChangeListener(css::uno::Sequence<OUString>{""}, &m_aPropertiesChangeListeners);
+ }
+
+ // log off ourself
+ Reference< css::lang::XComponent > xComp(m_xMainForm, UNO_QUERY);
+ if (xComp.is())
+ xComp->addEventListener(static_cast<css::lang::XEventListener*>(static_cast<css::beans::XPropertyChangeListener*>(this)));
+}
+
+void SbaXFormAdapter::AttachForm(const Reference< css::sdbc::XRowSet >& xNewMaster)
+{
+ if (xNewMaster == m_xMainForm)
+ return;
+
+ OSL_ENSURE(xNewMaster.get() != static_cast< css::sdbc::XRowSet* >(this), "SbaXFormAdapter::AttachForm : invalid argument !");
+
+ if (m_xMainForm.is())
+ {
+ StopListening();
+
+ // if our old master is loaded we have to send an 'unloaded' event
+ Reference< css::form::XLoadable > xLoadable(m_xMainForm, UNO_QUERY);
+ if (xLoadable->isLoaded())
+ {
+ css::lang::EventObject aEvt(*this);
+ m_aLoadListeners.notifyEach( &css::form::XLoadListener::unloaded, aEvt );
+ }
+ }
+
+ m_xMainForm = xNewMaster;
+
+ if (!m_xMainForm.is())
+ return;
+
+ StartListening();
+
+ // if our new master is loaded we have to send an 'loaded' event
+ Reference< css::form::XLoadable > xLoadable(m_xMainForm, UNO_QUERY);
+ if (xLoadable->isLoaded())
+ {
+ css::lang::EventObject aEvt(*this);
+ m_aLoadListeners.notifyEach( &css::form::XLoadListener::loaded, aEvt );
+ }
+
+ // TODO : perhaps _all_ of our listeners should be notified about our new state
+ // (nearly every aspect of us may have changed with new master form)
+}
+
+// css::sdbc::XCloseable
+void SAL_CALL SbaXFormAdapter::close()
+{
+ Reference< css::sdbc::XCloseable > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->close();
+}
+
+// css::sdbc::XResultSetMetaDataSupplier
+Reference< css::sdbc::XResultSetMetaData > SAL_CALL SbaXFormAdapter::getMetaData()
+{
+ Reference< css::sdbc::XResultSetMetaDataSupplier > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getMetaData();
+ return Reference< css::sdbc::XResultSetMetaData > ();
+}
+
+// css::sdbc::XColumnLocate
+sal_Int32 SAL_CALL SbaXFormAdapter::findColumn(const OUString& columnName)
+{
+ Reference< css::sdbc::XColumnLocate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->findColumn(columnName);
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+// css::sdbcx::XColumnsSupplier
+Reference< css::container::XNameAccess > SAL_CALL SbaXFormAdapter::getColumns()
+{
+ Reference< css::sdbcx::XColumnsSupplier > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getColumns();
+ return Reference< css::container::XNameAccess > ();
+}
+
+// css::sdbc::XRow
+sal_Bool SAL_CALL SbaXFormAdapter::wasNull()
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->wasNull();
+ return true;
+}
+
+OUString SAL_CALL SbaXFormAdapter::getString(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getString(columnIndex);
+ return OUString();
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::getBoolean(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getBoolean(columnIndex);
+ return false;
+}
+
+sal_Int8 SAL_CALL SbaXFormAdapter::getByte(sal_Int32 columnIndex)
+
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getByte(columnIndex);
+ return 0;
+}
+
+sal_Int16 SAL_CALL SbaXFormAdapter::getShort(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getShort(columnIndex);
+ return 0;
+}
+
+sal_Int32 SAL_CALL SbaXFormAdapter::getInt(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getInt(columnIndex);
+ return 0;
+}
+
+sal_Int64 SAL_CALL SbaXFormAdapter::getLong(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getLong(columnIndex);
+ return 0;
+}
+
+float SAL_CALL SbaXFormAdapter::getFloat(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getFloat(columnIndex);
+ return 0.0;
+}
+
+double SAL_CALL SbaXFormAdapter::getDouble(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getDouble(columnIndex);
+ return 0.0;
+}
+
+Sequence< sal_Int8 > SAL_CALL SbaXFormAdapter::getBytes(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getBytes(columnIndex);
+ return Sequence <sal_Int8> ();
+}
+
+css::util::Date SAL_CALL SbaXFormAdapter::getDate(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getDate(columnIndex);
+ return css::util::Date();
+}
+
+css::util::Time SAL_CALL SbaXFormAdapter::getTime(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getTime(columnIndex);
+ return css::util::Time();
+}
+
+css::util::DateTime SAL_CALL SbaXFormAdapter::getTimestamp(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getTimestamp(columnIndex);
+ return css::util::DateTime();
+}
+
+Reference< css::io::XInputStream > SAL_CALL SbaXFormAdapter::getBinaryStream(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getBinaryStream(columnIndex);
+ return Reference< css::io::XInputStream > ();
+}
+
+Reference< css::io::XInputStream > SAL_CALL SbaXFormAdapter::getCharacterStream(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getCharacterStream(columnIndex);
+ return Reference< css::io::XInputStream > ();
+}
+
+Any SAL_CALL SbaXFormAdapter::getObject(sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getObject(columnIndex, typeMap);
+ return Any();
+}
+
+Reference< css::sdbc::XRef > SAL_CALL SbaXFormAdapter::getRef(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getRef(columnIndex);
+ return Reference< css::sdbc::XRef > ();
+}
+
+Reference< css::sdbc::XBlob > SAL_CALL SbaXFormAdapter::getBlob(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getBlob(columnIndex);
+ return Reference< css::sdbc::XBlob > ();
+}
+
+Reference< css::sdbc::XClob > SAL_CALL SbaXFormAdapter::getClob(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getClob(columnIndex);
+ return Reference< css::sdbc::XClob > ();
+}
+
+Reference< css::sdbc::XArray > SAL_CALL SbaXFormAdapter::getArray(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRow > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getArray(columnIndex);
+ return Reference< css::sdbc::XArray > ();
+}
+
+// css::sdbcx::XRowLocate
+Any SAL_CALL SbaXFormAdapter::getBookmark()
+{
+ Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getBookmark();
+ return Any();
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::moveToBookmark(const Any& bookmark)
+{
+ Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->moveToBookmark(bookmark);
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows)
+{
+ Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->moveRelativeToBookmark(bookmark,rows);
+ return false;
+}
+
+sal_Int32 SAL_CALL SbaXFormAdapter::compareBookmarks(const Any& _first, const Any& _second)
+{
+ Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->compareBookmarks(_first, _second);
+ return 0;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::hasOrderedBookmarks()
+{
+ Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->hasOrderedBookmarks();
+ return false;
+}
+
+sal_Int32 SAL_CALL SbaXFormAdapter::hashBookmark(const Any& bookmark)
+{
+ Reference< css::sdbcx::XRowLocate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->hashBookmark(bookmark);
+ return 0;
+}
+
+// css::sdbc::XRowUpdate
+void SAL_CALL SbaXFormAdapter::updateNull(sal_Int32 columnIndex)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateNull(columnIndex);
+}
+
+void SAL_CALL SbaXFormAdapter::updateBoolean(sal_Int32 columnIndex, sal_Bool x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateBoolean(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateByte(sal_Int32 columnIndex, sal_Int8 x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateByte(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateShort(sal_Int32 columnIndex, sal_Int16 x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateShort(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateInt(sal_Int32 columnIndex, sal_Int32 x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateInt(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateLong(sal_Int32 columnIndex, sal_Int64 x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateLong(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateFloat(sal_Int32 columnIndex, float x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateFloat(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateDouble(sal_Int32 columnIndex, double x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateDouble(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateString(sal_Int32 columnIndex, const OUString& x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateString(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateBytes(sal_Int32 columnIndex, const Sequence< sal_Int8 >& x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateBytes(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateDate(sal_Int32 columnIndex, const css::util::Date& x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateDate(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateTime(sal_Int32 columnIndex, const css::util::Time& x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateTime(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime& x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateTimestamp(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateBinaryStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateBinaryStream(columnIndex, x, length);
+}
+
+void SAL_CALL SbaXFormAdapter::updateCharacterStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateCharacterStream(columnIndex, x, length);
+}
+
+void SAL_CALL SbaXFormAdapter::updateObject(sal_Int32 columnIndex, const Any& x)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateObject(columnIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::updateNumericObject(sal_Int32 columnIndex, const Any& x, sal_Int32 scale)
+{
+ Reference< css::sdbc::XRowUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateNumericObject(columnIndex, x, scale);
+}
+
+// css::sdbc::XResultSet
+sal_Bool SAL_CALL SbaXFormAdapter::next()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->next();
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::isBeforeFirst()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->isBeforeFirst();
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::isAfterLast()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->isAfterLast();
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::isFirst()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->isFirst();
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::isLast()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->isLast();
+ return false;
+}
+
+void SAL_CALL SbaXFormAdapter::beforeFirst()
+{
+ if (m_xMainForm.is())
+ m_xMainForm->beforeFirst();
+}
+
+void SAL_CALL SbaXFormAdapter::afterLast()
+{
+ if (m_xMainForm.is())
+ m_xMainForm->afterLast();
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::first()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->first();
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::last()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->last();
+ return false;
+}
+
+sal_Int32 SAL_CALL SbaXFormAdapter::getRow()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->getRow();
+ return 0;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::absolute(sal_Int32 row)
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->absolute(row);
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::relative(sal_Int32 rows)
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->relative(rows);
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::previous()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->previous();
+ return false;
+}
+
+void SAL_CALL SbaXFormAdapter::refreshRow()
+{
+ if (m_xMainForm.is())
+ m_xMainForm->refreshRow();
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::rowUpdated()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->rowUpdated();
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::rowInserted()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->rowInserted();
+ return false;
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::rowDeleted()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->rowDeleted();
+ return false;
+}
+
+Reference< XInterface > SAL_CALL SbaXFormAdapter::getStatement()
+{
+ if (m_xMainForm.is())
+ return m_xMainForm->getStatement();
+ return nullptr;
+}
+
+// css::sdbc::XResultSetUpdate
+void SAL_CALL SbaXFormAdapter::insertRow()
+{
+ Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->insertRow();
+}
+
+void SAL_CALL SbaXFormAdapter::updateRow()
+{
+ Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->updateRow();
+}
+
+void SAL_CALL SbaXFormAdapter::deleteRow()
+{
+ Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->deleteRow();
+}
+
+void SAL_CALL SbaXFormAdapter::cancelRowUpdates()
+{
+ Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->cancelRowUpdates();
+}
+
+void SAL_CALL SbaXFormAdapter::moveToInsertRow()
+{
+ Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->moveToInsertRow();
+}
+
+void SAL_CALL SbaXFormAdapter::moveToCurrentRow()
+{
+ Reference< css::sdbc::XResultSetUpdate > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->moveToCurrentRow();
+}
+
+// css::sdbc::XRowSet
+void SAL_CALL SbaXFormAdapter::execute()
+{
+ if (m_xMainForm.is())
+ m_xMainForm->execute();
+}
+
+void SAL_CALL SbaXFormAdapter::addRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& l)
+{
+ m_aRowSetListeners.addInterface(l);
+ if (m_aRowSetListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addRowSetListener(&m_aRowSetListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removeRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& l)
+{
+ if (m_aRowSetListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::sdbc::XRowSet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeRowSetListener(&m_aRowSetListeners);
+ }
+ m_aRowSetListeners.removeInterface(l);
+}
+
+// css::sdbcx::XDeleteRows
+Sequence<sal_Int32> SAL_CALL SbaXFormAdapter::deleteRows(const Sequence< Any >& rows)
+{
+ Reference< css::sdbcx::XDeleteRows > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->deleteRows(rows);
+ return Sequence<sal_Int32>();
+}
+
+// css::sdbc::XWarningsSupplier
+Any SAL_CALL SbaXFormAdapter::getWarnings()
+{
+ Reference< css::sdbc::XWarningsSupplier > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->getWarnings();
+ return Any();
+}
+
+void SAL_CALL SbaXFormAdapter::clearWarnings()
+{
+ Reference< css::sdbc::XWarningsSupplier > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->clearWarnings();
+}
+
+// css::sdb::XRowSetApproveBroadcaster
+void SAL_CALL SbaXFormAdapter::addRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& l)
+{
+ m_aRowSetApproveListeners.addInterface(l);
+ if (m_aRowSetApproveListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addRowSetApproveListener(&m_aRowSetApproveListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removeRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& l)
+{
+ if (m_aRowSetApproveListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::sdb::XRowSetApproveBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeRowSetApproveListener(&m_aRowSetApproveListeners);
+ }
+ m_aRowSetApproveListeners.removeInterface(l);
+}
+
+// css::sdbc::XSQLErrorBroadcaster
+void SAL_CALL SbaXFormAdapter::addSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& l)
+{
+ m_aErrorListeners.addInterface(l);
+ if (m_aErrorListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addSQLErrorListener(&m_aErrorListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removeSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& l)
+{
+ if (m_aErrorListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::sdb::XSQLErrorBroadcaster > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeSQLErrorListener(&m_aErrorListeners);
+ }
+ m_aErrorListeners.removeInterface(l);
+}
+
+// css::sdb::XResultSetAccess
+Reference< css::sdbc::XResultSet > SAL_CALL SbaXFormAdapter::createResultSet()
+{
+ Reference< css::sdb::XResultSetAccess > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->createResultSet();
+ return Reference< css::sdbc::XResultSet > ();
+}
+
+// css::form::XLoadable
+void SAL_CALL SbaXFormAdapter::load()
+{
+ Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->load();
+}
+
+void SAL_CALL SbaXFormAdapter::unload()
+{
+ Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->unload();
+}
+
+void SAL_CALL SbaXFormAdapter::reload()
+{
+ Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->reload();
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::isLoaded()
+{
+ Reference< css::form::XLoadable > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ return xIface->isLoaded();
+ return false;
+}
+
+void SAL_CALL SbaXFormAdapter::addLoadListener(const css::uno::Reference< css::form::XLoadListener>& l)
+{
+ m_aLoadListeners.addInterface(l);
+ if (m_aLoadListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addLoadListener(&m_aLoadListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removeLoadListener(const css::uno::Reference< css::form::XLoadListener >& l)
+{
+ if (m_aLoadListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::form::XLoadable > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeLoadListener(&m_aLoadListeners);
+ }
+ m_aLoadListeners.removeInterface(l);
+}
+
+// css::sdbc::XParameters
+void SAL_CALL SbaXFormAdapter::setNull(sal_Int32 parameterIndex, sal_Int32 sqlType)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setNull(parameterIndex, sqlType);
+}
+
+void SAL_CALL SbaXFormAdapter::setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setObjectNull(parameterIndex, sqlType, typeName);
+}
+
+void SAL_CALL SbaXFormAdapter::setBoolean(sal_Int32 parameterIndex, sal_Bool x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setBoolean(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setByte(sal_Int32 parameterIndex, sal_Int8 x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setByte(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setShort(sal_Int32 parameterIndex, sal_Int16 x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setShort(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setInt(sal_Int32 parameterIndex, sal_Int32 x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setInt(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setLong(sal_Int32 parameterIndex, sal_Int64 x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setLong(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setFloat(sal_Int32 parameterIndex, float x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setFloat(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setDouble(sal_Int32 parameterIndex, double x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setDouble(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setString(sal_Int32 parameterIndex, const OUString& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setString(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setBytes(sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setBytes(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setDate(sal_Int32 parameterIndex, const css::util::Date& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setDate(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setTime(sal_Int32 parameterIndex, const css::util::Time& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setTime(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setTimestamp(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setBinaryStream(sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setBinaryStream(parameterIndex, x, length);
+}
+
+void SAL_CALL SbaXFormAdapter::setCharacterStream(sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setCharacterStream(parameterIndex, x, length);
+}
+
+void SAL_CALL SbaXFormAdapter::setObject(sal_Int32 parameterIndex, const Any& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setObject(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setObjectWithInfo(sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
+}
+
+void SAL_CALL SbaXFormAdapter::setRef(sal_Int32 parameterIndex, const Reference< css::sdbc::XRef >& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setRef(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setBlob(sal_Int32 parameterIndex, const Reference< css::sdbc::XBlob >& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setBlob(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setClob(sal_Int32 parameterIndex, const Reference< css::sdbc::XClob >& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setClob(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::setArray(sal_Int32 parameterIndex, const Reference< css::sdbc::XArray >& x)
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->setArray(parameterIndex, x);
+}
+
+void SAL_CALL SbaXFormAdapter::clearParameters()
+{
+ Reference< css::sdbc::XParameters > xIface(m_xMainForm, UNO_QUERY);
+ if (xIface.is())
+ xIface->clearParameters();
+}
+
+// css::form::XDatabaseParameterBroadcaster
+void SAL_CALL SbaXFormAdapter::addParameterListener(const Reference< css::form::XDatabaseParameterListener >& aListener)
+{
+ m_aParameterListeners.addInterface(aListener);
+ if (m_aParameterListeners.getLength() == 1)
+ {
+ Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addParameterListener(&m_aParameterListeners);
+ }
+}
+
+void SAL_CALL SbaXFormAdapter::removeParameterListener(const Reference< css::form::XDatabaseParameterListener >& aListener)
+{
+ if (m_aParameterListeners.getLength() == 1)
+ {
+ Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeParameterListener(&m_aParameterListeners);
+ }
+ m_aParameterListeners.removeInterface(aListener);
+}
+
+// css::container::XChild
+Reference< XInterface > SAL_CALL SbaXFormAdapter::getParent()
+{
+ return m_xParent;
+}
+
+void SAL_CALL SbaXFormAdapter::setParent(const Reference< XInterface >& Parent)
+{
+ m_xParent = Parent;
+}
+
+// css::form::XSubmit
+void SAL_CALL SbaXFormAdapter::submit(const Reference< css::awt::XControl >& aControl, const css::awt::MouseEvent& aMouseEvt)
+{
+ Reference< css::form::XSubmit > xSubmit(m_xMainForm, UNO_QUERY);
+ if (xSubmit.is())
+ xSubmit->submit(aControl, aMouseEvt);
+}
+
+void SAL_CALL SbaXFormAdapter::addSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& l)
+{
+ m_aSubmitListeners.addInterface(l);
+ if (m_aSubmitListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addSubmitListener(&m_aSubmitListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removeSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& l)
+{
+ if (m_aSubmitListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::form::XSubmit > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeSubmitListener(&m_aSubmitListeners);
+ }
+ m_aSubmitListeners.removeInterface(l);
+}
+
+// css::awt::XTabControllerModel
+sal_Bool SAL_CALL SbaXFormAdapter::getGroupControl()
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroupControl : not supported !");
+ return false;
+}
+
+void SAL_CALL SbaXFormAdapter::setGroupControl(sal_Bool /*GroupControl*/)
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::setGroupControl : not supported !");
+}
+
+void SAL_CALL SbaXFormAdapter::setControlModels(const Sequence< Reference< css::awt::XControlModel > >& /*Controls*/)
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::setControlModels : not supported !");
+}
+
+Sequence< Reference< css::awt::XControlModel > > SAL_CALL SbaXFormAdapter::getControlModels()
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::getControlModels : not supported !");
+ return Sequence< Reference< css::awt::XControlModel > >();
+}
+
+void SAL_CALL SbaXFormAdapter::setGroup(const Sequence< Reference< css::awt::XControlModel > >& /*_rGroup*/, const OUString& /*GroupName*/)
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::setGroup : not supported !");
+}
+
+sal_Int32 SAL_CALL SbaXFormAdapter::getGroupCount()
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroupCount : not supported !");
+ return 0;
+}
+
+void SAL_CALL SbaXFormAdapter::getGroup(sal_Int32 /*nGroup*/, Sequence< Reference< css::awt::XControlModel > >& /*_rGroup*/, OUString& /*Name*/)
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroup : not supported !");
+}
+
+void SAL_CALL SbaXFormAdapter::getGroupByName(const OUString& /*Name*/, Sequence< Reference< css::awt::XControlModel > >& /*_rGroup*/)
+{
+ OSL_FAIL("SAL_CALL SbaXFormAdapter::getGroupByName : not supported !");
+}
+
+// css::lang::XComponent
+void SAL_CALL SbaXFormAdapter::dispose()
+{
+ // log off all multiplexers
+ if (m_xMainForm.is())
+ StopListening();
+
+ css::lang::EventObject aEvt(*this);
+ m_aLoadListeners.disposeAndClear(aEvt);
+ m_aRowSetListeners.disposeAndClear(aEvt);
+ m_aRowSetApproveListeners.disposeAndClear(aEvt);
+ m_aErrorListeners.disposeAndClear(aEvt);
+ m_aParameterListeners.disposeAndClear(aEvt);
+ m_aSubmitListeners.disposeAndClear(aEvt);
+ m_aResetListeners.disposeAndClear(aEvt);
+
+ m_aVetoablePropertyChangeListeners.disposeAndClear();
+ m_aPropertyChangeListeners.disposeAndClear();
+ m_aPropertiesChangeListeners.disposeAndClear(aEvt);
+
+ m_aDisposeListeners.disposeAndClear(aEvt);
+ m_aContainerListeners.disposeAndClear(aEvt);
+
+ // dispose all children
+ for (auto const& child : m_aChildren)
+ {
+ Reference< css::beans::XPropertySet > xSet(child, UNO_QUERY);
+ if (xSet.is())
+ xSet->removePropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this));
+
+ Reference< css::container::XChild > xChild(child, UNO_QUERY);
+ if (xChild.is())
+ xChild->setParent(Reference< XInterface > ());
+
+ Reference< css::lang::XComponent > xComp(child, UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_aChildren.clear();
+}
+
+void SAL_CALL SbaXFormAdapter::addEventListener(const Reference< css::lang::XEventListener >& xListener)
+{
+ m_aDisposeListeners.addInterface(xListener);
+}
+
+void SAL_CALL SbaXFormAdapter::removeEventListener(const Reference< css::lang::XEventListener >& aListener)
+{
+ m_aDisposeListeners.removeInterface(aListener);
+}
+
+// css::beans::XFastPropertySet
+void SAL_CALL SbaXFormAdapter::setFastPropertyValue(sal_Int32 nHandle, const Any& aValue)
+{
+ Reference< css::beans::XFastPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ OSL_ENSURE(xSet.is(), "SAL_CALL SbaXFormAdapter::setFastPropertyValue : have no master form !");
+
+ if (m_nNamePropHandle == nHandle)
+ {
+ if (aValue.getValueType().getTypeClass() != TypeClass_STRING)
+ {
+ throw css::lang::IllegalArgumentException();
+ }
+
+ // for notifying property listeners
+ css::beans::PropertyChangeEvent aEvt;
+ aEvt.Source = *this;
+ aEvt.PropertyName = PROPERTY_NAME;
+ aEvt.PropertyHandle = m_nNamePropHandle;
+ aEvt.OldValue <<= m_sName;
+ aEvt.NewValue = aValue;
+
+ aValue >>= m_sName;
+
+ m_aPropertyChangeListeners.getContainer(PROPERTY_NAME)->notifyEach(
+ &XPropertyChangeListener::propertyChange, aEvt );
+
+ return;
+ }
+
+ xSet->setFastPropertyValue(nHandle, aValue);
+}
+
+Any SAL_CALL SbaXFormAdapter::getFastPropertyValue(sal_Int32 nHandle)
+{
+ Reference< css::beans::XFastPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ OSL_ENSURE(xSet.is(), "SAL_CALL SbaXFormAdapter::getFastPropertyValue : have no master form !");
+
+ if (m_nNamePropHandle == nHandle)
+ return Any(m_sName);
+
+ return xSet->getFastPropertyValue(nHandle);
+}
+
+// css::container::XNamed
+OUString SAL_CALL SbaXFormAdapter::getName()
+{
+ return ::comphelper::getString(getPropertyValue(PROPERTY_NAME));
+}
+
+void SAL_CALL SbaXFormAdapter::setName(const OUString& aName)
+{
+ setPropertyValue(PROPERTY_NAME, Any(aName));
+}
+
+// css::io::XPersistObject
+OUString SAL_CALL SbaXFormAdapter::getServiceName()
+{
+ Reference< css::io::XPersistObject > xPersist(m_xMainForm, UNO_QUERY);
+ if (xPersist.is())
+ return xPersist->getServiceName();
+ return OUString();
+}
+
+void SAL_CALL SbaXFormAdapter::write(const Reference< css::io::XObjectOutputStream >& _rxOutStream)
+{
+ Reference< css::io::XPersistObject > xPersist(m_xMainForm, UNO_QUERY);
+ if (xPersist.is())
+ xPersist->write(_rxOutStream);
+}
+
+void SAL_CALL SbaXFormAdapter::read(const Reference< css::io::XObjectInputStream >& _rxInStream)
+{
+ Reference< css::io::XPersistObject > xPersist(m_xMainForm, UNO_QUERY);
+ if (xPersist.is())
+ xPersist->read(_rxInStream);
+}
+
+// css::beans::XMultiPropertySet
+Reference< css::beans::XPropertySetInfo > SAL_CALL SbaXFormAdapter::getPropertySetInfo()
+{
+ Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ if (!xSet.is())
+ return Reference< css::beans::XPropertySetInfo > ();
+
+ Reference< css::beans::XPropertySetInfo > xReturn = xSet->getPropertySetInfo();
+ if (-1 == m_nNamePropHandle)
+ {
+ // we need to determine the handle for the NAME property
+ const Sequence<css::beans::Property> aProps = xReturn->getProperties();
+ for (const css::beans::Property& rProp : aProps)
+ {
+ if (rProp.Name == PROPERTY_NAME)
+ {
+ m_nNamePropHandle = rProp.Handle;
+ break;
+ }
+ }
+ }
+ return xReturn;
+}
+
+void SAL_CALL SbaXFormAdapter::setPropertyValues(const Sequence< OUString >& PropertyNames, const Sequence< Any >& Values)
+{
+ Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ if (xSet.is())
+ xSet->setPropertyValues(PropertyNames, Values);
+}
+
+Sequence< Any > SAL_CALL SbaXFormAdapter::getPropertyValues(const Sequence< OUString >& aPropertyNames)
+{
+ Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ if (!xSet.is())
+ return Sequence< Any>(aPropertyNames.getLength());
+
+ Sequence< Any> aReturn = xSet->getPropertyValues(aPropertyNames);
+ auto aReturnRange = asNonConstRange(aReturn);
+
+ // search for (and fake) the NAME property
+ OSL_ENSURE(aReturn.getLength() == aPropertyNames.getLength(), "SAL_CALL SbaXFormAdapter::getPropertyValues : the main form returned an invalid-length sequence !");
+ for (sal_Int32 i=0; i<aPropertyNames.getLength(); ++i)
+ if (aPropertyNames[i] == PROPERTY_NAME)
+ {
+ aReturnRange[i] <<= m_sName;
+ break;
+ }
+
+ return aReturn;
+}
+
+void SAL_CALL SbaXFormAdapter::addPropertiesChangeListener(const Sequence< OUString>& /*aPropertyNames*/, const Reference< css::beans::XPropertiesChangeListener >& xListener)
+{
+ // we completely ignore the property names, _all_ changes of _all_ properties will be forwarded to _all_ listeners
+ m_aPropertiesChangeListeners.addInterface(xListener);
+ if (m_aPropertiesChangeListeners.getLength() == 1)
+ {
+ Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addPropertiesChangeListener(Sequence< OUString>{""}, &m_aPropertiesChangeListeners);
+ }
+}
+
+void SAL_CALL SbaXFormAdapter::removePropertiesChangeListener(const Reference< css::beans::XPropertiesChangeListener >& Listener)
+{
+ if (m_aPropertiesChangeListeners.getLength() == 1)
+ {
+ Reference< css::beans::XMultiPropertySet > xBroadcaster(m_xMainForm, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removePropertiesChangeListener(&m_aPropertiesChangeListeners);
+ }
+ m_aPropertiesChangeListeners.removeInterface(Listener);
+}
+
+void SAL_CALL SbaXFormAdapter::firePropertiesChangeEvent(const Sequence< OUString >& aPropertyNames, const Reference< css::beans::XPropertiesChangeListener >& xListener)
+{
+ Reference< css::beans::XMultiPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ if (xSet.is())
+ xSet->firePropertiesChangeEvent(aPropertyNames, xListener);
+}
+
+// css::beans::XPropertySet
+void SAL_CALL SbaXFormAdapter::setPropertyValue(const OUString& aPropertyName, const Any& aValue)
+{
+ Reference< css::beans::XPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ if (!xSet.is())
+ return;
+
+ // special handling for the "name" property
+ if (aPropertyName == PROPERTY_NAME)
+ setFastPropertyValue(m_nNamePropHandle, aValue);
+
+ xSet->setPropertyValue(aPropertyName, aValue);
+}
+
+Any SAL_CALL SbaXFormAdapter::getPropertyValue(const OUString& PropertyName)
+{
+ Reference< css::beans::XPropertySet > xSet(m_xMainForm, UNO_QUERY);
+ if (!xSet.is())
+ return Any();
+
+ // special handling for the "name" property
+ if (PropertyName == PROPERTY_NAME)
+ return getFastPropertyValue(m_nNamePropHandle);
+
+ return xSet->getPropertyValue(PropertyName);
+}
+
+void SAL_CALL SbaXFormAdapter::addPropertyChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener>& l )
+{
+ m_aPropertyChangeListeners.addInterface(rName, l);
+ if (m_aPropertyChangeListeners.getOverallLen() == 1)
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addPropertyChangeListener(OUString(), &m_aPropertyChangeListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removePropertyChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener>& l )
+{
+ if (m_aPropertyChangeListeners.getOverallLen() == 1)
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removePropertyChangeListener(OUString(), &m_aPropertyChangeListeners);
+ }
+ m_aPropertyChangeListeners.removeInterface(rName, l);
+}
+
+void SAL_CALL SbaXFormAdapter::addVetoableChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener>& l )
+{
+ m_aVetoablePropertyChangeListeners.addInterface(rName, l);
+ if (m_aVetoablePropertyChangeListeners.getOverallLen() == 1)
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removeVetoableChangeListener(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener>& l )
+{
+ if (m_aVetoablePropertyChangeListeners.getOverallLen() == 1)
+ {
+ css::uno::Reference< css::beans::XPropertySet > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeVetoableChangeListener(OUString(), &m_aVetoablePropertyChangeListeners);
+ }
+ m_aVetoablePropertyChangeListeners.removeInterface(rName, l);
+}
+
+
+// css::util::XCancellable
+void SAL_CALL SbaXFormAdapter::cancel()
+{
+ Reference< css::util::XCancellable > xCancel(m_xMainForm, UNO_QUERY);
+ if (!xCancel.is())
+ return;
+ xCancel->cancel();
+}
+
+// css::beans::XPropertyState
+css::beans::PropertyState SAL_CALL SbaXFormAdapter::getPropertyState(const OUString& PropertyName)
+{
+ Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY);
+ if (xState.is())
+ return xState->getPropertyState(PropertyName);
+ return css::beans::PropertyState_DEFAULT_VALUE;
+}
+
+Sequence< css::beans::PropertyState> SAL_CALL SbaXFormAdapter::getPropertyStates(const Sequence< OUString >& aPropertyName)
+{
+ Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY);
+ if (xState.is())
+ return xState->getPropertyStates(aPropertyName);
+
+ // set them all to DEFAULT
+ Sequence< css::beans::PropertyState> aReturn(aPropertyName.getLength());
+ for (css::beans::PropertyState& rState : asNonConstRange(aReturn))
+ rState = css::beans::PropertyState_DEFAULT_VALUE;
+ return aReturn;
+}
+
+void SAL_CALL SbaXFormAdapter::setPropertyToDefault(const OUString& PropertyName)
+{
+ Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY);
+ if (xState.is())
+ xState->setPropertyToDefault(PropertyName);
+}
+
+Any SAL_CALL SbaXFormAdapter::getPropertyDefault(const OUString& aPropertyName)
+{
+ Reference< css::beans::XPropertyState > xState(m_xMainForm, UNO_QUERY);
+ if (xState.is())
+ return xState->getPropertyDefault(aPropertyName);
+ return Any();
+}
+
+// css::form::XReset
+void SAL_CALL SbaXFormAdapter::reset()
+{
+ Reference< css::form::XReset > xReset(m_xMainForm, UNO_QUERY);
+ if (xReset.is())
+ xReset->reset();
+}
+
+void SAL_CALL SbaXFormAdapter::addResetListener(const css::uno::Reference< css::form::XResetListener >& l)
+{
+ m_aResetListeners.addInterface(l);
+ if (m_aResetListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addResetListener(&m_aResetListeners);
+ }
+}
+void SAL_CALL SbaXFormAdapter::removeResetListener(const css::uno::Reference< css::form::XResetListener >& l)
+{
+ if (m_aResetListeners.getLength() == 1)
+ {
+ css::uno::Reference< css::form::XReset > xBroadcaster(m_xMainForm, css::uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeResetListener(&m_aResetListeners);
+ }
+ m_aResetListeners.removeInterface(l);
+}
+
+// css::container::XNameContainer
+void SbaXFormAdapter::implInsert(const Any& aElement, sal_Int32 nIndex, const OUString* pNewElName)
+{
+ // extract the form component
+ if (aElement.getValueType().getTypeClass() != TypeClass_INTERFACE)
+ {
+ throw css::lang::IllegalArgumentException();
+ }
+
+ Reference< css::form::XFormComponent > xElement(aElement, UNO_QUERY);
+ if (!xElement.is())
+ {
+ throw css::lang::IllegalArgumentException();
+ }
+
+ // for the name we need the propset
+ Reference< css::beans::XPropertySet > xElementSet(xElement, UNO_QUERY);
+ if (!xElementSet.is())
+ {
+ throw css::lang::IllegalArgumentException();
+ }
+ OUString sName;
+ try
+ {
+ if (pNewElName)
+ xElementSet->setPropertyValue(PROPERTY_NAME, Any(*pNewElName));
+
+ xElementSet->getPropertyValue(PROPERTY_NAME) >>= sName;
+ }
+ catch(Exception&)
+ {
+ // the set didn't support the name prop
+ throw css::lang::IllegalArgumentException();
+ }
+
+ // check the index
+ OSL_ASSERT(nIndex >= 0);
+ if (sal::static_int_cast< sal_uInt32 >(nIndex) > m_aChildren.size())
+ nIndex = m_aChildren.size();
+
+ OSL_ENSURE(m_aChildren.size() == m_aChildNames.size(), "SAL_CALL SbaXFormAdapter::implInsert : inconsistent container state !");
+ m_aChildren.insert(m_aChildren.begin() + nIndex, xElement);
+ m_aChildNames.insert(m_aChildNames.begin() + nIndex, sName);
+
+ // listen for a change of the name
+ xElementSet->addPropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this));
+
+ // we are now the parent of the new element
+ xElement->setParent(static_cast<css::container::XContainer*>(this));
+
+ // notify the container listeners
+ css::container::ContainerEvent aEvt;
+ aEvt.Source = *this;
+ aEvt.Accessor <<= nIndex;
+ aEvt.Element <<= xElement;
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvt );
+}
+
+sal_Int32 SbaXFormAdapter::implGetPos(const OUString& rName)
+{
+ std::vector< OUString>::const_iterator aIter = std::find( m_aChildNames.begin(),
+ m_aChildNames.end(),
+ rName);
+
+ if(aIter != m_aChildNames.end())
+ return aIter - m_aChildNames.begin();
+
+ return -1;
+}
+
+void SAL_CALL SbaXFormAdapter::insertByName(const OUString& aName, const Any& aElement)
+{
+ implInsert(aElement, m_aChildren.size(), &aName);
+}
+
+void SAL_CALL SbaXFormAdapter::removeByName(const OUString& Name)
+{
+ sal_Int32 nPos = implGetPos(Name);
+ if (-1 == nPos)
+ {
+ throw css::container::NoSuchElementException();
+ }
+ removeByIndex(nPos);
+}
+
+// css::container::XNameReplace
+void SAL_CALL SbaXFormAdapter::replaceByName(const OUString& aName, const Any& aElement)
+{
+ sal_Int32 nPos = implGetPos(aName);
+ if (-1 == nPos)
+ {
+ throw css::container::NoSuchElementException();
+ }
+ replaceByIndex(nPos, aElement);
+}
+
+// css::container::XNameAccess
+Any SAL_CALL SbaXFormAdapter::getByName(const OUString& aName)
+{
+ sal_Int32 nPos = implGetPos(aName);
+ if (-1 == nPos)
+ {
+ throw css::container::NoSuchElementException();
+ }
+ return Any(m_aChildren[nPos]);
+}
+
+Sequence< OUString > SAL_CALL SbaXFormAdapter::getElementNames()
+{
+ return Sequence< OUString >(m_aChildNames.data(), m_aChildNames.size());
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::hasByName(const OUString& aName)
+{
+ return (-1 != implGetPos(aName));
+}
+
+// css::container::XElementAccess
+Type SAL_CALL SbaXFormAdapter::getElementType()
+{
+ return cppu::UnoType<css::form::XFormComponent>::get();
+}
+
+sal_Bool SAL_CALL SbaXFormAdapter::hasElements()
+{
+ return !m_aChildren.empty();
+}
+
+// css::container::XIndexContainer
+void SAL_CALL SbaXFormAdapter::insertByIndex(sal_Int32 _rIndex, const Any& Element)
+{
+ if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) )
+ throw css::lang::IndexOutOfBoundsException();
+ implInsert(Element, _rIndex);
+}
+
+void SAL_CALL SbaXFormAdapter::removeByIndex(sal_Int32 _rIndex)
+{
+ if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) )
+ throw css::lang::IndexOutOfBoundsException();
+
+ Reference< css::form::XFormComponent > xAffected = *(m_aChildren.begin() + _rIndex);
+
+ OSL_ENSURE(m_aChildren.size() == m_aChildNames.size(), "SAL_CALL SbaXFormAdapter::removeByIndex : inconsistent container state !");
+ m_aChildren.erase(m_aChildren.begin() + _rIndex);
+ m_aChildNames.erase(m_aChildNames.begin() + _rIndex);
+
+ // no need to listen anymore
+ Reference< css::beans::XPropertySet > xAffectedSet(xAffected, UNO_QUERY);
+ xAffectedSet->removePropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this));
+
+ // we are no longer the parent
+ xAffected->setParent(Reference< XInterface > ());
+
+ // notify container listeners
+ css::container::ContainerEvent aEvt;
+ aEvt.Source = *this;
+ aEvt.Element <<= xAffected;
+ m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvt );
+}
+
+// css::container::XIndexReplace
+void SAL_CALL SbaXFormAdapter::replaceByIndex(sal_Int32 _rIndex, const Any& Element)
+{
+ if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) )
+ throw css::lang::IndexOutOfBoundsException();
+
+ // extract the form component
+ if (Element.getValueType().getTypeClass() != TypeClass_INTERFACE)
+ {
+ throw css::lang::IllegalArgumentException();
+ }
+
+ Reference< css::form::XFormComponent > xElement(Element, UNO_QUERY);
+ if (!xElement.is())
+ {
+ throw css::lang::IllegalArgumentException();
+ }
+
+ // for the name we need the propset
+ Reference< css::beans::XPropertySet > xElementSet(xElement, UNO_QUERY);
+ if (!xElementSet.is())
+ {
+ throw css::lang::IllegalArgumentException();
+ }
+ OUString sName;
+ try
+ {
+ xElementSet->getPropertyValue(PROPERTY_NAME) >>= sName;
+ }
+ catch(Exception&)
+ {
+ // the set didn't support the name prop
+ throw css::lang::IllegalArgumentException();
+ }
+
+ Reference< css::form::XFormComponent > xOld = *(m_aChildren.begin() + _rIndex);
+
+ OSL_ENSURE(m_aChildren.size() == m_aChildNames.size(), "SAL_CALL SbaXFormAdapter::replaceByIndex : inconsistent container state !");
+ *(m_aChildren.begin() + _rIndex) = xElement;
+ *(m_aChildNames.begin() + _rIndex) = sName;
+
+ // correct property change listening
+ Reference< css::beans::XPropertySet > xOldSet(xOld, UNO_QUERY);
+ xOldSet->removePropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this));
+ xElementSet->addPropertyChangeListener(PROPERTY_NAME, static_cast<css::beans::XPropertyChangeListener*>(this));
+
+ // parent reset
+ xOld->setParent(Reference< XInterface > ());
+ xElement->setParent(static_cast<css::container::XContainer*>(this));
+
+ // notify container listeners
+ css::container::ContainerEvent aEvt;
+ aEvt.Source = *this;
+ aEvt.Accessor <<= _rIndex;
+ aEvt.Element <<= xElement;
+ aEvt.ReplacedElement <<= xOld;
+
+ m_aContainerListeners.notifyEach( &XContainerListener::elementReplaced, aEvt );
+}
+
+// css::container::XIndexAccess
+sal_Int32 SAL_CALL SbaXFormAdapter::getCount()
+{
+ return m_aChildren.size();
+}
+
+Any SAL_CALL SbaXFormAdapter::getByIndex(sal_Int32 _rIndex)
+{
+ if ( ( _rIndex < 0 ) || ( o3tl::make_unsigned(_rIndex) >= m_aChildren.size() ) )
+ throw css::lang::IndexOutOfBoundsException();
+
+ Reference< css::form::XFormComponent > xElement = *(m_aChildren.begin() + _rIndex);
+ return Any(xElement);
+}
+
+// css::container::XContainer
+void SAL_CALL SbaXFormAdapter::addContainerListener(const Reference< css::container::XContainerListener >& xListener)
+{
+ m_aContainerListeners.addInterface(xListener);
+}
+
+void SAL_CALL SbaXFormAdapter::removeContainerListener(const Reference< css::container::XContainerListener >& xListener)
+{
+ m_aContainerListeners.removeInterface(xListener);
+}
+
+// css::container::XEnumerationAccess
+Reference< css::container::XEnumeration > SAL_CALL SbaXFormAdapter::createEnumeration()
+{
+ return new ::comphelper::OEnumerationByName(this);
+}
+
+// css::beans::XPropertyChangeListener
+void SAL_CALL SbaXFormAdapter::propertyChange(const css::beans::PropertyChangeEvent& evt)
+{
+ if (evt.PropertyName != PROPERTY_NAME)
+ return;
+
+ std::vector< css::uno::Reference< css::form::XFormComponent > >::const_iterator aIter = std::find_if( m_aChildren.begin(),
+ m_aChildren.end(),
+ [&evt](css::uno::Reference< css::uno::XInterface > const & x) { return x == evt.Source; });
+
+ if(aIter != m_aChildren.end())
+ {
+ sal_Int32 nPos = aIter - m_aChildren.begin();
+ OSL_ENSURE(*(m_aChildNames.begin() + nPos) == ::comphelper::getString(evt.OldValue), "SAL_CALL SbaXFormAdapter::propertyChange : object has a wrong name !");
+ *(m_aChildNames.begin() + nPos) = ::comphelper::getString(evt.NewValue);
+ }
+}
+
+// css::lang::XEventListener
+void SAL_CALL SbaXFormAdapter::disposing(const css::lang::EventObject& Source)
+{
+ // was it our main form ?
+ if (Source.Source == m_xMainForm)
+ dispose();
+
+ std::vector< css::uno::Reference< css::form::XFormComponent > >::const_iterator aIter = std::find_if( m_aChildren.begin(),
+ m_aChildren.end(),
+ [&Source](css::uno::Reference< css::uno::XInterface > const & x) { return x == Source.Source; });
+ if(aIter != m_aChildren.end())
+ removeByIndex(aIter - m_aChildren.begin());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/genericcontroller.cxx b/dbaccess/source/ui/browser/genericcontroller.cxx
new file mode 100644
index 000000000..a4b3936b1
--- /dev/null
+++ b/dbaccess/source/ui/browser/genericcontroller.cxx
@@ -0,0 +1,1217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbaccess/genericcontroller.hxx>
+#include <browserids.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <dbaccess/dataview.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <vcl/stdtext.hxx>
+#include <framework/titlehelper.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+
+#include <com/sun/star/ui/XSidebarProvider.hpp>
+#include <sfx2/userinputinterception.hxx>
+
+#include <datasourceconnector.hxx>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/status/Visibility.hpp>
+#include <com/sun/star/frame/XUntitledNumbers.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <limits>
+#include <unordered_map>
+#include <set>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::frame::status;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::ui;
+using namespace ::dbtools;
+using namespace ::comphelper;
+
+#define ALL_FEATURES -1
+
+typedef std::unordered_map< sal_Int16, sal_Int16 > CommandHashMap;
+
+namespace dbaui
+{
+
+namespace {
+
+// UserDefinedFeatures
+class UserDefinedFeatures
+{
+public:
+ explicit UserDefinedFeatures( const Reference< XController >& _rxController );
+
+ void execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs );
+
+private:
+ css::uno::WeakReference< XController > m_aController;
+};
+
+}
+
+UserDefinedFeatures::UserDefinedFeatures( const Reference< XController >& _rxController )
+ :m_aController( _rxController )
+{
+}
+
+void UserDefinedFeatures::execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs )
+{
+ try
+ {
+ Reference< XController > xController( Reference< XController >(m_aController), UNO_SET_THROW );
+ Reference< XDispatchProvider > xDispatchProvider( xController->getFrame(), UNO_QUERY_THROW );
+ Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch(
+ _rFeatureURL,
+ "_self",
+ FrameSearchFlag::AUTO
+ ) );
+
+ if ( xDispatch == xController )
+ {
+ SAL_WARN("dbaccess.ui", "UserDefinedFeatures::execute: the controller shouldn't be the dispatcher here!" );
+ xDispatch.clear();
+ }
+
+ if ( xDispatch.is() )
+ xDispatch->dispatch( _rFeatureURL, _rArgs );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+// OGenericUnoController_Data
+struct OGenericUnoController_Data
+{
+ ::sfx2::UserInputInterception m_aUserInputInterception;
+ UserDefinedFeatures m_aUserDefinedFeatures;
+
+ OGenericUnoController_Data( OGenericUnoController& _rController, ::osl::Mutex& _rMutex )
+ :m_aUserInputInterception( _rController, _rMutex )
+ ,m_aUserDefinedFeatures( _rController.getXController() )
+ {
+ }
+};
+
+// OGenericUnoController
+OGenericUnoController::OGenericUnoController(const Reference< XComponentContext >& _rM)
+ :OGenericUnoController_Base( getMutex() )
+ ,m_pView(nullptr)
+#ifdef DBG_UTIL
+ ,m_bDescribingSupportedFeatures( false )
+#endif
+ ,m_aAsyncInvalidateAll(LINK(this, OGenericUnoController, OnAsyncInvalidateAll))
+ ,m_aAsyncCloseTask(LINK(this, OGenericUnoController, OnAsyncCloseTask))
+ ,m_xContext(_rM)
+ ,m_aCurrentFrame( *this )
+ ,m_bPreview(false)
+ ,m_bReadOnly(false)
+ ,m_bCurrentlyModified(false)
+ ,m_bExternalTitle(false)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ m_pData.reset( new OGenericUnoController_Data( *this, getMutex() ) );
+ }
+ osl_atomic_decrement( &m_refCount );
+
+
+ try
+ {
+ m_xUrlTransformer = URLTransformer::create(_rM);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OGenericUnoController::~OGenericUnoController()
+{
+
+}
+
+bool OGenericUnoController::Construct(vcl::Window* /*pParent*/)
+{
+ OSL_ENSURE( getView(), "the view is NULL!" );
+
+ if ( getView() )
+ {
+ getView()->Construct();
+ getView()->Show();
+ }
+
+ m_aSupportedFeatures.clear();
+ fillSupportedFeatures();
+
+ // create the database context
+ OSL_ENSURE(getORB().is(), "OGenericUnoController::Construct need a service factory!");
+ try
+ {
+ m_xDatabaseContext = DatabaseContext::create(getORB());
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui","OGenericUnoController::Construct: could not create (or start listening at) the database context!");
+ // at least notify the user. Though the whole component does not make any sense without the database context ...
+ ShowServiceNotAvailableError(getFrameWeld(), u"com.sun.star.sdb.DatabaseContext", true);
+ }
+
+ return true;
+}
+
+IMPL_LINK_NOARG(OGenericUnoController, OnAsyncInvalidateAll, void*, void)
+{
+ if ( !OGenericUnoController_Base::rBHelper.bInDispose && !OGenericUnoController_Base::rBHelper.bDisposed )
+ InvalidateFeature_Impl();
+}
+
+void OGenericUnoController::impl_initialize()
+{
+}
+
+void SAL_CALL OGenericUnoController::initialize( const Sequence< Any >& aArguments )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XFrame > xFrame;
+
+ PropertyValue aValue;
+ const Any* pIter = aArguments.getConstArray();
+ const Any* pEnd = pIter + aArguments.getLength();
+
+ for ( ; pIter != pEnd; ++pIter )
+ {
+ if ( ( *pIter >>= aValue ) && aValue.Name == "Frame" )
+ {
+ xFrame.set(aValue.Value,UNO_QUERY_THROW);
+ }
+ else if ( ( *pIter >>= aValue ) && aValue.Name == "Preview" )
+ {
+ aValue.Value >>= m_bPreview;
+ m_bReadOnly = true;
+ }
+ }
+ try
+ {
+ if ( !xFrame.is() )
+ throw IllegalArgumentException("need a frame", *this, 1 );
+
+ Reference<XWindow> xParent = xFrame->getContainerWindow();
+ VclPtr<vcl::Window> pParentWin = VCLUnoHelper::GetWindow(xParent);
+ if (!pParentWin)
+ {
+ throw IllegalArgumentException("Parent window is null", *this, 1 );
+ }
+
+ m_aInitParameters.assign( aArguments );
+ Construct( pParentWin );
+
+ ODataView* pView = getView();
+ if ( !pView )
+ throw RuntimeException("unable to create a view", *this );
+
+ if ( m_bReadOnly || m_bPreview )
+ pView->EnableInput( false );
+
+ impl_initialize();
+ }
+ catch(Exception&)
+ {
+ // no one clears my view if I won't
+ m_pView = nullptr;
+ throw;
+ }
+}
+
+void SAL_CALL OGenericUnoController::acquire( ) noexcept
+{
+ OGenericUnoController_Base::acquire();
+}
+
+void SAL_CALL OGenericUnoController::release( ) noexcept
+{
+ OGenericUnoController_Base::release();
+}
+
+void OGenericUnoController::startFrameListening( const Reference< XFrame >& _rxFrame )
+{
+ if ( _rxFrame.is() )
+ _rxFrame->addFrameActionListener( this );
+}
+
+void OGenericUnoController::stopFrameListening( const Reference< XFrame >& _rxFrame )
+{
+ if ( _rxFrame.is() )
+ _rxFrame->removeFrameActionListener( this );
+}
+
+void OGenericUnoController::disposing(const EventObject& Source)
+{
+ // our frame ?
+ if ( Source.Source == getFrame() )
+ stopFrameListening( getFrame() );
+}
+
+void OGenericUnoController::modified(const EventObject& aEvent)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( !isDataSourceReadOnly() )
+ {
+ Reference<XModifiable> xModi(aEvent.Source,UNO_QUERY);
+ if ( xModi.is() )
+ m_bCurrentlyModified = xModi->isModified(); // can only be reset by save
+ else
+ m_bCurrentlyModified = true;
+ }
+ InvalidateFeature(ID_BROWSER_SAVEDOC);
+ InvalidateFeature(ID_BROWSER_UNDO);
+}
+
+Reference< XWindow > SAL_CALL OGenericUnoController::getComponentWindow()
+{
+ SolarMutexGuard g;
+ return VCLUnoHelper::GetInterface( getView() );
+}
+
+Reference<XSidebarProvider> SAL_CALL OGenericUnoController::getSidebar()
+{
+ return nullptr;
+}
+
+OUString SAL_CALL OGenericUnoController::getViewControllerName()
+{
+ return "Default";
+}
+
+Sequence< PropertyValue > SAL_CALL OGenericUnoController::getCreationArguments()
+{
+ // currently we do not support any creation args, so anything passed to XModel2::createViewController would be
+ // lost, so we can equally return an empty sequence here
+ return Sequence< PropertyValue >();
+}
+
+void OGenericUnoController::attachFrame( const Reference< XFrame >& _rxFrame )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ stopFrameListening( m_aCurrentFrame.getFrame() );
+ Reference< XFrame > xFrame = m_aCurrentFrame.attachFrame( _rxFrame );
+ startFrameListening( xFrame );
+
+ loadMenu( xFrame );
+
+ if ( getView() )
+ getView()->attachFrame( xFrame );
+}
+
+namespace
+{
+ typedef std::vector< Any > States;
+
+ void lcl_notifyMultipleStates( XStatusListener& _rListener, FeatureStateEvent& _rEvent, const States& _rStates )
+ {
+ for (auto const& elem : _rStates)
+ {
+ _rEvent.State = elem;
+ _rListener.statusChanged( _rEvent );
+ }
+ }
+
+ void lcl_collectStates( const FeatureState& _rFeatureState, States& _out_rStates )
+ {
+ // order matters, due to a bug in framework which resets the check state when any non-boolean event
+ // arrives
+ // #i68215# is the bug to (re-)introduce this "ordered" notification here
+ // #i67882# is the bug which was caused by the real fix which we did in framework
+ // #i68216# is the bug which requests to fix the code in Draw which relies on
+ // framework's implementation details
+ if ( !!_rFeatureState.sTitle )
+ _out_rStates.push_back( Any( *_rFeatureState.sTitle ) );
+ if ( !!_rFeatureState.bChecked )
+ _out_rStates.push_back( Any( *_rFeatureState.bChecked ) );
+ if ( !!_rFeatureState.bInvisible )
+ _out_rStates.push_back( Any( Visibility( !*_rFeatureState.bInvisible ) ) );
+ if ( _rFeatureState.aValue.hasValue() )
+ _out_rStates.push_back( _rFeatureState.aValue );
+ if ( _out_rStates.empty() )
+ _out_rStates.emplace_back( );
+ }
+}
+
+void OGenericUnoController::ImplBroadcastFeatureState(const OUString& _rFeature, const Reference< XStatusListener > & xListener, bool _bIgnoreCache)
+{
+ sal_uInt16 nFeat = m_aSupportedFeatures[ _rFeature ].nFeatureId;
+ FeatureState aFeatState( GetState( nFeat ) );
+
+ FeatureState& rCachedState = m_aStateCache[nFeat]; // creates if necessary
+ if ( !_bIgnoreCache )
+ {
+ // check if we really need to notify the listeners : this method may be called much more often than needed, so check
+ // the cached state of the feature
+ bool bAlreadyCached = ( m_aStateCache.find(nFeat) != m_aStateCache.end() );
+ if ( bAlreadyCached )
+ if ( ( rCachedState.bEnabled == aFeatState.bEnabled )
+ && ( rCachedState.bChecked == aFeatState.bChecked )
+ && ( rCachedState.bInvisible == aFeatState.bInvisible )
+ && ( rCachedState.sTitle == aFeatState.sTitle )
+ )
+ return;
+ }
+ rCachedState = aFeatState;
+
+ FeatureStateEvent aEvent;
+ aEvent.FeatureURL.Complete = _rFeature;
+ if (m_xUrlTransformer.is())
+ m_xUrlTransformer->parseStrict(aEvent.FeatureURL);
+ aEvent.Source = static_cast<XDispatch*>(this);
+ aEvent.IsEnabled = aFeatState.bEnabled;
+
+ // collect all states to be notified
+ States aStates;
+ lcl_collectStates( aFeatState, aStates );
+
+ // a special listener ?
+ if ( xListener.is() )
+ lcl_notifyMultipleStates( *xListener, aEvent, aStates );
+ else
+ { // no -> iterate through all listeners responsible for the URL
+ std::set<OUString> aFeatureCommands;
+ for( const auto& rFeature : m_aSupportedFeatures )
+ {
+ if( rFeature.second.nFeatureId == nFeat )
+ aFeatureCommands.insert( rFeature.first );
+ }
+
+ // it is possible that listeners are registered or revoked while
+ // we are notifying them, so we must use a copy of m_arrStatusListener, not
+ // m_arrStatusListener itself
+ Dispatch aNotifyLoop( m_arrStatusListener );
+
+ for (auto const& elem : aNotifyLoop)
+ {
+ if ( aFeatureCommands.find( elem.aURL.Complete ) != aFeatureCommands.end() )
+ {
+ aEvent.FeatureURL = elem.aURL;
+ lcl_notifyMultipleStates( *elem.xListener, aEvent, aStates );
+ }
+ }
+ }
+
+}
+
+bool OGenericUnoController::isFeatureSupported( sal_Int32 _nId )
+{
+ SupportedFeatures::const_iterator aFeaturePos = std::find_if(
+ m_aSupportedFeatures.begin(),
+ m_aSupportedFeatures.end(),
+ CompareFeatureById(_nId)
+ );
+
+ return ( m_aSupportedFeatures.end() != aFeaturePos && !aFeaturePos->first.isEmpty());
+}
+
+void OGenericUnoController::InvalidateFeature_Impl()
+{
+ bool bEmpty = true;
+ FeatureListener aNextFeature;
+ {
+ ::osl::MutexGuard aGuard( m_aFeatureMutex);
+ bEmpty = m_aFeaturesToInvalidate.empty();
+ if (!bEmpty)
+ aNextFeature = m_aFeaturesToInvalidate.front();
+ }
+ while(!bEmpty)
+ {
+ if ( ALL_FEATURES == aNextFeature.nId )
+ {
+ InvalidateAll_Impl();
+ break;
+ }
+ else
+ {
+ SupportedFeatures::const_iterator aFeaturePos = std::find_if(
+ m_aSupportedFeatures.begin(),
+ m_aSupportedFeatures.end(),
+ CompareFeatureById( aNextFeature.nId )
+ );
+
+#if OSL_DEBUG_LEVEL > 0
+ if ( m_aSupportedFeatures.end() == aFeaturePos )
+ {
+ SAL_WARN( "dbaccess.ui", "OGenericUnoController::InvalidateFeature_Impl: feature id "
+ << aNextFeature.nId
+ << " has been invalidated, but is not supported!" );
+ }
+#endif
+ if ( m_aSupportedFeatures.end() != aFeaturePos )
+ // we really know this feature
+ ImplBroadcastFeatureState( aFeaturePos->first, aNextFeature.xListener, aNextFeature.bForceBroadcast );
+ }
+
+ ::osl::MutexGuard aGuard( m_aFeatureMutex);
+ m_aFeaturesToInvalidate.pop_front();
+ bEmpty = m_aFeaturesToInvalidate.empty();
+ if (!bEmpty)
+ aNextFeature = m_aFeaturesToInvalidate.front();
+ }
+}
+
+void OGenericUnoController::ImplInvalidateFeature( sal_Int32 _nId, const Reference< XStatusListener >& _xListener, bool _bForceBroadcast )
+{
+#if OSL_DEBUG_LEVEL > 0
+ if ( _nId != -1 )
+ {
+ auto isSupportedFeature = std::any_of(
+ m_aSupportedFeatures.begin(),
+ m_aSupportedFeatures.end(),
+ CompareFeatureById( _nId )
+ );
+ OSL_ENSURE( isSupportedFeature, "OGenericUnoController::ImplInvalidateFeature: invalidating an unsupported feature is suspicious, at least!" );
+ }
+#endif
+
+ FeatureListener aListener;
+ aListener.nId = _nId;
+ aListener.xListener = _xListener;
+ aListener.bForceBroadcast = _bForceBroadcast;
+
+ bool bWasEmpty;
+ {
+ ::osl::MutexGuard aGuard( m_aFeatureMutex );
+ bWasEmpty = m_aFeaturesToInvalidate.empty();
+ m_aFeaturesToInvalidate.push_back( aListener );
+ }
+
+ if ( bWasEmpty )
+ m_aAsyncInvalidateAll.Call();
+}
+
+void OGenericUnoController::InvalidateFeature(sal_uInt16 _nId, const Reference< XStatusListener > & _xListener, bool _bForceBroadcast)
+{
+ ImplInvalidateFeature( _nId, _xListener, _bForceBroadcast );
+}
+
+void OGenericUnoController::InvalidateAll()
+{
+ ImplInvalidateFeature( ALL_FEATURES, nullptr, true );
+}
+
+void OGenericUnoController::InvalidateAll_Impl()
+{
+ // invalidate all supported features
+ for (auto const& supportedFeature : m_aSupportedFeatures)
+ ImplBroadcastFeatureState( supportedFeature.first, nullptr, true );
+
+ {
+ ::osl::MutexGuard aGuard( m_aFeatureMutex);
+ OSL_ENSURE(m_aFeaturesToInvalidate.size(), "OGenericUnoController::InvalidateAll_Impl: to be called from within InvalidateFeature_Impl only!");
+ m_aFeaturesToInvalidate.pop_front();
+ if(!m_aFeaturesToInvalidate.empty())
+ m_aAsyncInvalidateAll.Call();
+ }
+}
+
+Reference< XDispatch > OGenericUnoController::queryDispatch(const URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags)
+{
+ Reference< XDispatch > xReturn;
+
+ OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::queryDispatch: shouldn't this be filled at construction time?" );
+ if ( m_aSupportedFeatures.empty() )
+ fillSupportedFeatures();
+
+ // URL's we can handle ourself?
+ if ( aURL.Complete == ".uno:FormSlots/ConfirmDeletion"
+ || ( ( m_aSupportedFeatures.find( aURL.Complete ) != m_aSupportedFeatures.end() )
+ && !isUserDefinedFeature( aURL.Complete )
+ )
+ )
+ {
+ xReturn = this;
+ }
+ // no? -> ask the slave dispatcher
+ else if ( m_xSlaveDispatcher.is() )
+ {
+ xReturn = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+ }
+
+ // outta here
+ return xReturn;
+}
+
+Sequence< Reference< XDispatch > > OGenericUnoController::queryDispatches(const Sequence< DispatchDescriptor >& aDescripts)
+{
+ Sequence< Reference< XDispatch > > aReturn;
+ sal_Int32 nLen = aDescripts.getLength();
+ if ( nLen )
+ {
+ aReturn.realloc( nLen );
+ Reference< XDispatch >* pReturn = aReturn.getArray();
+ const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen;
+ const DispatchDescriptor* pDescripts = aDescripts.getConstArray();
+
+ for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts )
+ {
+ *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags );
+ }
+ }
+
+ return aReturn;
+}
+
+Reference< XDispatchProvider > OGenericUnoController::getSlaveDispatchProvider()
+{
+ return m_xSlaveDispatcher;
+}
+
+void OGenericUnoController::setSlaveDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider)
+{
+ m_xSlaveDispatcher = _xNewProvider;
+}
+
+Reference< XDispatchProvider > OGenericUnoController::getMasterDispatchProvider()
+{
+ return m_xMasterDispatcher;
+}
+
+void OGenericUnoController::setMasterDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider)
+{
+ m_xMasterDispatcher = _xNewProvider;
+}
+
+void OGenericUnoController::dispatch(const URL& _aURL, const Sequence< PropertyValue >& aArgs)
+{
+ SolarMutexGuard aSolarGuard;
+ // The SolarMutex is not locked anymore when the framework calls into
+ // here. So, lock it ourself. The real solution would be to lock it only in the places
+ // where it's needed, but a) this might turn out difficult, since we then also need to care
+ // for locking in the proper order (SolarMutex and m_aMutex), and b) this would be too many places
+ // for the time frame of the fix.
+ // #i52602#
+ executeChecked(_aURL,aArgs);
+}
+
+void OGenericUnoController::addStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL)
+{
+ // parse the URL now and here, this saves later parsing in each notification round
+ URL aParsedURL( _rURL );
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aParsedURL );
+
+ // remember the listener together with the URL
+ m_arrStatusListener.insert( m_arrStatusListener.end(), DispatchTarget( aParsedURL, aListener ) );
+
+ // initially broadcast the state
+ ImplBroadcastFeatureState( aParsedURL.Complete, aListener, true );
+ // force the new state to be broadcast to the new listener
+}
+
+void OGenericUnoController::removeStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL)
+{
+ if (_rURL.Complete.isEmpty())
+ {
+ m_arrStatusListener.erase(std::remove_if(m_arrStatusListener.begin(), m_arrStatusListener.end(),
+ [&aListener](const DispatchTarget& rCurrent) { return rCurrent.xListener == aListener; }),
+ m_arrStatusListener.end());
+ }
+ else
+ {
+ // remove the listener only for the given URL
+ Dispatch::iterator iterSearch = std::find_if(m_arrStatusListener.begin(), m_arrStatusListener.end(),
+ [&aListener, &_rURL](const DispatchTarget& rCurrent) {
+ return (rCurrent.xListener == aListener) && (rCurrent.aURL.Complete == _rURL.Complete); });
+ if (iterSearch != m_arrStatusListener.end())
+ m_arrStatusListener.erase(iterSearch);
+ }
+
+ OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::removeStatusListener: shouldn't this be filled at construction time?" );
+ if ( m_aSupportedFeatures.empty() )
+ fillSupportedFeatures();
+
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find(_rURL.Complete);
+ if (aIter != m_aSupportedFeatures.end())
+ { // clear the cache for that feature
+ StateCache::const_iterator aCachePos = m_aStateCache.find( aIter->second.nFeatureId );
+ if ( aCachePos != m_aStateCache.end() )
+ m_aStateCache.erase( aCachePos );
+ }
+
+ // now remove the listener from the deque
+ ::osl::MutexGuard aGuard( m_aFeatureMutex );
+ m_aFeaturesToInvalidate.erase(
+ std::remove_if( m_aFeaturesToInvalidate.begin(),
+ m_aFeaturesToInvalidate.end(),
+ FindFeatureListener(aListener))
+ ,m_aFeaturesToInvalidate.end());
+}
+
+void OGenericUnoController::releaseNumberForComponent()
+{
+ try
+ {
+ Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY );
+ if ( xUntitledProvider.is() )
+ xUntitledProvider->releaseNumberForComponent(static_cast<XWeak*>(this));
+ }
+ catch( const Exception& )
+ {
+ // NII
+ }
+}
+
+void OGenericUnoController::disposing()
+{
+ {
+ EventObject aDisposeEvent;
+ aDisposeEvent.Source = static_cast<XWeak*>(this);
+ Dispatch aStatusListener = m_arrStatusListener;
+ for (auto const& statusListener : aStatusListener)
+ {
+ statusListener.xListener->disposing(aDisposeEvent);
+ }
+ m_arrStatusListener.clear();
+ }
+
+ m_xDatabaseContext = nullptr;
+ {
+ ::osl::MutexGuard aGuard( m_aFeatureMutex);
+ m_aAsyncInvalidateAll.CancelCall();
+ m_aFeaturesToInvalidate.clear();
+ }
+
+ releaseNumberForComponent();
+
+ // check out from all the objects we are listening
+ // the frame
+ stopFrameListening( m_aCurrentFrame.getFrame() );
+ m_aCurrentFrame.attachFrame( nullptr );
+
+ m_xMasterDispatcher = nullptr;
+ m_xSlaveDispatcher = nullptr;
+ m_xTitleHelper.clear();
+ m_xUrlTransformer.clear();
+ m_aInitParameters.clear();
+}
+
+void SAL_CALL OGenericUnoController::addEventListener( const Reference< XEventListener >& xListener )
+{
+ // disambiguate
+ OGenericUnoController_Base::WeakComponentImplHelperBase::addEventListener( xListener );
+}
+
+void SAL_CALL OGenericUnoController::removeEventListener( const Reference< XEventListener >& xListener )
+{
+ // disambiguate
+ OGenericUnoController_Base::WeakComponentImplHelperBase::removeEventListener( xListener );
+}
+
+void OGenericUnoController::frameAction(const FrameActionEvent& aEvent)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( aEvent.Frame == m_aCurrentFrame.getFrame() )
+ m_aCurrentFrame.frameAction( aEvent.Action );
+}
+
+void OGenericUnoController::implDescribeSupportedFeature( const OUString& _rCommandURL,
+ sal_uInt16 _nFeatureId, sal_Int16 _nCommandGroup )
+{
+#ifdef DBG_UTIL
+ OSL_ENSURE( m_bDescribingSupportedFeatures, "OGenericUnoController::implDescribeSupportedFeature: bad timing for this call!" );
+#endif
+ OSL_PRECOND( _nFeatureId < ( std::numeric_limits< sal_uInt16 >::max() - 1000 ), // FIRST_USER_DEFINED_FEATURE
+ "OGenericUnoController::implDescribeSupportedFeature: invalid feature id!" );
+
+ ControllerFeature aFeature;
+ aFeature.Command = _rCommandURL;
+ aFeature.nFeatureId = _nFeatureId;
+ aFeature.GroupId = _nCommandGroup;
+
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE( m_aSupportedFeatures.find( aFeature.Command ) == m_aSupportedFeatures.end(),
+ "OGenericUnoController::implDescribeSupportedFeature: this feature is already there!" );
+#endif
+ m_aSupportedFeatures[ aFeature.Command ] = aFeature;
+}
+
+void OGenericUnoController::describeSupportedFeatures()
+{
+ // add all supported features
+ implDescribeSupportedFeature( ".uno:Copy", ID_BROWSER_COPY, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Cut", ID_BROWSER_CUT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Paste", ID_BROWSER_PASTE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:ClipboardFormatItems", ID_BROWSER_CLIPBOARD_FORMAT_ITEMS );
+ implDescribeSupportedFeature( ".uno:DSBEditDoc", ID_BROWSER_EDITDOC, CommandGroup::DOCUMENT );
+}
+
+FeatureState OGenericUnoController::GetState( sal_uInt16 _nId ) const
+{
+ FeatureState aReturn;
+ // (disabled automatically)
+
+ switch ( _nId )
+ {
+ case ID_BROWSER_UNDO:
+ case ID_BROWSER_SAVEDOC:
+ aReturn.bEnabled = true;
+ break;
+ default:
+ // for now, enable all the time
+ // TODO: we should ask the dispatcher. However, this is laborious, since you cannot ask a dispatcher
+ // directly, but need to add a status listener.
+ aReturn.bEnabled = true;
+ break;
+ }
+
+ return aReturn;
+}
+
+void OGenericUnoController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue>& _rArgs )
+{
+ OSL_ENSURE( isUserDefinedFeature( _nId ),
+ "OGenericUnoController::Execute: responsible for user defined features only!" );
+
+ // user defined features can be handled by dispatch interceptors resp. protocol handlers only.
+ // So, we need to do a queryDispatch, and dispatch the URL
+ m_pData->m_aUserDefinedFeatures.execute( getURLForId( _nId ), _rArgs );
+}
+
+URL OGenericUnoController::getURLForId(sal_Int32 _nId) const
+{
+ URL aReturn;
+ if ( m_xUrlTransformer.is() )
+ {
+ SupportedFeatures::const_iterator aIter = std::find_if(
+ m_aSupportedFeatures.begin(),
+ m_aSupportedFeatures.end(),
+ CompareFeatureById( _nId )
+ );
+
+ if ( m_aSupportedFeatures.end() != aIter && !aIter->first.isEmpty() )
+ {
+ aReturn.Complete = aIter->first;
+ m_xUrlTransformer->parseStrict( aReturn );
+ }
+ }
+ return aReturn;
+}
+
+bool OGenericUnoController::isUserDefinedFeature( const sal_uInt16 _nFeatureId )
+{
+ return
+ (_nFeatureId >= ( std::numeric_limits< sal_uInt16 >::max() - 1000 )) // test if >= FIRST_USER_DEFINED_FEATURE
+ &&
+ ( _nFeatureId < (std::numeric_limits< sal_uInt16 >::max())) // test if < LAST_USER_DEFINED_FEATURE
+ ;
+}
+
+bool OGenericUnoController::isUserDefinedFeature( const OUString& _rFeatureURL ) const
+{
+ SupportedFeatures::const_iterator pos = m_aSupportedFeatures.find( _rFeatureURL );
+ OSL_PRECOND( pos != m_aSupportedFeatures.end(),
+ "OGenericUnoController::isUserDefinedFeature: this is no supported feature at all!" );
+
+ return ( pos != m_aSupportedFeatures.end() ) && isUserDefinedFeature( pos->second.nFeatureId );
+}
+
+sal_Bool SAL_CALL OGenericUnoController::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+void OGenericUnoController::startConnectionListening(const Reference< XConnection >& _rxConnection)
+{
+ // we have to remove ourself before disposing the connection
+ Reference< XComponent > xComponent(_rxConnection, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast<XFrameActionListener*>(this));
+}
+
+void OGenericUnoController::stopConnectionListening(const Reference< XConnection >& _rxConnection)
+{
+ // we have to remove ourself before disposing the connection
+ Reference< XComponent > xComponent(_rxConnection, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(static_cast<XFrameActionListener*>(this));
+}
+
+Reference< XConnection > OGenericUnoController::connect( const Reference< XDataSource>& _xDataSource )
+{
+ weld::WaitObject aWaitCursor(getFrameWeld());
+
+ ODatasourceConnector aConnector( getORB(), getFrameWeld(), OUString() );
+ Reference< XConnection > xConnection = aConnector.connect( _xDataSource, nullptr );
+ startConnectionListening( xConnection );
+
+ return xConnection;
+}
+
+Reference< XConnection > OGenericUnoController::connect( const OUString& _rDataSourceName,
+ const OUString& _rContextInformation, ::dbtools::SQLExceptionInfo* _pErrorInfo )
+{
+ weld::WaitObject aWaitCursor(getFrameWeld());
+
+ ODatasourceConnector aConnector( getORB(), getFrameWeld(), _rContextInformation );
+ Reference<XConnection> xConnection = aConnector.connect( _rDataSourceName, _pErrorInfo );
+ startConnectionListening( xConnection );
+
+ return xConnection;
+}
+
+void OGenericUnoController::setView( const VclPtr<ODataView> &i_rView )
+{
+ m_pView = i_rView;
+}
+
+void OGenericUnoController::clearView()
+{
+ m_pView = nullptr;
+}
+
+void OGenericUnoController::showError(const SQLExceptionInfo& _rInfo)
+{
+ ::dbtools::showError(_rInfo,VCLUnoHelper::GetInterface(getView()),getORB());
+}
+
+Reference< XLayoutManager > OGenericUnoController::getLayoutManager(const Reference< XFrame >& _xFrame)
+{
+ Reference< XPropertySet > xPropSet( _xFrame, UNO_QUERY );
+ Reference< XLayoutManager > xLayoutManager;
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ xLayoutManager.set(xPropSet->getPropertyValue("LayoutManager"),UNO_QUERY);
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+ return xLayoutManager;
+}
+
+void OGenericUnoController::loadMenu(const Reference< XFrame >& _xFrame)
+{
+ Reference< XLayoutManager > xLayoutManager = getLayoutManager(_xFrame);
+ if ( xLayoutManager.is() )
+ {
+ xLayoutManager->lock();
+ xLayoutManager->createElement( "private:resource/menubar/menubar" );
+ xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
+ xLayoutManager->unlock();
+ xLayoutManager->doLayout();
+ }
+
+ onLoadedMenu( xLayoutManager );
+}
+
+void OGenericUnoController::onLoadedMenu(const Reference< XLayoutManager >& /*_xLayoutManager*/)
+{
+ // not interested in
+}
+
+void OGenericUnoController::closeTask()
+{
+ m_aAsyncCloseTask.Call();
+}
+
+IMPL_LINK_NOARG(OGenericUnoController, OnAsyncCloseTask, void*, void)
+{
+ if ( !OGenericUnoController_Base::rBHelper.bInDispose )
+ {
+ try
+ {
+ Reference< util::XCloseable > xCloseable( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW );
+ xCloseable->close( false ); // false - holds the owner ship for this frame inside this object!
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+Any SAL_CALL OGenericUnoController::getViewData()
+{
+ return Any();
+}
+
+void SAL_CALL OGenericUnoController::restoreViewData(const Any& /*Data*/)
+{
+}
+
+Reference< XModel > SAL_CALL OGenericUnoController::getModel()
+{
+ return Reference< XModel >();
+}
+
+Reference< XFrame > SAL_CALL OGenericUnoController::getFrame()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_aCurrentFrame.getFrame();
+}
+
+sal_Bool SAL_CALL OGenericUnoController::attachModel(const Reference< XModel > & /*xModel*/)
+{
+ SAL_WARN("dbaccess.ui", "OGenericUnoController::attachModel: not supported!" );
+ return false;
+}
+
+void OGenericUnoController::executeUnChecked(sal_uInt16 _nCommandId, const Sequence< PropertyValue >& aArgs)
+{
+ Execute(_nCommandId, aArgs);
+}
+
+void OGenericUnoController::executeUnChecked(const util::URL& _rCommand, const Sequence< PropertyValue >& aArgs)
+{
+ OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::executeUnChecked: shouldn't this be filled at construction time?" );
+ if ( m_aSupportedFeatures.empty() )
+ fillSupportedFeatures();
+
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCommand.Complete );
+ if (aIter != m_aSupportedFeatures.end())
+ Execute( aIter->second.nFeatureId, aArgs );
+}
+
+void OGenericUnoController::executeChecked(const util::URL& _rCommand, const Sequence< PropertyValue >& aArgs)
+{
+ OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::executeChecked: shouldn't this be filled at construction time?" );
+ if ( m_aSupportedFeatures.empty() )
+ fillSupportedFeatures();
+
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCommand.Complete );
+ if ( aIter != m_aSupportedFeatures.end() )
+ {
+ sal_uInt16 nFeatureId = aIter->second.nFeatureId;
+ if ( GetState( nFeatureId ).bEnabled )
+ Execute( nFeatureId, aArgs );
+ }
+}
+
+Reference< awt::XWindow> OGenericUnoController::getTopMostContainerWindow() const
+{
+ Reference< css::awt::XWindow> xWindow;
+
+ // get the top most window
+ Reference< XFrame > xFrame( m_aCurrentFrame.getFrame() );
+ if ( xFrame.is() )
+ {
+ xWindow = xFrame->getContainerWindow();
+
+ while ( xFrame.is() && !xFrame->isTop() )
+ {
+ xFrame = xFrame->getCreator();
+ }
+ if ( xFrame.is() )
+ xWindow = xFrame->getContainerWindow();
+ }
+ return xWindow;
+}
+
+Reference< XTitle > OGenericUnoController::impl_getTitleHelper_throw(bool bCreateIfNecessary)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if (!m_xTitleHelper.is() && bCreateIfNecessary)
+ {
+ Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY );
+
+ m_xTitleHelper = new ::framework::TitleHelper( m_xContext, Reference< XController >(this), xUntitledProvider );
+ }
+
+ return m_xTitleHelper;
+}
+
+// XTitle
+OUString SAL_CALL OGenericUnoController::getTitle()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( m_bExternalTitle )
+ return impl_getTitleHelper_throw()->getTitle ();
+ return getPrivateTitle() + impl_getTitleHelper_throw()->getTitle ();
+}
+
+// XTitle
+void SAL_CALL OGenericUnoController::setTitle(const OUString& sTitle)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ m_bExternalTitle = true;
+ impl_getTitleHelper_throw()->setTitle (sTitle);
+}
+
+// XTitleChangeBroadcaster
+void SAL_CALL OGenericUnoController::addTitleChangeListener(const Reference< XTitleChangeListener >& xListener)
+{
+ Reference< XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper_throw(), UNO_QUERY);
+ if (xBroadcaster.is ())
+ xBroadcaster->addTitleChangeListener (xListener);
+}
+
+void SAL_CALL OGenericUnoController::removeTitleChangeListener(const Reference< XTitleChangeListener >& xListener)
+{
+ Reference< XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper_throw(false), UNO_QUERY);
+ if (xBroadcaster.is ())
+ xBroadcaster->removeTitleChangeListener (xListener);
+}
+
+// XUserInputInterception
+void SAL_CALL OGenericUnoController::addKeyHandler( const Reference< XKeyHandler >& _rxHandler )
+{
+ if ( _rxHandler.is() )
+ m_pData->m_aUserInputInterception.addKeyHandler( _rxHandler );
+}
+
+void SAL_CALL OGenericUnoController::removeKeyHandler( const Reference< XKeyHandler >& _rxHandler )
+{
+ m_pData->m_aUserInputInterception.removeKeyHandler( _rxHandler );
+}
+
+void SAL_CALL OGenericUnoController::addMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler )
+{
+ if ( _rxHandler.is() )
+ m_pData->m_aUserInputInterception.addMouseClickHandler( _rxHandler );
+}
+
+void SAL_CALL OGenericUnoController::removeMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler )
+{
+ m_pData->m_aUserInputInterception.removeMouseClickHandler( _rxHandler );
+}
+
+void OGenericUnoController::executeChecked(sal_uInt16 _nCommandId, const Sequence< PropertyValue >& aArgs)
+{
+ if ( isCommandEnabled(_nCommandId) )
+ Execute(_nCommandId, aArgs);
+}
+
+bool OGenericUnoController::isCommandEnabled(sal_uInt16 _nCommandId) const
+{
+ return GetState( _nCommandId ).bEnabled;
+}
+
+bool OGenericUnoController::isDataSourceReadOnly() const
+{
+ return false;
+}
+
+Reference< XController > OGenericUnoController::getXController()
+{
+ return this;
+}
+
+bool OGenericUnoController::interceptUserInput( const NotifyEvent& _rEvent )
+{
+ return m_pData->m_aUserInputInterception.handleNotifyEvent( _rEvent );
+}
+
+bool OGenericUnoController::isCommandChecked(sal_uInt16 _nCommandId) const
+{
+ FeatureState aState = GetState( _nCommandId );
+
+ return aState.bChecked && *aState.bChecked;
+}
+
+bool OGenericUnoController::isCommandEnabled( const OUString& _rCompleteCommandURL ) const
+{
+ OSL_ENSURE( !_rCompleteCommandURL.isEmpty(), "OGenericUnoController::isCommandEnabled: Empty command url!" );
+
+ bool bIsEnabled = false;
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCompleteCommandURL );
+ if ( aIter != m_aSupportedFeatures.end() )
+ bIsEnabled = isCommandEnabled( aIter->second.nFeatureId );
+
+ return bIsEnabled;
+}
+
+Sequence< ::sal_Int16 > SAL_CALL OGenericUnoController::getSupportedCommandGroups()
+{
+ CommandHashMap aCmdHashMap;
+ for (auto const& supportedFeature : m_aSupportedFeatures)
+ if ( supportedFeature.second.GroupId != CommandGroup::INTERNAL )
+ aCmdHashMap.emplace( supportedFeature.second.GroupId, 0 );
+
+ return comphelper::mapKeysToSequence( aCmdHashMap );
+}
+
+Sequence< DispatchInformation > SAL_CALL OGenericUnoController::getConfigurableDispatchInformation( ::sal_Int16 CommandGroup )
+{
+ std::vector< DispatchInformation > aInformationVector;
+ for (auto const& supportedFeature : m_aSupportedFeatures)
+ {
+ if ( sal_Int16( supportedFeature.second.GroupId ) == CommandGroup )
+ {
+ aInformationVector.push_back( supportedFeature.second );
+ }
+ }
+
+ return comphelper::containerToSequence( aInformationVector );
+}
+
+void OGenericUnoController::fillSupportedFeatures()
+{
+#ifdef DBG_UTIL
+ m_bDescribingSupportedFeatures = true;
+#endif
+ describeSupportedFeatures();
+#ifdef DBG_UTIL
+ m_bDescribingSupportedFeatures = false;
+#endif
+}
+
+void SAL_CALL OGenericUnoController::dispose()
+{
+ SolarMutexGuard aSolarGuard;
+ OGenericUnoController_Base::dispose();
+}
+
+weld::Window* OGenericUnoController::getFrameWeld() const
+{
+ return m_pView ? m_pView->GetFrameWeld() : nullptr;
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/sbagrid.cxx b/dbaccess/source/ui/browser/sbagrid.cxx
new file mode 100644
index 000000000..d1adbea01
--- /dev/null
+++ b/dbaccess/source/ui/browser/sbagrid.cxx
@@ -0,0 +1,1364 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+
+#include <sot/exchange.hxx>
+
+#include <svx/dbaexchange.hxx>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+
+#include <sbagrid.hxx>
+#include <dlgsize.hxx>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <tools/diagnose_ex.h>
+
+#include <svl/numuno.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include <cppuhelper/queryinterface.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <dbexchange.hxx>
+#include <svtools/stringtransfer.hxx>
+#include <UITools.hxx>
+#include <TokenWriter.hxx>
+#include <osl/diagnose.h>
+#include <algorithm>
+
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::util;
+using namespace ::dbaui;
+using namespace ::dbtools;
+using namespace ::svx;
+using namespace ::svt;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbu_SbaXGridControl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new SbaXGridControl(context));
+}
+
+css::uno::Sequence<OUString> SAL_CALL SbaXGridControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.form.control.InteractionGridControl", "com.sun.star.form.control.GridControl",
+ "com.sun.star.awt.UnoControl" };
+}
+
+
+// SbaXGridControl
+
+OUString SAL_CALL SbaXGridControl::getImplementationName()
+{
+ return "com.sun.star.comp.dbu.SbaXGridControl";
+}
+
+SbaXGridControl::SbaXGridControl(const Reference< XComponentContext >& _rM)
+ : FmXGridControl(_rM)
+{
+}
+
+SbaXGridControl::~SbaXGridControl()
+{
+}
+
+rtl::Reference<FmXGridPeer> SbaXGridControl::imp_CreatePeer(vcl::Window* pParent)
+{
+ rtl::Reference<FmXGridPeer> pReturn = new SbaXGridPeer(m_xContext);
+
+ // translate properties into WinBits
+ WinBits nStyle = WB_TABSTOP;
+ Reference< XPropertySet > xModelSet(getModel(), UNO_QUERY);
+ if (xModelSet.is())
+ {
+ try
+ {
+ if (::comphelper::getINT16(xModelSet->getPropertyValue(PROPERTY_BORDER)))
+ nStyle |= WB_BORDER;
+ }
+ catch(Exception&)
+ {
+ }
+
+ }
+
+ pReturn->Create(pParent, nStyle);
+ return pReturn;
+}
+
+Any SAL_CALL SbaXGridControl::queryInterface(const Type& _rType)
+{
+ Any aRet = FmXGridControl::queryInterface(_rType);
+ return aRet.hasValue() ? aRet : ::cppu::queryInterface(_rType,static_cast<css::frame::XDispatch*>(this));
+}
+
+Sequence< Type > SAL_CALL SbaXGridControl::getTypes( )
+{
+ return comphelper::concatSequences(
+ FmXGridControl::getTypes(),
+ Sequence { cppu::UnoType<css::frame::XDispatch>::get() });
+}
+
+Sequence< sal_Int8 > SAL_CALL SbaXGridControl::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SAL_CALL SbaXGridControl::createPeer(const Reference< css::awt::XToolkit > & rToolkit, const Reference< css::awt::XWindowPeer > & rParentPeer)
+{
+ FmXGridControl::createPeer(rToolkit, rParentPeer);
+
+ OSL_ENSURE(!mbCreatingPeer, "FmXGridControl::createPeer : recursion!");
+ // see the base class' createPeer for a comment on this
+
+ // TODO: why the hell this whole class does not use any mutex?
+
+ Reference< css::frame::XDispatch > xDisp(getPeer(), UNO_QUERY);
+ for (auto const& elem : m_aStatusMultiplexer)
+ {
+ if (elem.second.is() && elem.second->getLength())
+ xDisp->addStatusListener(elem.second, elem.first);
+ }
+}
+
+void SAL_CALL SbaXGridControl::dispatch(const css::util::URL& aURL, const Sequence< PropertyValue >& aArgs)
+{
+ Reference< css::frame::XDispatch > xDisp(getPeer(), UNO_QUERY);
+ if (xDisp.is())
+ xDisp->dispatch(aURL, aArgs);
+}
+
+void SAL_CALL SbaXGridControl::addStatusListener( const Reference< XStatusListener > & _rxListener, const URL& _rURL )
+{
+ ::osl::MutexGuard aGuard( GetMutex() );
+ if ( !_rxListener.is() )
+ return;
+
+ rtl::Reference<SbaXStatusMultiplexer>& xMultiplexer = m_aStatusMultiplexer[ _rURL ];
+ if ( !xMultiplexer.is() )
+ {
+ xMultiplexer = new SbaXStatusMultiplexer( *this, GetMutex() );
+ }
+
+ xMultiplexer->addInterface( _rxListener );
+ if ( getPeer().is() )
+ {
+ if ( 1 == xMultiplexer->getLength() )
+ { // the first external listener for this URL
+ Reference< XDispatch > xDisp( getPeer(), UNO_QUERY );
+ xDisp->addStatusListener( xMultiplexer, _rURL );
+ }
+ else
+ { // already have other listeners for this URL
+ _rxListener->statusChanged( xMultiplexer->getLastEvent() );
+ }
+ }
+}
+
+void SAL_CALL SbaXGridControl::removeStatusListener(const Reference< css::frame::XStatusListener > & _rxListener, const css::util::URL& _rURL)
+{
+ ::osl::MutexGuard aGuard( GetMutex() );
+
+ rtl::Reference<SbaXStatusMultiplexer>& xMultiplexer = m_aStatusMultiplexer[_rURL];
+ if (!xMultiplexer.is())
+ {
+ xMultiplexer = new SbaXStatusMultiplexer(*this,GetMutex());
+ }
+
+ if (getPeer().is() && xMultiplexer->getLength() == 1)
+ {
+ Reference< css::frame::XDispatch > xDisp(getPeer(), UNO_QUERY);
+ xDisp->removeStatusListener(xMultiplexer, _rURL);
+ }
+ xMultiplexer->removeInterface( _rxListener );
+}
+
+void SAL_CALL SbaXGridControl::dispose()
+{
+ SolarMutexGuard aGuard;
+
+ EventObject aEvt;
+ aEvt.Source = *this;
+
+ for (auto & elem : m_aStatusMultiplexer)
+ {
+ if (elem.second.is())
+ {
+ elem.second->disposeAndClear(aEvt);
+ elem.second.clear();
+ }
+ }
+ StatusMultiplexerArray().swap(m_aStatusMultiplexer);
+
+ FmXGridControl::dispose();
+}
+
+// SbaXGridPeer
+SbaXGridPeer::SbaXGridPeer(const Reference< XComponentContext >& _rM)
+: FmXGridPeer(_rM)
+,m_aStatusListeners(m_aMutex)
+{
+}
+
+SbaXGridPeer::~SbaXGridPeer()
+{
+}
+
+void SAL_CALL SbaXGridPeer::dispose()
+{
+ EventObject aEvt(*this);
+
+ m_aStatusListeners.disposeAndClear(aEvt);
+
+ FmXGridPeer::dispose();
+}
+
+void SbaXGridPeer::NotifyStatusChanged(const css::util::URL& _rUrl, const Reference< css::frame::XStatusListener > & xControl)
+{
+ VclPtr< SbaGridControl > pGrid = GetAs< SbaGridControl >();
+ if (!pGrid)
+ return;
+
+ css::frame::FeatureStateEvent aEvt;
+ aEvt.Source = *this;
+ aEvt.IsEnabled = !pGrid->IsReadOnlyDB();
+ aEvt.FeatureURL = _rUrl;
+
+ MapDispatchToBool::const_iterator aURLStatePos = m_aDispatchStates.find( classifyDispatchURL( _rUrl ) );
+ if ( m_aDispatchStates.end() != aURLStatePos )
+ aEvt.State <<= aURLStatePos->second;
+ else
+ aEvt.State <<= false;
+
+ if (xControl.is())
+ xControl->statusChanged(aEvt);
+ else
+ {
+ ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener> * pIter
+ = m_aStatusListeners.getContainer(_rUrl);
+
+ if (pIter)
+ {
+ pIter->notifyEach( &XStatusListener::statusChanged, aEvt );
+ }
+ }
+}
+
+Any SAL_CALL SbaXGridPeer::queryInterface(const Type& _rType)
+{
+ Any aRet = ::cppu::queryInterface(_rType,static_cast<css::frame::XDispatch*>(this));
+ if(aRet.hasValue())
+ return aRet;
+ return FmXGridPeer::queryInterface(_rType);
+}
+
+Reference< css::frame::XDispatch > SAL_CALL SbaXGridPeer::queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags)
+{
+ if ( ( aURL.Complete == ".uno:GridSlots/BrowserAttribs" ) || ( aURL.Complete == ".uno:GridSlots/RowHeight" )
+ || ( aURL.Complete == ".uno:GridSlots/ColumnAttribs" ) || ( aURL.Complete == ".uno:GridSlots/ColumnWidth" )
+ )
+ {
+ return static_cast<css::frame::XDispatch*>(this);
+ }
+
+ return FmXGridPeer::queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+}
+
+IMPL_LINK_NOARG( SbaXGridPeer, OnDispatchEvent, void*, void )
+{
+ VclPtr< SbaGridControl > pGrid = GetAs< SbaGridControl >();
+ if ( !pGrid ) // if this fails, we were disposing before arriving here
+ return;
+
+ if ( !Application::IsMainThread() )
+ {
+ // still not in the main thread (see SbaXGridPeer::dispatch). post an event, again
+ // without moving the special even to the back of the queue
+ pGrid->PostUserEvent( LINK( this, SbaXGridPeer, OnDispatchEvent ) );
+ }
+ else
+ {
+ DispatchArgs aArgs = m_aDispatchArgs.front();
+ m_aDispatchArgs.pop();
+
+ SbaXGridPeer::dispatch( aArgs.aURL, aArgs.aArgs );
+ }
+}
+
+SbaXGridPeer::DispatchType SbaXGridPeer::classifyDispatchURL( const URL& _rURL )
+{
+ DispatchType eURLType = dtUnknown;
+ if ( _rURL.Complete == ".uno:GridSlots/BrowserAttribs" )
+ eURLType = dtBrowserAttribs;
+ else if ( _rURL.Complete == ".uno:GridSlots/RowHeight" )
+ eURLType = dtRowHeight;
+ else if ( _rURL.Complete == ".uno:GridSlots/ColumnAttribs" )
+ eURLType = dtColumnAttribs;
+ else if ( _rURL.Complete == ".uno:GridSlots/ColumnWidth" )
+ eURLType = dtColumnWidth;
+ return eURLType;
+}
+
+void SAL_CALL SbaXGridPeer::dispatch(const URL& aURL, const Sequence< PropertyValue >& aArgs)
+{
+ VclPtr< SbaGridControl > pGrid = GetAs< SbaGridControl >();
+ if (!pGrid)
+ return;
+
+ if ( !Application::IsMainThread() )
+ {
+ // we're not in the main thread. This is bad, as we want to raise windows here,
+ // and VCL does not like windows to be opened in non-main threads (at least on Win32).
+ // Okay, do this async. No problem with this, as XDispatch::dispatch is defined to be
+ // a one-way method.
+
+ // save the args
+ DispatchArgs aDispatchArgs;
+ aDispatchArgs.aURL = aURL;
+ aDispatchArgs.aArgs = aArgs;
+ m_aDispatchArgs.push( aDispatchArgs );
+
+ // post an event
+ // we use the Window::PostUserEvent here, instead of the application::PostUserEvent
+ // this saves us from keeping track of these events - as soon as the window dies,
+ // the events are deleted automatically. For the application way, we would need to
+ // do this ourself.
+ // As we use our grid as window, and the grid dies before we die, this should be no problem.
+ pGrid->PostUserEvent( LINK( this, SbaXGridPeer, OnDispatchEvent ) );
+ return;
+ }
+
+ SolarMutexGuard aGuard;
+ sal_Int16 nColId = -1;
+ for (const PropertyValue& rArg : aArgs)
+ {
+ if (rArg.Name == "ColumnViewPos")
+ {
+ nColId = pGrid->GetColumnIdFromViewPos(::comphelper::getINT16(rArg.Value));
+ break;
+ }
+ if (rArg.Name == "ColumnModelPos")
+ {
+ nColId = pGrid->GetColumnIdFromModelPos(::comphelper::getINT16(rArg.Value));
+ break;
+ }
+ if (rArg.Name == "ColumnId")
+ {
+ nColId = ::comphelper::getINT16(rArg.Value);
+ break;
+ }
+ }
+
+ DispatchType eURLType = classifyDispatchURL( aURL );
+
+ if ( dtUnknown == eURLType )
+ return;
+
+ // notify any status listeners that the dialog is now active (well, about to be active)
+ MapDispatchToBool::const_iterator aThisURLState = m_aDispatchStates.emplace( eURLType, true ).first;
+ NotifyStatusChanged( aURL, nullptr );
+
+ // execute the dialog
+ switch ( eURLType )
+ {
+ case dtBrowserAttribs:
+ pGrid->SetBrowserAttrs();
+ break;
+
+ case dtRowHeight:
+ pGrid->SetRowHeight();
+ break;
+
+ case dtColumnAttribs:
+ {
+ OSL_ENSURE(nColId != -1, "SbaXGridPeer::dispatch : invalid parameter !");
+ if (nColId != -1)
+ break;
+ pGrid->SetColAttrs(nColId);
+ }
+ break;
+
+ case dtColumnWidth:
+ {
+ OSL_ENSURE(nColId != -1, "SbaXGridPeer::dispatch : invalid parameter !");
+ if (nColId != -1)
+ break;
+ pGrid->SetColWidth(nColId);
+ }
+ break;
+
+ case dtUnknown:
+ break;
+ }
+
+ // notify any status listeners that the dialog vanished
+ m_aDispatchStates.erase( aThisURLState );
+ NotifyStatusChanged( aURL, nullptr );
+}
+
+void SAL_CALL SbaXGridPeer::addStatusListener(const Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL)
+{
+ ::comphelper::OInterfaceContainerHelper3< css::frame::XStatusListener >* pCont
+ = m_aStatusListeners.getContainer(aURL);
+ if (!pCont)
+ m_aStatusListeners.addInterface(aURL,xControl);
+ else
+ pCont->addInterface(xControl);
+ NotifyStatusChanged(aURL, xControl);
+}
+
+void SAL_CALL SbaXGridPeer::removeStatusListener(const Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL)
+{
+ ::comphelper::OInterfaceContainerHelper3< css::frame::XStatusListener >* pCont = m_aStatusListeners.getContainer(aURL);
+ if ( pCont )
+ pCont->removeInterface(xControl);
+}
+
+Sequence< Type > SAL_CALL SbaXGridPeer::getTypes()
+{
+ return comphelper::concatSequences(
+ FmXGridPeer::getTypes(),
+ Sequence { cppu::UnoType<css::frame::XDispatch>::get() });
+}
+
+UNO3_GETIMPLEMENTATION2_IMPL(SbaXGridPeer, FmXGridPeer);
+
+VclPtr<FmGridControl> SbaXGridPeer::imp_CreateControl(vcl::Window* pParent, WinBits nStyle)
+{
+ return VclPtr<SbaGridControl>::Create( m_xContext, pParent, this, nStyle);
+}
+
+// SbaGridHeader
+
+SbaGridHeader::SbaGridHeader(BrowseBox* pParent)
+ :FmGridHeader(pParent, WB_STDHEADERBAR | WB_DRAG)
+ ,DragSourceHelper(this)
+{
+}
+
+SbaGridHeader::~SbaGridHeader()
+{
+ disposeOnce();
+}
+
+void SbaGridHeader::dispose()
+{
+ DragSourceHelper::dispose();
+ FmGridHeader::dispose();
+}
+
+void SbaGridHeader::StartDrag( sal_Int8 _nAction, const Point& _rPosPixel )
+{
+ SolarMutexGuard aGuard;
+ // in the new DnD API, the solar mutex is not locked when StartDrag is called
+
+ ImplStartColumnDrag( _nAction, _rPosPixel );
+}
+
+void SbaGridHeader::MouseButtonDown( const MouseEvent& _rMEvt )
+{
+ if (_rMEvt.IsLeft())
+ if (_rMEvt.GetClicks() != 2)
+ {
+ // the base class will start a column move here, which we don't want to allow
+ // (at the moment. If we store relative positions with the columns, we can allow column moves...)
+
+ }
+
+ FmGridHeader::MouseButtonDown(_rMEvt);
+}
+
+void SbaGridHeader::ImplStartColumnDrag(sal_Int8 _nAction, const Point& _rMousePos)
+{
+ sal_uInt16 nId = GetItemId(_rMousePos);
+ bool bResizingCol = false;
+ if (HEADERBAR_ITEM_NOTFOUND != nId)
+ {
+ tools::Rectangle aColRect = GetItemRect(nId);
+ aColRect.AdjustLeft(nId ? 3 : 0 ); // the handle col (nId == 0) does not have a left margin for resizing
+ aColRect.AdjustRight( -3 );
+ bResizingCol = !aColRect.Contains(_rMousePos);
+ }
+ if (bResizingCol)
+ return;
+
+ // force the base class to end its drag mode
+ EndTracking(TrackingEventFlags::Cancel | TrackingEventFlags::End);
+
+ // because we have 3d-buttons the select handler is called from MouseButtonUp, but StartDrag
+ // occurs earlier (while the mouse button is down)
+ // so for optical reasons we select the column before really starting the drag operation.
+ notifyColumnSelect(nId);
+
+ static_cast<SbaGridControl*>(GetParent())->StartDrag(_nAction,
+ Point(
+ _rMousePos.X() + GetPosPixel().X(), // we aren't left-justified with our parent, in contrast to the data window
+ _rMousePos.Y() - GetSizePixel().Height()
+ )
+ );
+}
+
+void SbaGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, weld::Menu& rMenu,
+ weld::Menu& rInsertMenu, weld::Menu& rChangeMenu,
+ weld::Menu& rShowMenu)
+{
+ FmGridHeader::PreExecuteColumnContextMenu(nColId, rMenu, rInsertMenu, rChangeMenu, rShowMenu);
+
+ // some items are valid only if the db isn't readonly
+ bool bDBIsReadOnly = static_cast<SbaGridControl*>(GetParent())->IsReadOnlyDB();
+
+ if (bDBIsReadOnly)
+ {
+ rMenu.set_visible("hide", false);
+ rMenu.set_sensitive("hide", false);
+ rMenu.set_visible("show", false);
+ rMenu.set_sensitive("show", false);
+ }
+
+ // prepend some new items
+ bool bColAttrs = (nColId != sal_uInt16(-1)) && (nColId != 0);
+ if ( !bColAttrs || bDBIsReadOnly)
+ return;
+
+ sal_uInt16 nPos = 0;
+ sal_uInt16 nModelPos = static_cast<SbaGridControl*>(GetParent())->GetModelColumnPos(nColId);
+ Reference< XPropertySet > xField = static_cast<SbaGridControl*>(GetParent())->getField(nModelPos);
+
+ if ( xField.is() )
+ {
+ switch( ::comphelper::getINT32(xField->getPropertyValue(PROPERTY_TYPE)) )
+ {
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::SQLNULL:
+ case DataType::OBJECT:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::REF:
+ break;
+ default:
+ rMenu.insert(nPos++, "colattrset", DBA_RES(RID_STR_COLUMN_FORMAT),
+ nullptr, nullptr, nullptr, TRISTATE_INDET);
+ rMenu.insert_separator(nPos++, "separator1");
+ }
+ }
+
+ rMenu.insert(nPos++, "colwidth", DBA_RES(RID_STR_COLUMN_WIDTH),
+ nullptr, nullptr, nullptr, TRISTATE_INDET);
+ rMenu.insert_separator(nPos++, "separator2");
+}
+
+void SbaGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const weld::Menu& rMenu, const OString& rExecutionResult)
+{
+ if (rExecutionResult == "colwidth")
+ static_cast<SbaGridControl*>(GetParent())->SetColWidth(nColId);
+ else if (rExecutionResult == "colattrset")
+ static_cast<SbaGridControl*>(GetParent())->SetColAttrs(nColId);
+ else
+ FmGridHeader::PostExecuteColumnContextMenu(nColId, rMenu, rExecutionResult);
+}
+
+// SbaGridControl
+SbaGridControl::SbaGridControl(Reference< XComponentContext > const & _rM,
+ vcl::Window* pParent, FmXGridPeer* _pPeer, WinBits nBits)
+ :FmGridControl(_rM,pParent, _pPeer, nBits)
+ ,m_pMasterListener(nullptr)
+ ,m_nAsyncDropEvent(nullptr)
+ ,m_bActivatingForDrop(false)
+{
+}
+
+SbaGridControl::~SbaGridControl()
+{
+ disposeOnce();
+}
+
+void SbaGridControl::dispose()
+{
+ if (m_nAsyncDropEvent)
+ Application::RemoveUserEvent(m_nAsyncDropEvent);
+ m_nAsyncDropEvent = nullptr;
+ FmGridControl::dispose();
+}
+
+VclPtr<BrowserHeader> SbaGridControl::imp_CreateHeaderBar(BrowseBox* pParent)
+{
+ return VclPtr<SbaGridHeader>::Create(pParent);
+}
+
+CellController* SbaGridControl::GetController(sal_Int32 nRow, sal_uInt16 nCol)
+{
+ if ( m_bActivatingForDrop )
+ return nullptr;
+
+ return FmGridControl::GetController(nRow, nCol);
+}
+
+void SbaGridControl::PreExecuteRowContextMenu(weld::Menu& rMenu)
+{
+ FmGridControl::PreExecuteRowContextMenu(rMenu);
+
+ sal_uInt16 nPos = 0;
+
+ if (!IsReadOnlyDB())
+ {
+ rMenu.insert(nPos++, "tableattr", DBA_RES(RID_STR_TABLE_FORMAT),
+ nullptr, nullptr, nullptr, TRISTATE_INDET);
+ rMenu.insert(nPos++, "rowheight", DBA_RES(RID_STR_ROW_HEIGHT),
+ nullptr, nullptr, nullptr, TRISTATE_INDET);
+ rMenu.insert_separator(nPos++, "separator1");
+ }
+
+ if ( GetSelectRowCount() > 0 )
+ {
+ rMenu.insert(nPos++, "copy", DBA_RES(RID_STR_COPY),
+ nullptr, nullptr, nullptr, TRISTATE_INDET);
+ rMenu.insert_separator(nPos++, "separator2");
+ }
+}
+
+SvNumberFormatter* SbaGridControl::GetDatasourceFormatter()
+{
+ Reference< css::util::XNumberFormatsSupplier > xSupplier = ::dbtools::getNumberFormats(::dbtools::getConnection(Reference< XRowSet > (getDataSource(),UNO_QUERY)), true, getContext());
+
+ SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier );
+ if ( !pSupplierImpl )
+ return nullptr;
+
+ SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter();
+ return pFormatter;
+}
+
+void SbaGridControl::SetColWidth(sal_uInt16 nColId)
+{
+ // get the (UNO) column model
+ sal_uInt16 nModelPos = GetModelColumnPos(nColId);
+ Reference< XIndexAccess > xCols = GetPeer()->getColumns();
+ Reference< XPropertySet > xAffectedCol;
+ if (xCols.is() && (nModelPos != sal_uInt16(-1)))
+ xAffectedCol.set(xCols->getByIndex(nModelPos), css::uno::UNO_QUERY);
+
+ if (!xAffectedCol.is())
+ return;
+
+ Any aWidth = xAffectedCol->getPropertyValue(PROPERTY_WIDTH);
+ sal_Int32 nCurWidth = aWidth.hasValue() ? ::comphelper::getINT32(aWidth) : -1;
+
+ DlgSize aDlgColWidth(GetFrameWeld(), nCurWidth, false);
+ if (aDlgColWidth.run() != RET_OK)
+ return;
+
+ sal_Int32 nValue = aDlgColWidth.GetValue();
+ Any aNewWidth;
+ if (-1 == nValue)
+ { // set to default
+ Reference< XPropertyState > xPropState(xAffectedCol, UNO_QUERY);
+ if (xPropState.is())
+ {
+ try { aNewWidth = xPropState->getPropertyDefault(PROPERTY_WIDTH); } catch(Exception&) { } ;
+ }
+ }
+ else
+ aNewWidth <<= nValue;
+ try { xAffectedCol->setPropertyValue(PROPERTY_WIDTH, aNewWidth); } catch(Exception&) { } ;
+}
+
+void SbaGridControl::SetRowHeight()
+{
+ Reference< XPropertySet > xCols(GetPeer()->getColumns(), UNO_QUERY);
+ if (!xCols.is())
+ return;
+
+ Any aHeight = xCols->getPropertyValue(PROPERTY_ROW_HEIGHT);
+ sal_Int32 nCurHeight = aHeight.hasValue() ? ::comphelper::getINT32(aHeight) : -1;
+
+ DlgSize aDlgRowHeight(GetFrameWeld(), nCurHeight, true);
+ if (aDlgRowHeight.run() != RET_OK)
+ return;
+
+ sal_Int32 nValue = aDlgRowHeight.GetValue();
+ Any aNewHeight;
+ if (sal_Int16(-1) == nValue)
+ { // set to default
+ Reference< XPropertyState > xPropState(xCols, UNO_QUERY);
+ if (xPropState.is())
+ {
+ try
+ {
+ aNewHeight = xPropState->getPropertyDefault(PROPERTY_ROW_HEIGHT);
+ }
+ catch(Exception&)
+ { }
+ }
+ }
+ else
+ aNewHeight <<= nValue;
+ try
+ {
+ xCols->setPropertyValue(PROPERTY_ROW_HEIGHT, aNewHeight);
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "setPropertyValue: PROPERTY_ROW_HEIGHT throws an exception");
+ }
+}
+
+void SbaGridControl::SetColAttrs(sal_uInt16 nColId)
+{
+ SvNumberFormatter* pFormatter = GetDatasourceFormatter();
+ if (!pFormatter)
+ return;
+
+ sal_uInt16 nModelPos = GetModelColumnPos(nColId);
+
+ // get the (UNO) column model
+ Reference< XIndexAccess > xCols = GetPeer()->getColumns();
+ Reference< XPropertySet > xAffectedCol;
+ if (xCols.is() && (nModelPos != sal_uInt16(-1)))
+ xAffectedCol.set(xCols->getByIndex(nModelPos), css::uno::UNO_QUERY);
+
+ // get the field the column is bound to
+ Reference< XPropertySet > xField = getField(nModelPos);
+ ::dbaui::callColumnFormatDialog(xAffectedCol,xField,pFormatter,GetFrameWeld());
+}
+
+void SbaGridControl::SetBrowserAttrs()
+{
+ Reference< XPropertySet > xGridModel(GetPeer()->getColumns(), UNO_QUERY);
+ if (!xGridModel.is())
+ return;
+
+ try
+ {
+ Reference< XComponentContext > xContext = getContext();
+ css::uno::Sequence<css::uno::Any> aArguments{
+ Any(comphelper::makePropertyValue("IntrospectedObject", xGridModel)),
+ Any(comphelper::makePropertyValue("ParentWindow", VCLUnoHelper::GetInterface(this)))
+ };
+ Reference<XExecutableDialog> xExecute(xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.form.ControlFontDialog",
+ aArguments, xContext), css::uno::UNO_QUERY_THROW);
+ xExecute->execute();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SbaGridControl::PostExecuteRowContextMenu(const OString& rExecutionResult)
+{
+ if (rExecutionResult == "tableattr")
+ SetBrowserAttrs();
+ else if (rExecutionResult == "rowheight")
+ SetRowHeight();
+ else if (rExecutionResult == "copy")
+ CopySelectedRowsToClipboard();
+ else
+ FmGridControl::PostExecuteRowContextMenu(rExecutionResult);
+}
+
+void SbaGridControl::Select()
+{
+ // Some selection has changed ...
+ FmGridControl::Select();
+
+ if (m_pMasterListener)
+ m_pMasterListener->SelectionChanged();
+}
+
+void SbaGridControl::ActivateCell(sal_Int32 nRow, sal_uInt16 nCol, bool bSetCellFocus /*= sal_True*/ )
+{
+ FmGridControl::ActivateCell(nRow, nCol, bSetCellFocus);
+ if (m_pMasterListener)
+ m_pMasterListener->CellActivated();
+}
+
+void SbaGridControl::DeactivateCell(bool bUpdate /*= sal_True*/)
+{
+ FmGridControl::DeactivateCell(bUpdate);
+ if (m_pMasterListener)
+ m_pMasterListener->CellDeactivated();
+}
+
+void SbaGridControl::onRowChange()
+{
+ if ( m_pMasterListener )
+ m_pMasterListener->RowChanged();
+}
+
+void SbaGridControl::onColumnChange()
+{
+ if ( m_pMasterListener )
+ m_pMasterListener->ColumnChanged();
+}
+
+Reference< XPropertySet > SbaGridControl::getField(sal_uInt16 nModelPos)
+{
+ Reference< XPropertySet > xEmptyReturn;
+ try
+ {
+ // first get the name of the column
+ Reference< XIndexAccess > xCols = GetPeer()->getColumns();
+ if ( xCols.is() && xCols->getCount() > nModelPos )
+ {
+ Reference< XPropertySet > xCol(xCols->getByIndex(nModelPos),UNO_QUERY);
+ if ( xCol.is() )
+ xEmptyReturn.set(xCol->getPropertyValue(PROPERTY_BOUNDFIELD),UNO_QUERY);
+ }
+ else
+ OSL_FAIL("SbaGridControl::getField getColumns returns NULL or ModelPos is > than count!");
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "SbaGridControl::getField Exception occurred");
+ }
+
+ return xEmptyReturn;
+}
+
+bool SbaGridControl::IsReadOnlyDB() const
+{
+ // assume yes if anything fails
+ bool bDBIsReadOnly = true;
+
+ try
+ {
+ // the db is the implemented by the parent of the grid control's model ...
+ Reference< XChild > xColumns(GetPeer()->getColumns(), UNO_QUERY);
+ if (xColumns.is())
+ {
+ Reference< XRowSet > xDataSource(xColumns->getParent(), UNO_QUERY);
+ ::dbtools::ensureRowSetConnection( xDataSource, getContext(), nullptr );
+ Reference< XChild > xConn(::dbtools::getConnection(xDataSource),UNO_QUERY);
+ if (xConn.is())
+ {
+ // ... and the RO-flag simply is implemented by a property
+ Reference< XPropertySet > xDbProps(xConn->getParent(), UNO_QUERY);
+ if (xDbProps.is())
+ {
+ Reference< XPropertySetInfo > xInfo = xDbProps->getPropertySetInfo();
+ if (xInfo->hasPropertyByName(PROPERTY_ISREADONLY))
+ bDBIsReadOnly = ::comphelper::getBOOL(xDbProps->getPropertyValue(PROPERTY_ISREADONLY));
+ }
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "SbaGridControl::IsReadOnlyDB Exception occurred");
+ }
+
+ return bDBIsReadOnly;
+}
+
+void SbaGridControl::MouseButtonDown( const BrowserMouseEvent& rMEvt)
+{
+ sal_Int32 nRow = GetRowAtYPosPixel(rMEvt.GetPosPixel().Y());
+ sal_uInt16 nColPos = GetColumnAtXPosPixel(rMEvt.GetPosPixel().X());
+ sal_uInt16 nViewPos = (nColPos == BROWSER_INVALIDID) ? sal_uInt16(-1) : nColPos-1;
+ // 'the handle column' and 'no valid column' will both result in a view position of -1 !
+
+ bool bHitEmptySpace = (nRow > GetRowCount()) || (nViewPos == sal_uInt16(-1));
+
+ if (bHitEmptySpace && (rMEvt.GetClicks() == 2) && rMEvt.IsMod1())
+ Control::MouseButtonDown(rMEvt);
+ else
+ FmGridControl::MouseButtonDown(rMEvt);
+}
+
+void SbaGridControl::StartDrag( sal_Int8 _nAction, const Point& _rPosPixel )
+{
+ SolarMutexGuard aGuard;
+ // in the new DnD API, the solar mutex is not locked when StartDrag is called
+
+ bool bHandled = false;
+
+ do
+ {
+ // determine if dragging is allowed
+ // (Yes, this is controller (not view) functionality. But collecting and evaluating all the
+ // information necessary via UNO would be quite difficult (if not impossible) so
+ // my laziness says 'do it here'...)
+ sal_Int32 nRow = GetRowAtYPosPixel(_rPosPixel.Y());
+ sal_uInt16 nColPos = GetColumnAtXPosPixel(_rPosPixel.X());
+ sal_uInt16 nViewPos = (nColPos == BROWSER_INVALIDID) ? sal_uInt16(-1) : nColPos-1;
+ // 'the handle column' and 'no valid column' will both result in a view position of -1 !
+
+ bool bCurrentRowVirtual = IsCurrentAppending() && IsModified();
+ // the current row doesn't really exist: the user's appending a new one and already has entered some data,
+ // so the row contains data which has no counter part within the data source
+
+ sal_Int32 nCorrectRowCount = GetRowCount();
+ if (GetOptions() & DbGridControlOptions::Insert)
+ --nCorrectRowCount; // there is an empty row for inserting records
+ if (bCurrentRowVirtual)
+ --nCorrectRowCount;
+
+ if ((nColPos == BROWSER_INVALIDID) || (nRow >= nCorrectRowCount))
+ break;
+
+ bool bHitHandle = (nColPos == 0);
+
+ // check which kind of dragging has to be initiated
+ if ( bHitHandle // the handle column
+ // AND
+ && ( GetSelectRowCount() // at least one row is selected
+ // OR
+ || ( (nRow >= 0) // a row below the header
+ && !bCurrentRowVirtual // we aren't appending a new record
+ && (nRow != GetCurrentPos()) // a row which is not the current one
+ ) // OR
+ || ( (0 == GetSelectRowCount()) // no rows selected
+ && (-1 == nRow) // hit the header
+ )
+ )
+ )
+ { // => start dragging the row
+ if (GetDataWindow().IsMouseCaptured())
+ GetDataWindow().ReleaseMouse();
+
+ if (0 == GetSelectRowCount())
+ // no rows selected, but here in this branch
+ // -> the user started dragging the upper left corner, which symbolizes the whole table
+ SelectAll();
+
+ getMouseEvent().Clear();
+ implTransferSelectedRows(static_cast<sal_Int16>(nRow), false);
+
+ bHandled = true;
+ }
+ else if ( (nRow < 0) // the header
+ && (!bHitHandle) // non-handle column
+ && (nViewPos < GetViewColCount()) // valid (existing) column
+ )
+ { // => start dragging the column
+ if (GetDataWindow().IsMouseCaptured())
+ GetDataWindow().ReleaseMouse();
+
+ getMouseEvent().Clear();
+ DoColumnDrag(nViewPos);
+
+ bHandled = true;
+ }
+ else if ( !bHitHandle // non-handle column
+ && (nRow >= 0) // non-header row
+ )
+ { // => start dragging the field content
+ if (GetDataWindow().IsMouseCaptured())
+ GetDataWindow().ReleaseMouse();
+
+ getMouseEvent().Clear();
+ DoFieldDrag(nViewPos, static_cast<sal_Int16>(nRow));
+
+ bHandled = true;
+ }
+ }
+ while (false);
+
+ if (!bHandled)
+ FmGridControl::StartDrag(_nAction, _rPosPixel);
+}
+
+void SbaGridControl::DoColumnDrag(sal_uInt16 nColumnPos)
+{
+ Reference< XPropertySet > xDataSource = getDataSource();
+ OSL_ENSURE(xDataSource.is(), "SbaGridControl::DoColumnDrag : invalid data source !");
+ ::dbtools::ensureRowSetConnection(Reference< XRowSet >(getDataSource(),UNO_QUERY), getContext(), nullptr);
+
+ Reference< XPropertySet > xAffectedCol;
+ Reference< XPropertySet > xAffectedField;
+ Reference< XConnection > xActiveConnection;
+
+ // determine the field to drag
+ OUString sField;
+ try
+ {
+ xActiveConnection = ::dbtools::getConnection(Reference< XRowSet >(getDataSource(),UNO_QUERY));
+
+ sal_uInt16 nModelPos = GetModelColumnPos(GetColumnIdFromViewPos(nColumnPos));
+ Reference< XIndexContainer > xCols = GetPeer()->getColumns();
+ xAffectedCol.set(xCols->getByIndex(nModelPos),UNO_QUERY);
+ if (xAffectedCol.is())
+ {
+ xAffectedCol->getPropertyValue(PROPERTY_CONTROLSOURCE) >>= sField;
+ xAffectedField.set(xAffectedCol->getPropertyValue(PROPERTY_BOUNDFIELD),UNO_QUERY);
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("SbaGridControl::DoColumnDrag : something went wrong while getting the column");
+ }
+ if (sField.isEmpty())
+ return;
+
+ rtl::Reference<OColumnTransferable> pDataTransfer = new OColumnTransferable(xDataSource, sField, xAffectedField, xActiveConnection, ColumnTransferFormatFlags::FIELD_DESCRIPTOR | ColumnTransferFormatFlags::COLUMN_DESCRIPTOR);
+ pDataTransfer->StartDrag(this, DND_ACTION_COPY | DND_ACTION_LINK);
+}
+
+void SbaGridControl::CopySelectedRowsToClipboard()
+{
+ OSL_ENSURE( GetSelectRowCount() > 0, "SbaGridControl::CopySelectedRowsToClipboard: invalid call!" );
+ implTransferSelectedRows( static_cast<sal_Int16>(FirstSelectedRow()), true );
+}
+
+void SbaGridControl::implTransferSelectedRows( sal_Int16 nRowPos, bool _bTrueIfClipboardFalseIfDrag )
+{
+ Reference< XPropertySet > xForm = getDataSource();
+ OSL_ENSURE( xForm.is(), "SbaGridControl::implTransferSelectedRows: invalid form!" );
+
+ // build the sequence of numbers of selected rows
+ Sequence< Any > aSelectedRows;
+ bool bSelectionBookmarks = true;
+
+ // collect the affected rows
+ if ((GetSelectRowCount() == 0) && (nRowPos >= 0))
+ {
+ aSelectedRows = { Any(static_cast<sal_Int32>(nRowPos + 1)) };
+ bSelectionBookmarks = false;
+ }
+ else if ( !IsAllSelected() && GetSelectRowCount() )
+ {
+ aSelectedRows = getSelectionBookmarks();
+ bSelectionBookmarks = true;
+ }
+
+ try
+ {
+ rtl::Reference<ODataClipboard> pTransfer = new ODataClipboard( xForm, aSelectedRows, bSelectionBookmarks, getContext() );
+
+ if ( _bTrueIfClipboardFalseIfDrag )
+ pTransfer->CopyToClipboard( this );
+ else
+ pTransfer->StartDrag(this, DND_ACTION_COPY | DND_ACTION_LINK);
+ }
+ catch(Exception&)
+ {
+ }
+}
+
+void SbaGridControl::DoFieldDrag(sal_uInt16 nColumnPos, sal_Int16 nRowPos)
+{
+ // the only thing to do here is dragging the pure cell text
+ // the old implementation copied a SBA_FIELDDATAEXCHANGE_FORMAT, too, (which was rather expensive to obtain),
+ // but we have no client for this DnD format anymore (the mail part of SO 5.2 was the only client)
+
+ try
+ {
+ OUString sCellText;
+ Reference< XGridFieldDataSupplier > xFieldData(GetPeer());
+ Sequence<sal_Bool> aSupportingText = xFieldData->queryFieldDataType(cppu::UnoType<decltype(sCellText)>::get());
+ if (aSupportingText.getConstArray()[nColumnPos])
+ {
+ Sequence< Any> aCellContents = xFieldData->queryFieldData(nRowPos, cppu::UnoType<decltype(sCellText)>::get());
+ sCellText = ::comphelper::getString(aCellContents.getConstArray()[nColumnPos]);
+ ::svt::OStringTransfer::StartStringDrag(sCellText, this, DND_ACTION_COPY);
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("SbaGridControl::DoFieldDrag : could not retrieve the cell's contents !");
+ return;
+ }
+
+}
+
+ namespace {
+
+/// unary_function Functor object for class ZZ returntype is void
+ struct SbaGridControlPrec
+ {
+ bool operator()(const DataFlavorExVector::value_type& _aType)
+ {
+ switch (_aType.mnSotId)
+ {
+ case SotClipboardFormatId::DBACCESS_TABLE: // table descriptor
+ case SotClipboardFormatId::DBACCESS_QUERY: // query descriptor
+ case SotClipboardFormatId::DBACCESS_COMMAND: // SQL command
+ return true;
+ default: break;
+ }
+ return false;
+ }
+ };
+
+ }
+
+sal_Int8 SbaGridControl::AcceptDrop( const BrowserAcceptDropEvent& rEvt )
+{
+ sal_Int8 nAction = DND_ACTION_NONE;
+
+ // we need a valid connection
+ if (!::dbtools::getConnection(Reference< XRowSet > (getDataSource(),UNO_QUERY)).is())
+ return nAction;
+
+ if ( IsDropFormatSupported( SotClipboardFormatId::STRING ) )
+ do
+ { // odd construction, but spares us a lot of (explicit ;) goto's
+
+ if (!GetEmptyRow().is())
+ // without an empty row we're not in update mode
+ break;
+
+ const sal_Int32 nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false);
+ const sal_uInt16 nCol = GetColumnId(GetColumnAtXPosPixel(rEvt.maPosPixel.X()));
+
+ sal_Int32 nCorrectRowCount = GetRowCount();
+ if (GetOptions() & DbGridControlOptions::Insert)
+ --nCorrectRowCount; // there is an empty row for inserting records
+ if (IsCurrentAppending())
+ --nCorrectRowCount; // the current data record doesn't really exist, we are appending a new one
+
+ if ( (nCol == BROWSER_INVALIDID) || (nRow >= nCorrectRowCount) || (nCol == 0) )
+ // no valid cell under the mouse cursor
+ break;
+
+ tools::Rectangle aRect = GetCellRect(nRow, nCol, false);
+ if (!aRect.Contains(rEvt.maPosPixel))
+ // not dropped within a cell (a cell isn't as wide as the column - the are small spaces)
+ break;
+
+ if ((IsModified() || (GetCurrentRow().is() && GetCurrentRow()->IsModified())) && (GetCurrentPos() != nRow))
+ // there is a current and modified row or cell and he text is to be dropped into another one
+ break;
+
+ CellControllerRef xCurrentController = Controller();
+ if (xCurrentController.is() && xCurrentController->IsValueChangedFromSaved() && ((nRow != GetCurRow()) || (nCol != GetCurColumnId())))
+ // the current controller is modified and the user wants to drop in another cell -> no chance
+ // (when leaving the modified cell an error may occur - this is deadly while dragging)
+ break;
+
+ Reference< XPropertySet > xField = getField(GetModelColumnPos(nCol));
+ if (!xField.is())
+ // the column is not valid bound (for instance a binary field)
+ break;
+
+ try
+ {
+ if (::comphelper::getBOOL(xField->getPropertyValue(PROPERTY_ISREADONLY)))
+ break;
+ }
+ catch (const Exception& )
+ {
+ // assume RO
+ break;
+ }
+
+ try
+ {
+ // assume that text can be dropped into a field if the column has a css::awt::XTextComponent interface
+ Reference< XIndexAccess > xColumnControls(GetPeer());
+ if (xColumnControls.is())
+ {
+ Reference< css::awt::XTextComponent > xColControl(
+ xColumnControls->getByIndex(GetViewColumnPos(nCol)),
+ css::uno::UNO_QUERY);
+ if (xColControl.is())
+ {
+ m_bActivatingForDrop = true;
+ GoToRowColumnId(nRow, nCol);
+ m_bActivatingForDrop = false;
+
+ nAction = DND_ACTION_COPY;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ } while (false);
+
+ if(nAction != DND_ACTION_COPY && GetEmptyRow().is())
+ {
+ const DataFlavorExVector& _rFlavors = GetDataFlavors();
+ if(std::any_of(_rFlavors.begin(),_rFlavors.end(),SbaGridControlPrec()))
+ nAction = DND_ACTION_COPY;
+ }
+
+ return (DND_ACTION_NONE != nAction) ? nAction : FmGridControl::AcceptDrop(rEvt);
+}
+
+sal_Int8 SbaGridControl::ExecuteDrop( const BrowserExecuteDropEvent& rEvt )
+{
+ // we need some properties of our data source
+ Reference< XPropertySet > xDataSource = getDataSource();
+ if (!xDataSource.is())
+ return DND_ACTION_NONE;
+
+ // we need a valid connection
+ if (!::dbtools::getConnection(Reference< XRowSet > (xDataSource,UNO_QUERY)).is())
+ return DND_ACTION_NONE;
+
+ if ( IsDropFormatSupported( SotClipboardFormatId::STRING ) )
+ {
+ sal_Int32 nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false);
+ sal_uInt16 nCol = GetColumnAtXPosPixel(rEvt.maPosPixel.X());
+
+ sal_Int32 nCorrectRowCount = GetRowCount();
+ if (GetOptions() & DbGridControlOptions::Insert)
+ --nCorrectRowCount; // there is an empty row for inserting records
+ if (IsCurrentAppending())
+ --nCorrectRowCount; // the current data record doesn't really exist, we are appending a new one
+
+ OSL_ENSURE((nCol != BROWSER_INVALIDID) && (nRow < nCorrectRowCount), "SbaGridControl::Drop : dropped on an invalid position !");
+ // AcceptDrop should have caught this
+
+ // from now we work with ids instead of positions
+ nCol = GetColumnId(nCol);
+
+ GoToRowColumnId(nRow, nCol);
+ if (!IsEditing())
+ ActivateCell();
+
+ CellControllerRef xCurrentController = Controller();
+ EditCellController* pController = dynamic_cast<EditCellController*>(xCurrentController.get());
+ if (!pController)
+ return DND_ACTION_NONE;
+
+ // get the dropped string
+ TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable );
+ OUString sDropped;
+ if ( !aDropped.GetString( SotClipboardFormatId::STRING, sDropped ) )
+ return DND_ACTION_NONE;
+
+ IEditImplementation* pEditImplementation = pController->GetEditImplementation();
+ pEditImplementation->SetText(sDropped);
+ // SetText itself doesn't call a Modify as it isn't a user interaction
+ pController->Modify();
+
+ return DND_ACTION_COPY;
+ }
+
+ if(GetEmptyRow().is())
+ {
+ const DataFlavorExVector& _rFlavors = GetDataFlavors();
+ if( std::any_of(_rFlavors.begin(),_rFlavors.end(), SbaGridControlPrec()) )
+ {
+ TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable );
+ m_aDataDescriptor = ODataAccessObjectTransferable::extractObjectDescriptor(aDropped);
+ if (m_nAsyncDropEvent)
+ Application::RemoveUserEvent(m_nAsyncDropEvent);
+ m_nAsyncDropEvent = Application::PostUserEvent(LINK(this, SbaGridControl, AsynchDropEvent), nullptr, true);
+ return DND_ACTION_COPY;
+ }
+ }
+
+ return DND_ACTION_NONE;
+}
+
+Reference< XPropertySet > SbaGridControl::getDataSource() const
+{
+ Reference< XPropertySet > xReturn;
+
+ Reference< XChild > xColumns(GetPeer()->getColumns(), UNO_QUERY);
+ if (xColumns.is())
+ xReturn.set(xColumns->getParent(), UNO_QUERY);
+
+ return xReturn;
+}
+
+IMPL_LINK_NOARG(SbaGridControl, AsynchDropEvent, void*, void)
+{
+ m_nAsyncDropEvent = nullptr;
+
+ Reference< XPropertySet > xDataSource = getDataSource();
+ if ( xDataSource.is() )
+ {
+ bool bCountFinal = false;
+ xDataSource->getPropertyValue(PROPERTY_ISROWCOUNTFINAL) >>= bCountFinal;
+ if ( !bCountFinal )
+ setDataSource(nullptr); // detach from grid control
+ Reference< XResultSetUpdate > xResultSetUpdate(xDataSource,UNO_QUERY);
+ rtl::Reference<ODatabaseImportExport> pImExport = new ORowSetImportExport(GetFrameWeld(),xResultSetUpdate,m_aDataDescriptor, getContext());
+ Hide();
+ try
+ {
+ pImExport->initialize(m_aDataDescriptor);
+ if (m_pMasterListener)
+ m_pMasterListener->BeforeDrop();
+ if(!pImExport->Read())
+ {
+ OUString sError = DBA_RES(STR_NO_COLUMNNAME_MATCHING);
+ throwGenericSQLException(sError,nullptr);
+ }
+ if (m_pMasterListener)
+ m_pMasterListener->AfterDrop();
+ Show();
+ }
+ catch(const SQLException& e)
+ {
+ if (m_pMasterListener)
+ m_pMasterListener->AfterDrop();
+ Show();
+ ::dbtools::showError( ::dbtools::SQLExceptionInfo(e), VCLUnoHelper::GetInterface(this), getContext() );
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ if (m_pMasterListener)
+ m_pMasterListener->AfterDrop();
+ Show();
+ }
+ if ( !bCountFinal )
+ setDataSource(Reference< XRowSet >(xDataSource,UNO_QUERY));
+ }
+ m_aDataDescriptor.clear();
+}
+
+OUString SbaGridControl::GetAccessibleObjectDescription( AccessibleBrowseBoxObjType eObjType,sal_Int32 _nPosition) const
+{
+ OUString sRet;
+ if ( AccessibleBrowseBoxObjType::BrowseBox == eObjType )
+ {
+ SolarMutexGuard aGuard;
+ sRet = DBA_RES(STR_DATASOURCE_GRIDCONTROL_DESC);
+ }
+ else
+ sRet = FmGridControl::GetAccessibleObjectDescription( eObjType,_nPosition);
+ return sRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/sbamultiplex.cxx b/dbaccess/source/ui/browser/sbamultiplex.cxx
new file mode 100644
index 000000000..8bf7ed747
--- /dev/null
+++ b/dbaccess/source/ui/browser/sbamultiplex.cxx
@@ -0,0 +1,528 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sbamultiplex.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+using namespace dbaui;
+
+// the listener multiplexers
+
+// XStatusListener
+SbaXStatusMultiplexer::SbaXStatusMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXStatusMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::frame::XStatusListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::frame::XStatusListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXStatusMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+
+void SAL_CALL SbaXStatusMultiplexer::statusChanged(const css::frame::FeatureStateEvent& e)
+{
+ m_aLastKnownStatus = e;
+ m_aLastKnownStatus.Source = &m_rParent;
+ notifyEach( &XStatusListener::statusChanged, m_aLastKnownStatus );
+}
+
+// LoadListener
+SbaXLoadMultiplexer::SbaXLoadMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXLoadMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::form::XLoadListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::form::XLoadListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXLoadMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+void SAL_CALL SbaXLoadMultiplexer::loaded(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XLoadListener::loaded, aMulti );
+}
+void SAL_CALL SbaXLoadMultiplexer::unloaded(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XLoadListener::unloaded, aMulti );
+}
+
+void SAL_CALL SbaXLoadMultiplexer::unloading(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XLoadListener::unloading, aMulti );
+}
+
+void SAL_CALL SbaXLoadMultiplexer::reloading(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XLoadListener::reloading, aMulti );
+}
+
+void SAL_CALL SbaXLoadMultiplexer::reloaded(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XLoadListener::reloaded, aMulti );
+}
+
+
+// css::sdbc::XRowSetListener
+SbaXRowSetMultiplexer::SbaXRowSetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXRowSetMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::sdbc::XRowSetListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::sdbc::XRowSetListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXRowSetMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+void SAL_CALL SbaXRowSetMultiplexer::cursorMoved(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XRowSetListener::cursorMoved, aMulti );
+}
+
+void SAL_CALL SbaXRowSetMultiplexer::rowChanged(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XRowSetListener::rowChanged, aMulti );
+}
+
+void SAL_CALL SbaXRowSetMultiplexer::rowSetChanged(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XRowSetListener::rowSetChanged, aMulti );
+}
+
+// css::sdb::XRowSetApproveListener
+SbaXRowSetApproveMultiplexer::SbaXRowSetApproveMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXRowSetApproveMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::sdb::XRowSetApproveListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::sdb::XRowSetApproveListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXRowSetApproveMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+sal_Bool SAL_CALL SbaXRowSetApproveMultiplexer::approveCursorMove(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ bool bResult = true;
+ while (bResult && aIt.hasMoreElements())
+ bResult = aIt.next()->approveCursorMove(aMulti);
+ return bResult;
+}
+
+sal_Bool SAL_CALL SbaXRowSetApproveMultiplexer::approveRowChange(const css::sdb::RowChangeEvent& e)
+{
+ css::sdb::RowChangeEvent aMulti(e);
+ aMulti.Source = &m_rParent;
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ bool bResult = true;
+ while (bResult && aIt.hasMoreElements())
+ bResult = aIt.next()->approveRowChange(aMulti);
+ return bResult;
+}
+
+sal_Bool SAL_CALL SbaXRowSetApproveMultiplexer::approveRowSetChange(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ bool bResult = true;
+ while (bResult && aIt.hasMoreElements())
+ bResult = aIt.next()->approveRowSetChange(aMulti);
+ return bResult;
+}
+
+// css::sdb::XSQLErrorListener
+SbaXSQLErrorMultiplexer::SbaXSQLErrorMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXSQLErrorMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::sdb::XSQLErrorListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::sdb::XSQLErrorListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXSQLErrorMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+void SAL_CALL SbaXSQLErrorMultiplexer::errorOccured(const css::sdb::SQLErrorEvent& e)
+{
+ css::sdb::SQLErrorEvent aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XSQLErrorListener::errorOccured, aMulti );
+}
+
+// css::form::XDatabaseParameterListener
+SbaXParameterMultiplexer::SbaXParameterMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXParameterMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::form::XDatabaseParameterListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::form::XDatabaseParameterListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXParameterMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+sal_Bool SAL_CALL SbaXParameterMultiplexer::approveParameter(const css::form::DatabaseParameterEvent& e)
+{
+ css::form::DatabaseParameterEvent aMulti(e);
+ aMulti.Source = &m_rParent;
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ bool bResult = true;
+ while (bResult && aIt.hasMoreElements())
+ bResult = aIt.next()->approveParameter(aMulti);
+ return bResult;
+}
+
+// css::form::XSubmitListener
+SbaXSubmitMultiplexer::SbaXSubmitMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXSubmitMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::form::XSubmitListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::form::XSubmitListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXSubmitMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+
+
+sal_Bool SAL_CALL SbaXSubmitMultiplexer::approveSubmit(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ bool bResult = true;
+ while (bResult && aIt.hasMoreElements())
+ bResult = aIt.next()->approveSubmit(aMulti);
+ return bResult;
+}
+
+// css::form::XResetListener
+SbaXResetMultiplexer::SbaXResetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXResetMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::form::XResetListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::form::XResetListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXResetMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+
+sal_Bool SAL_CALL SbaXResetMultiplexer::approveReset(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ ::comphelper::OInterfaceIteratorHelper3 aIt(*this);
+ bool bResult = true;
+ while (bResult && aIt.hasMoreElements())
+ bResult = aIt.next()->approveReset(aMulti);
+ return bResult;
+}
+
+void SAL_CALL SbaXResetMultiplexer::resetted(const css::lang::EventObject& e)
+{
+ css::lang::EventObject aMulti(e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XResetListener::resetted, aMulti );
+}
+
+// css::beans::XPropertyChangeListener
+SbaXPropertyChangeMultiplexer::SbaXPropertyChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,m_aListeners(rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXPropertyChangeMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::beans::XPropertyChangeListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::beans::XPropertyChangeListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXPropertyChangeMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+void SAL_CALL SbaXPropertyChangeMultiplexer::propertyChange(const css::beans::PropertyChangeEvent& e)
+{
+ ::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>* pListeners = m_aListeners.getContainer(e.PropertyName);
+ if (pListeners)
+ Notify(*pListeners, e);
+
+ /* do the notification for the unspecialized listeners, too */
+ pListeners = m_aListeners.getContainer(OUString());
+ if (pListeners)
+ Notify(*pListeners, e);
+}
+
+void SbaXPropertyChangeMultiplexer::addInterface(const OUString& rName,
+ const css::uno::Reference< css::beans::XPropertyChangeListener > & rListener)
+{
+ m_aListeners.addInterface(rName, rListener);
+}
+
+void SbaXPropertyChangeMultiplexer::removeInterface(const OUString& rName,
+ const css::uno::Reference< css::beans::XPropertyChangeListener > & rListener)
+{
+ m_aListeners.removeInterface(rName, rListener);
+}
+
+void SbaXPropertyChangeMultiplexer::disposeAndClear()
+{
+ css::lang::EventObject aEvt(m_rParent);
+ m_aListeners.disposeAndClear(aEvt);
+}
+
+sal_Int32 SbaXPropertyChangeMultiplexer::getOverallLen() const
+{
+ sal_Int32 nLen = 0;
+ const std::vector< OUString > aContained = m_aListeners.getContainedTypes();
+ for ( OUString const & s : aContained)
+ {
+ ::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>* pListeners = m_aListeners.getContainer(s);
+ if (!pListeners)
+ continue;
+ nLen += pListeners->getLength();
+ }
+ return nLen;
+}
+
+void SbaXPropertyChangeMultiplexer::Notify(::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e)
+{
+ css::beans::PropertyChangeEvent aMulti(e);
+ aMulti.Source = &m_rParent;
+ rListeners.notifyEach( &XPropertyChangeListener::propertyChange, aMulti );
+}
+
+// css::beans::XVetoableChangeListener
+SbaXVetoableChangeMultiplexer::SbaXVetoableChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,m_aListeners(rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXVetoableChangeMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::beans::XVetoableChangeListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::beans::XVetoableChangeListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXVetoableChangeMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+void SAL_CALL SbaXVetoableChangeMultiplexer::vetoableChange(const css::beans::PropertyChangeEvent& e)
+{
+ ::comphelper::OInterfaceContainerHelper3<css::beans::XVetoableChangeListener>* pListeners = m_aListeners.getContainer(e.PropertyName);
+ if (pListeners)
+ Notify(*pListeners, e);
+
+ /* do the notification for the unspecialized listeners, too */
+ pListeners = m_aListeners.getContainer(OUString());
+ if (pListeners)
+ Notify(*pListeners, e);
+}
+
+void SbaXVetoableChangeMultiplexer::addInterface(const OUString& rName,
+ const css::uno::Reference< css::beans::XVetoableChangeListener > & rListener)
+{
+ m_aListeners.addInterface(rName, rListener);
+}
+
+void SbaXVetoableChangeMultiplexer::removeInterface(const OUString& rName,
+ const css::uno::Reference< css::beans::XVetoableChangeListener > & rListener)
+{
+ m_aListeners.removeInterface(rName, rListener);
+}
+
+void SbaXVetoableChangeMultiplexer::disposeAndClear()
+{
+ css::lang::EventObject aEvt(m_rParent);
+ m_aListeners.disposeAndClear(aEvt);
+}
+
+sal_Int32 SbaXVetoableChangeMultiplexer::getOverallLen() const
+{
+ sal_Int32 nLen = 0;
+ const std::vector< OUString > aContained = m_aListeners.getContainedTypes();
+ for ( OUString const & s : aContained)
+ {
+ ::comphelper::OInterfaceContainerHelper3<XVetoableChangeListener>* pListeners = m_aListeners.getContainer(s);
+ if (!pListeners)
+ continue;
+ nLen += pListeners->getLength();
+ }
+ return nLen;
+}
+
+void SbaXVetoableChangeMultiplexer::Notify(::comphelper::OInterfaceContainerHelper3<XVetoableChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e)
+{
+ css::beans::PropertyChangeEvent aMulti(e);
+ aMulti.Source = &m_rParent;
+ rListeners.notifyEach( &XVetoableChangeListener::vetoableChange, aMulti );
+}
+
+// css::beans::XPropertiesChangeListener
+SbaXPropertiesChangeMultiplexer::SbaXPropertiesChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex)
+ :OSbaWeakSubObject(rSource)
+ ,OInterfaceContainerHelper3(_rMutex)
+{
+}
+
+css::uno::Any SAL_CALL SbaXPropertiesChangeMultiplexer::queryInterface(const css::uno::Type& _rType)
+{
+ css::uno::Any aReturn = OSbaWeakSubObject::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::beans::XPropertiesChangeListener* >(this),
+ static_cast< css::lang::XEventListener* >(static_cast< css::beans::XPropertiesChangeListener* >(this))
+ );
+
+ return aReturn;
+}
+void SAL_CALL SbaXPropertiesChangeMultiplexer::disposing(const css::lang::EventObject& )
+{
+}
+
+void SbaXPropertiesChangeMultiplexer::propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent>& aEvts)
+{
+ // the SbaXPropertiesChangeMultiplexer doesn't care about the property names a listener logs on for, it simply
+ // forwards _all_ changes to _all_ listeners
+
+ css::uno::Sequence< css::beans::PropertyChangeEvent> aMulti(aEvts);
+ for (css::beans::PropertyChangeEvent & rEvent : asNonConstRange(aMulti))
+ rEvent.Source = &m_rParent;
+
+ notifyEach( &css::beans::XPropertiesChangeListener::propertiesChange, aMulti );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/browser/unodatbr.cxx b/dbaccess/source/ui/browser/unodatbr.cxx
new file mode 100644
index 000000000..b993fac97
--- /dev/null
+++ b/dbaccess/source/ui/browser/unodatbr.cxx
@@ -0,0 +1,3819 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <browserids.hxx>
+#include <core_resource.hxx>
+#include <helpids.h>
+#include <dbtreelistbox.hxx>
+#include "dbtreemodel.hxx"
+#include <strings.hrc>
+#include <imageprovider.hxx>
+#include <sbagrid.hxx>
+#include <strings.hxx>
+#include <UITools.hxx>
+#include <unodatbr.hxx>
+
+#include <com/sun/star/awt/MouseWheelBehavior.hpp>
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/form/XReset.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/i18n/Collator.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XDatabaseContext.hpp>
+#include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/ui/XContextMenuInterceptor.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <svl/filenotation.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <svx/databaseregistrationui.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <tools/multisel.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/confignode.hxx>
+#include <vcl/split.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdb::application;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::ui;
+using namespace ::dbtools;
+using namespace ::comphelper;
+using namespace ::svx;
+
+// SbaTableQueryBrowser
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_ODatasourceBrowser_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ SolarMutexGuard aGuard;
+ return cppu::acquire(new ::dbaui::SbaTableQueryBrowser(context));
+}
+
+namespace dbaui
+{
+
+namespace DatabaseObject = css::sdb::application::DatabaseObject;
+namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer;
+
+static void SafeAddPropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
+{
+ Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo();
+ if (xInfo->hasPropertyByName(rPropName))
+ xSet->addPropertyChangeListener(rPropName, pListener);
+}
+
+static void SafeRemovePropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
+{
+ Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo();
+ if (xInfo->hasPropertyByName(rPropName))
+ xSet->removePropertyChangeListener(rPropName, pListener);
+}
+
+OUString SAL_CALL SbaTableQueryBrowser::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.ODatasourceBrowser";
+}
+
+css::uno::Sequence<OUString> SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.DataSourceBrowser" };
+}
+
+SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM)
+ :SbaXDataBrowserController(_rM)
+ ,m_aSelectionListeners( getMutex() )
+ ,m_aContextMenuInterceptors( getMutex() )
+ ,m_aTableCopyHelper(this)
+ ,m_pTreeView(nullptr)
+ ,m_pSplitter(nullptr)
+ ,m_nAsyncDrop(nullptr)
+ ,m_bQueryEscapeProcessing( false )
+ ,m_bShowMenu(false)
+ ,m_bInSuspend(false)
+ ,m_bEnableBrowser(true)
+{
+}
+
+SbaTableQueryBrowser::~SbaTableQueryBrowser()
+{
+ if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
+ {
+ SAL_WARN("dbaccess.ui", "Please check who doesn't dispose this component!");
+ // increment ref count to prevent double call of Dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+ SolarMutexGuard g;
+ m_pTreeView.reset();
+ m_pSplitter.reset();
+}
+
+Any SAL_CALL SbaTableQueryBrowser::queryInterface(const Type& _rType)
+{
+ if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) )
+ {
+ OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" );
+ if ( !!m_aDocScriptSupport && *m_aDocScriptSupport )
+ return Any( Reference< XScriptInvocationContext >( this ) );
+ return Any();
+ }
+
+ Any aReturn = SbaXDataBrowserController::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = SbaTableQueryBrowser_Base::queryInterface(_rType);
+ return aReturn;
+}
+
+Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes( )
+{
+ Sequence< Type > aTypes( ::comphelper::concatSequences(
+ SbaXDataBrowserController::getTypes(),
+ SbaTableQueryBrowser_Base::getTypes()
+ ) );
+
+ OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" );
+ if ( !m_aDocScriptSupport || !*m_aDocScriptSupport )
+ {
+ auto [begin, end] = asNonConstRange(aTypes);
+ auto newEnd = std::remove_if( begin, end,
+ [](const Type& type)
+ { return type == cppu::UnoType<XScriptInvocationContext>::get(); } );
+ aTypes.realloc( std::distance(begin, newEnd) );
+ }
+ return aTypes;
+}
+
+Sequence< sal_Int8 > SAL_CALL SbaTableQueryBrowser::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SAL_CALL SbaTableQueryBrowser::disposing()
+{
+ SolarMutexGuard aGuard;
+ // doin' a lot of VCL stuff here -> lock the SolarMutex
+
+ // kiss our listeners goodbye
+ css::lang::EventObject aEvt(*this);
+ m_aSelectionListeners.disposeAndClear(aEvt);
+ m_aContextMenuInterceptors.disposeAndClear(aEvt);
+
+ if (getBrowserView())
+ {
+ // Need to do some cleanup of the data pointed to the tree view entries before we remove the treeview
+ clearTreeModel();
+ m_pTreeView = nullptr;
+ getBrowserView()->setTreeView(nullptr);
+ }
+
+ // remove ourself as status listener
+ implRemoveStatusListeners();
+
+ // check out from all the objects we are listening
+ // the frame
+ if (m_xCurrentFrameParent.is())
+ m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
+
+ // remove the container listener from the database context
+ try
+ {
+ Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
+ xDatabaseRegistrations->removeDatabaseRegistrationsListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ SbaXDataBrowserController::disposing();
+}
+
+bool SbaTableQueryBrowser::Construct(vcl::Window* pParent)
+{
+ if ( !SbaXDataBrowserController::Construct( pParent ) )
+ return false;
+
+ try
+ {
+ Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
+ xDatabaseRegistrations->addDatabaseRegistrationsListener( this );
+
+ // the collator for the string compares
+ m_xCollator = Collator::create( getORB() );
+ m_xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Construct: could not create (or start listening at) the database context!");
+ }
+
+ // some help ids
+ if (!getBrowserView() || !getBrowserView()->getVclControl())
+ return true;
+
+ // create controls and set sizes
+ const tools::Long nFrameWidth = getBrowserView()->LogicToPixel(::Size(3, 0), MapMode(MapUnit::MapAppFont)).Width();
+
+ m_pSplitter = VclPtr<Splitter>::Create(getBrowserView(),WB_HSCROLL);
+ m_pSplitter->SetPosSizePixel( ::Point(0,0), ::Size(nFrameWidth,0) );
+ m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) );
+
+ m_pTreeView = VclPtr<InterimDBTreeListBox>::Create(getBrowserView());
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ rTreeView.connect_expanding(LINK(this, SbaTableQueryBrowser, OnExpandEntry));
+
+ m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry));
+
+ m_pTreeView->setContextMenuProvider( this );
+ m_pTreeView->setControlActionListener( this );
+ m_pTreeView->SetHelpId(HID_CTL_TREEVIEW);
+
+ // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide
+ m_pSplitter->SetSplitPosPixel(getBrowserView()->LogicToPixel(::Size(80, 0), MapMode(MapUnit::MapAppFont)).Width());
+
+ getBrowserView()->setSplitter(m_pSplitter);
+ getBrowserView()->setTreeView(m_pTreeView);
+
+ // fill view with data
+ rTreeView.set_sort_order(true);
+ rTreeView.set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){
+ return OnTreeEntryCompare(rLeft, rRight);
+ });
+ rTreeView.make_sorted();
+ m_pTreeView->SetSelChangeHdl(LINK(this, SbaTableQueryBrowser, OnSelectionChange));
+ m_pTreeView->show_container();
+
+ // TODO
+ getBrowserView()->getVclControl()->SetHelpId(HID_CTL_TABBROWSER);
+ if (getBrowserView()->getVclControl()->GetHeaderBar())
+ getBrowserView()->getVclControl()->GetHeaderBar()->SetHelpId(HID_DATABROWSE_HEADER);
+ InvalidateFeature(ID_BROWSER_EXPLORER);
+
+ return true;
+}
+
+namespace
+{
+ struct SelectValueByName
+ {
+ const Any& operator()( OUString const& i_name ) const
+ {
+ return m_rCollection.get( i_name );
+ }
+
+ explicit SelectValueByName( ::comphelper::NamedValueCollection const& i_collection )
+ :m_rCollection( i_collection )
+ {
+ }
+
+ ::comphelper::NamedValueCollection const& m_rCollection;
+ };
+}
+
+void SbaTableQueryBrowser::impl_sanitizeRowSetClauses_nothrow()
+{
+ try
+ {
+ Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW );
+ bool bEscapeProcessing = false;
+ OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
+ if ( !bEscapeProcessing )
+ // don't touch or interpret anything if escape processing is disabled
+ return;
+
+ Reference< XSingleSelectQueryComposer > xComposer( createParser_nothrow() );
+ if ( !xComposer.is() )
+ // can't do anything. Already reported via assertion in createParser_nothrow.
+ return;
+
+ // the tables participating in the statement
+ const Reference< XTablesSupplier > xSuppTables( xComposer, UNO_QUERY_THROW );
+ const Reference< XNameAccess > xTableNames( xSuppTables->getTables(), UNO_SET_THROW );
+
+ // the columns participating in the statement
+ const Reference< XColumnsSupplier > xSuppColumns( xComposer, UNO_QUERY_THROW );
+ const Reference< XNameAccess > xColumnNames( xSuppColumns->getColumns(), UNO_SET_THROW );
+
+ // check if the order columns apply to tables which really exist in the statement
+ const Reference< XIndexAccess > xOrderColumns( xComposer->getOrderColumns(), UNO_SET_THROW );
+ const sal_Int32 nOrderColumns( xOrderColumns->getCount() );
+ bool invalidColumn = nOrderColumns == 0;
+ for ( sal_Int32 c=0; ( c < nOrderColumns ) && !invalidColumn; ++c )
+ {
+ const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW );
+ OUString sTableName;
+ OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName );
+ OUString sColumnName;
+ OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName );
+
+ if ( sTableName.isEmpty() )
+ {
+ if ( !xColumnNames->hasByName( sColumnName ) )
+ {
+ invalidColumn = true;
+ break;
+ }
+ }
+ else
+ {
+ if ( !xTableNames->hasByName( sTableName ) )
+ {
+ invalidColumn = true;
+ break;
+ }
+
+ const Reference< XColumnsSupplier > xSuppTableColumns( xTableNames->getByName( sTableName ), UNO_QUERY_THROW );
+ const Reference< XNameAccess > xTableColumnNames( xSuppTableColumns->getColumns(), UNO_SET_THROW );
+ if ( !xTableColumnNames->hasByName( sColumnName ) )
+ {
+ invalidColumn = true;
+ break;
+ }
+ }
+ }
+
+ if ( invalidColumn )
+ {
+ // reset the complete order statement at both the row set and the parser
+ xRowSetProps->setPropertyValue( PROPERTY_ORDER, Any( OUString() ) );
+ xComposer->setOrder( "" );
+ }
+
+ // check if the columns participating in the filter refer to existing tables
+ // TODO: there's no API at all for this. The method which comes nearest to what we need is
+ // "getStructuredFilter", but it returns pure column names only. That is, for a statement like
+ // "SELECT * FROM <table> WHERE <other_table>.<column> = <value>", it will return "<column>". But
+ // there's no API at all to retrieve the information about "<other_table>" - which is what would
+ // be needed here.
+ // That'd be a chance to replace getStructuredFilter with something more reasonable.
+ // So, what really would be handy, is some
+ // XNormalizedFilter getNormalizedFilter();
+ // with
+ // interface XDisjunctiveFilterExpression
+ // {
+ // XConjunctiveFilterTerm getTerm( int index );
+ // }
+ // interface XConjunctiveFilterTerm
+ // {
+ // ComparisonPredicate getPredicate( int index );
+ // }
+ // struct ComparisonPredicate
+ // {
+ // XComparisonOperand Lhs;
+ // SQLFilterOperator Operator;
+ // XComparisonOperand Rhs;
+ // }
+ // interface XComparisonOperand
+ // {
+ // SQLFilterOperand Type;
+ // XPropertySet getColumn();
+ // string getLiteral();
+ // ...
+ // }
+ // enum SQLFilterOperand { Column, Literal, ... }
+ // ... or something like this...
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+bool SbaTableQueryBrowser::InitializeForm( const Reference< XPropertySet > & i_formProperties )
+{
+ if (!m_xCurrentlyDisplayed)
+ return true;
+
+ // this method set all format settings from the original table or query
+ try
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
+ ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" );
+ ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" );
+
+ Reference< XPropertySetInfo > xPSI( pData->xObjectProperties->getPropertySetInfo(), UNO_SET_THROW );
+
+ ::comphelper::NamedValueCollection aPropertyValues;
+
+ const OUString aTransferProperties[] =
+ {
+ OUString(PROPERTY_APPLYFILTER),
+ OUString(PROPERTY_FILTER),
+ OUString(PROPERTY_HAVING_CLAUSE),
+ OUString(PROPERTY_ORDER)
+ };
+ for (const auto & aTransferProperty : aTransferProperties)
+ {
+ if ( !xPSI->hasPropertyByName( aTransferProperty ) )
+ continue;
+ aPropertyValues.put( aTransferProperty, pData->xObjectProperties->getPropertyValue( aTransferProperty ) );
+ }
+
+ std::vector< OUString > aNames( aPropertyValues.getNames() );
+ std::sort(aNames.begin(), aNames.end());
+ Sequence< OUString > aPropNames( comphelper::containerToSequence(aNames) );
+
+ Sequence< Any > aPropValues( aNames.size() );
+ std::transform( aNames.begin(), aNames.end(), aPropValues.getArray(), SelectValueByName( aPropertyValues ) );
+
+ Reference< XMultiPropertySet > xFormMultiSet( i_formProperties, UNO_QUERY_THROW );
+ xFormMultiSet->setPropertyValues( aPropNames, aPropValues );
+
+ impl_sanitizeRowSetClauses_nothrow();
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ return false;
+ }
+
+ return true;
+}
+
+void SbaTableQueryBrowser::initializePreviewMode()
+{
+ if ( getBrowserView() && getBrowserView()->getVclControl() )
+ {
+ getBrowserView()->getVclControl()->AlwaysEnableInput( false );
+ getBrowserView()->getVclControl()->EnableInput( false );
+ getBrowserView()->getVclControl()->ForceHideScrollbars();
+ }
+ Reference< XPropertySet > xDataSourceSet(getRowSet(), UNO_QUERY);
+ if ( xDataSourceSet.is() )
+ {
+ xDataSourceSet->setPropertyValue("AllowInserts",Any(false));
+ xDataSourceSet->setPropertyValue("AllowUpdates",Any(false));
+ xDataSourceSet->setPropertyValue("AllowDeletes",Any(false));
+ }
+}
+
+void SbaTableQueryBrowser::InitializeGridModel(const Reference< css::form::XFormComponent > & xGrid)
+{
+ try
+ {
+ Reference< css::form::XGridColumnFactory > xColFactory(xGrid, UNO_QUERY);
+ Reference< XNameContainer > xColContainer(xGrid, UNO_QUERY);
+ clearGridColumns( xColContainer );
+
+ Reference< XLoadable > xFormAsLoadable;
+ if (xGrid.is())
+ xFormAsLoadable.set(xGrid->getParent(), css::uno::UNO_QUERY);
+ if (xFormAsLoadable.is() && xFormAsLoadable->isLoaded())
+ {
+ // set the formats from the table
+ if (m_xCurrentlyDisplayed)
+ {
+ Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 ));
+ Sequence< Any> aValues(7 + ( m_bPreview ? 5 : 0 ));
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
+ OSL_ENSURE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeGridModel: No table available!" );
+ if ( !pData->xObjectProperties.is() )
+ return;
+
+ OUString* pStringIter = aProperties.getArray();
+ Any* pValueIter = aValues.getArray();
+ if ( m_bPreview )
+ {
+ *pStringIter++ = "AlwaysShowCursor";
+ *pValueIter++ <<= false;
+ *pStringIter++ = PROPERTY_BORDER;
+ *pValueIter++ <<= sal_Int16(0);
+ }
+
+ *pStringIter++ = PROPERTY_FONT;
+ *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_FONT);
+ *pStringIter++ = PROPERTY_TEXTEMPHASIS;
+ *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTEMPHASIS);
+ *pStringIter++ = PROPERTY_TEXTRELIEF;
+ *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTRELIEF);
+ if ( m_bPreview )
+ {
+ *pStringIter++ = "HasNavigationBar";
+ *pValueIter++ <<= false;
+ *pStringIter++ = "HasRecordMarker";
+ *pValueIter++ <<= false;
+ }
+ *pStringIter++ = PROPERTY_ROW_HEIGHT;
+ *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_ROW_HEIGHT);
+ if ( m_bPreview )
+ {
+ *pStringIter++ = "Tabstop";
+ *pValueIter++ <<= false;
+ }
+ *pStringIter++ = PROPERTY_TEXTCOLOR;
+ *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTCOLOR);
+ *pStringIter++ = PROPERTY_TEXTLINECOLOR;
+ *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTLINECOLOR);
+
+ Reference< XMultiPropertySet > xFormMultiSet(xGrid, UNO_QUERY);
+ xFormMultiSet->setPropertyValues(aProperties, aValues);
+ }
+
+ // get the formats supplier of the database we're working with
+ Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormatter()->getNumberFormatsSupplier();
+
+ Reference<XConnection> xConnection;
+ Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
+ xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
+ OSL_ENSURE(xConnection.is(),"A ActiveConnection should normally exists!");
+
+ Reference<XChild> xChild(xConnection,UNO_QUERY);
+ Reference<XPropertySet> xDataSourceProp(xChild->getParent(),UNO_QUERY);
+ bool bSuppressVersionCol = false;
+ OSL_VERIFY( xDataSourceProp->getPropertyValue( PROPERTY_SUPPRESSVERSIONCL ) >>= bSuppressVersionCol );
+
+ // insert the column into the gridcontrol so that we see something :-)
+ OUString aCurrentModelType;
+ Reference<XColumnsSupplier> xSupCols(getRowSet(),UNO_QUERY);
+ Reference<XNameAccess> xColumns = xSupCols->getColumns();
+
+ OUString sDefaultProperty;
+ Reference< XPropertySet > xColumn;
+ Reference< XPropertySetInfo > xColPSI;
+ const Sequence<OUString> aColNames = xColumns->getElementNames();
+ for (const OUString& rName : aColNames)
+ {
+ xColumn.set( xColumns->getByName( rName ), UNO_QUERY_THROW );
+ xColPSI.set( xColumn->getPropertySetInfo(), UNO_SET_THROW );
+
+ // ignore the column when it is a rowversion one
+ if ( bSuppressVersionCol
+ && xColPSI->hasPropertyByName( PROPERTY_ISROWVERSION )
+ && ::cppu::any2bool( xColumn->getPropertyValue( PROPERTY_ISROWVERSION ) )
+ )
+ continue;
+
+ // use the result set column's type to determine the type of grid column to create
+ bool bFormattedIsNumeric = true;
+ sal_Int32 nType = ::comphelper::getINT32( xColumn->getPropertyValue( PROPERTY_TYPE ) );
+
+ std::vector< NamedValue > aInitialValues;
+ std::vector< OUString > aCopyProperties;
+ Any aDefault;
+
+ switch(nType)
+ {
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ {
+ aCurrentModelType = "CheckBox";
+ aInitialValues.emplace_back( "VisualEffect", Any( VisualEffect::FLAT ) );
+ sDefaultProperty = PROPERTY_DEFAULTSTATE;
+
+ sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
+ OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
+ aInitialValues.emplace_back(
+ "TriState",
+ Any( ColumnValue::NO_NULLS != nNullable )
+ );
+ if ( ColumnValue::NO_NULLS == nNullable )
+ aDefault <<= sal_Int16(TRISTATE_FALSE);
+ }
+ break;
+
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ aInitialValues.emplace_back( "MultiLine", Any( true ) );
+ [[fallthrough]];
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ aCurrentModelType = "TextField";
+ sDefaultProperty = PROPERTY_DEFAULTTEXT;
+ break;
+
+ case DataType::VARCHAR:
+ case DataType::CHAR:
+ bFormattedIsNumeric = false;
+ [[fallthrough]];
+ default:
+ aCurrentModelType = "FormattedField";
+ sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT;
+
+ if ( xSupplier.is() )
+ aInitialValues.emplace_back( "FormatsSupplier", Any( xSupplier ) );
+ aInitialValues.emplace_back( "TreatAsNumber", Any( bFormattedIsNumeric ) );
+ aCopyProperties.emplace_back(PROPERTY_FORMATKEY );
+ break;
+ }
+
+ aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, Any( rName ) );
+ OUString sLabel;
+ xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
+ if ( !sLabel.isEmpty() )
+ aInitialValues.emplace_back( PROPERTY_LABEL, Any( sLabel ) );
+ else
+ aInitialValues.emplace_back( PROPERTY_LABEL, Any( rName ) );
+
+ Reference< XPropertySet > xGridCol( xColFactory->createColumn( aCurrentModelType ), UNO_SET_THROW );
+ Reference< XPropertySetInfo > xGridColPSI( xGridCol->getPropertySetInfo(), UNO_SET_THROW );
+
+ // calculate the default
+ if ( xGridColPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) )
+ {
+ aDefault = xColumn->getPropertyValue( PROPERTY_CONTROLDEFAULT );
+ // default value
+ if ( nType == DataType::BIT || nType == DataType::BOOLEAN )
+ {
+ if ( aDefault.hasValue() )
+ aDefault <<= (comphelper::getString(aDefault).toInt32() == 0) ? sal_Int16(TRISTATE_FALSE) : sal_Int16(TRISTATE_TRUE);
+ else
+ aDefault <<= sal_Int16(TRISTATE_INDET);
+ }
+ }
+
+ if ( aDefault.hasValue() )
+ aInitialValues.emplace_back( sDefaultProperty, aDefault );
+
+ // transfer properties from the definition to the UNO-model :
+ aCopyProperties.emplace_back(PROPERTY_HIDDEN );
+ aCopyProperties.emplace_back(PROPERTY_WIDTH );
+
+ // help text to display for the column
+ Any aDescription;
+ if ( xColPSI->hasPropertyByName( PROPERTY_HELPTEXT ) )
+ aDescription = xColumn->getPropertyValue( PROPERTY_HELPTEXT );
+ OUString sTemp;
+ aDescription >>= sTemp;
+ if ( sTemp.isEmpty() )
+ xColumn->getPropertyValue( PROPERTY_DESCRIPTION ) >>= sTemp;
+
+ aDescription <<= sTemp;
+ aInitialValues.emplace_back( PROPERTY_HELPTEXT, aDescription );
+
+ // ... horizontal justify
+ Any aAlign; aAlign <<= sal_Int16( 0 );
+ Any aColAlign( xColumn->getPropertyValue( PROPERTY_ALIGN ) );
+ if ( aColAlign.hasValue() )
+ aAlign <<= sal_Int16( ::comphelper::getINT32( aColAlign ) );
+ aInitialValues.emplace_back( PROPERTY_ALIGN, aAlign );
+
+ // don't allow the mouse to scroll in the cells
+ if ( xGridColPSI->hasPropertyByName( PROPERTY_MOUSE_WHEEL_BEHAVIOR ) )
+ aInitialValues.emplace_back( PROPERTY_MOUSE_WHEEL_BEHAVIOR, Any( MouseWheelBehavior::SCROLL_DISABLED ) );
+
+ // now set all those values
+ for (auto const& property : aInitialValues)
+ {
+ xGridCol->setPropertyValue( property.Name, property.Value );
+ }
+ for (auto const& copyPropertyName : aCopyProperties)
+ xGridCol->setPropertyValue( copyPropertyName, xColumn->getPropertyValue(copyPropertyName) );
+
+ xColContainer->insertByName(rName, Any(xGridCol));
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+static Reference<XPropertySet> getColumnHelper(const weld::TreeView& rTreeView,
+ const weld::TreeIter* pCurrentlyDisplayed,
+ const Reference<XPropertySet>& rxSource)
+{
+ Reference<XPropertySet> xRet;
+ if (pCurrentlyDisplayed)
+ {
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pCurrentlyDisplayed));
+ Reference<XColumnsSupplier> xColumnsSup(pData->xObjectProperties,UNO_QUERY);
+ Reference<XNameAccess> xNames = xColumnsSup->getColumns();
+ OUString aName;
+ rxSource->getPropertyValue(PROPERTY_NAME) >>= aName;
+ if(xNames.is() && xNames->hasByName(aName))
+ xRet.set(xNames->getByName(aName),UNO_QUERY);
+ }
+ return xRet;
+}
+
+void SbaTableQueryBrowser::transferChangedControlProperty(const OUString& _rProperty, const Any& _rNewValue)
+{
+ if (m_xCurrentlyDisplayed)
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
+ Reference< XPropertySet > xObjectProps = pData->xObjectProperties;
+ OSL_ENSURE(xObjectProps.is(),"SbaTableQueryBrowser::transferChangedControlProperty: no table/query object!");
+ if (xObjectProps.is())
+ xObjectProps->setPropertyValue(_rProperty, _rNewValue);
+ }
+}
+
+void SbaTableQueryBrowser::propertyChange(const PropertyChangeEvent& evt)
+{
+ SbaXDataBrowserController::propertyChange(evt);
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+
+ try
+ {
+ Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
+ if (!xSource.is())
+ return;
+ // one of the many properties which require us to update the definition ?
+ // a column's width ?
+ else if (evt.PropertyName == PROPERTY_WIDTH)
+ { // a column width has changed -> update the model
+ // (the update of the view is done elsewhere)
+ Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
+ if(xProp.is())
+ {
+ if(!evt.NewValue.hasValue())
+ xProp->setPropertyValue(PROPERTY_WIDTH,Any(sal_Int32(227)));
+ else
+ xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue);
+ }
+ }
+
+ // a column's 'visible' state ?
+ else if (evt.PropertyName == PROPERTY_HIDDEN)
+ {
+ Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
+ if(xProp.is())
+ xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue);
+ }
+
+ // a columns alignment ?
+ else if (evt.PropertyName == PROPERTY_ALIGN)
+ {
+ Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
+ try
+ {
+ if(xProp.is())
+ {
+ if(evt.NewValue.hasValue())
+ {
+ sal_Int16 nAlign = 0;
+ if(evt.NewValue >>= nAlign)
+ xProp->setPropertyValue(PROPERTY_ALIGN,Any(sal_Int32(nAlign)));
+ else
+ xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue);
+ }
+ else
+ xProp->setPropertyValue(PROPERTY_ALIGN,Any(css::awt::TextAlign::LEFT));
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ // a column's format ?
+ else if ( evt.PropertyName == PROPERTY_FORMATKEY
+ && (TypeClass_LONG == evt.NewValue.getValueTypeClass())
+ )
+ {
+ // update the model (means the definition object)
+ Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
+ if(xProp.is())
+ xProp->setPropertyValue(PROPERTY_FORMATKEY,evt.NewValue);
+ }
+
+ // some table definition properties ?
+ // the height of the rows in the grid ?
+ else if (evt.PropertyName == PROPERTY_ROW_HEIGHT)
+ {
+ if (m_xCurrentlyDisplayed)
+ {
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
+ OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" );
+
+ bool bDefault = !evt.NewValue.hasValue();
+ if (bDefault)
+ pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,Any(sal_Int32(45)));
+ else
+ pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,evt.NewValue);
+ }
+ }
+
+ else if ( evt.PropertyName == PROPERTY_FONT // the font ?
+ || evt.PropertyName == PROPERTY_TEXTCOLOR // the text color ?
+ || evt.PropertyName == PROPERTY_FILTER // the filter ?
+ || evt.PropertyName == PROPERTY_HAVING_CLAUSE // the having clause ?
+ || evt.PropertyName == PROPERTY_ORDER // the sort ?
+ || evt.PropertyName == PROPERTY_APPLYFILTER // the appliance of the filter ?
+ || evt.PropertyName == PROPERTY_TEXTLINECOLOR // the text line color ?
+ || evt.PropertyName == PROPERTY_TEXTEMPHASIS // the text emphasis ?
+ || evt.PropertyName == PROPERTY_TEXTRELIEF // the text relief ?
+ )
+ {
+ transferChangedControlProperty(evt.PropertyName, evt.NewValue);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+sal_Bool SbaTableQueryBrowser::suspend(sal_Bool bSuspend)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( getView() && getView()->IsInModalMode() )
+ return false;
+ bool bRet = false;
+ if ( !m_bInSuspend )
+ {
+ m_bInSuspend = true;
+ if ( rBHelper.bDisposed )
+ throw DisposedException( OUString(), *this );
+
+ bRet = SbaXDataBrowserController::suspend(bSuspend);
+ if ( bRet && getView() )
+ getView()->Hide();
+
+ m_bInSuspend = false;
+ }
+
+ return bRet;
+}
+
+void SAL_CALL SbaTableQueryBrowser::statusChanged( const FeatureStateEvent& _rEvent )
+{
+ // search the external dispatcher causing this call
+ Reference< XDispatch > xSource(_rEvent.Source, UNO_QUERY);
+ bool bFound = false;
+ for (auto & externalFeature : m_aExternalFeatures)
+ {
+ if ( _rEvent.FeatureURL.Complete == externalFeature.second.aURL.Complete)
+ {
+ bFound = true;
+ OSL_ENSURE( xSource.get() == externalFeature.second.xDispatcher.get(), "SbaTableQueryBrowser::statusChanged: inconsistent!" );
+ // update the enabled state
+ externalFeature.second.bEnabled = _rEvent.IsEnabled;
+
+ switch ( externalFeature.first )
+ {
+ case ID_BROWSER_DOCUMENT_DATASOURCE:
+ {
+ // if it's the slot for the document data source, remember the state
+ Sequence< PropertyValue > aDescriptor;
+ bool bProperFormat = _rEvent.State >>= aDescriptor;
+ OSL_ENSURE(bProperFormat, "SbaTableQueryBrowser::statusChanged: need a data access descriptor here!");
+ m_aDocumentDataSource.initializeFrom(aDescriptor);
+
+ OSL_ENSURE( ( m_aDocumentDataSource.has(DataAccessDescriptorProperty::DataSource)
+ || m_aDocumentDataSource.has(DataAccessDescriptorProperty::DatabaseLocation)
+ )
+ && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command)
+ && m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType),
+ "SbaTableQueryBrowser::statusChanged: incomplete descriptor!");
+
+ // check if we know the object which is set as document data source
+ checkDocumentDataSource();
+ }
+ break;
+
+ default:
+ // update the toolbox
+ implCheckExternalSlot( externalFeature.first );
+ break;
+ }
+ break;
+ }
+ }
+
+ OSL_ENSURE(bFound, "SbaTableQueryBrowser::statusChanged: don't know who sent this!");
+}
+
+void SbaTableQueryBrowser::checkDocumentDataSource()
+{
+ std::unique_ptr<weld::TreeIter> xDataSourceEntry;
+ std::unique_ptr<weld::TreeIter> xContainerEntry;
+ std::unique_ptr<weld::TreeIter> xObjectEntry = getObjectEntry(m_aDocumentDataSource, &xDataSourceEntry, &xContainerEntry);
+ bool bKnownDocDataSource = static_cast<bool>(xObjectEntry);
+ if (!bKnownDocDataSource)
+ {
+ if (xDataSourceEntry)
+ {
+ // at least the data source is known
+ if (xContainerEntry)
+ {
+ bKnownDocDataSource = true; // assume we know it.
+ // TODO: should we expand the object container? This may be too expensive just for checking...
+ }
+ else
+ {
+ if (m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType)
+ && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command))
+ { // maybe we have a command to be displayed ?
+ sal_Int32 nCommandType = CommandType::TABLE;
+ m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
+
+ OUString sCommand;
+ m_aDocumentDataSource[DataAccessDescriptorProperty::Command] >>= sCommand;
+
+ bKnownDocDataSource = (CommandType::COMMAND == nCommandType) && (!sCommand.isEmpty());
+ }
+ }
+ }
+ }
+
+ if ( !bKnownDocDataSource )
+ m_aExternalFeatures[ ID_BROWSER_DOCUMENT_DATASOURCE ].bEnabled = false;
+
+ // update the toolbox
+ implCheckExternalSlot(ID_BROWSER_DOCUMENT_DATASOURCE);
+}
+
+void SbaTableQueryBrowser::extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor, OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing)
+{
+ _rDataSource = _rDescriptor.getDataSource();
+ if ( _rDescriptor.has(DataAccessDescriptorProperty::Command) )
+ _rDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand;
+ if ( _rDescriptor.has(DataAccessDescriptorProperty::CommandType) )
+ _rDescriptor[DataAccessDescriptorProperty::CommandType] >>= _rCommandType;
+
+ // escape processing is the only one allowed not to be present
+ _rEscapeProcessing = true;
+ if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing))
+ _rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]);
+}
+
+namespace
+{
+ bool getDataSourceDisplayName_isURL( const OUString& _rDS, OUString& _rDisplayName, OUString& _rUniqueId )
+ {
+ INetURLObject aURL( _rDS );
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ _rDisplayName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
+ _rUniqueId = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ return true;
+ }
+ _rDisplayName = _rDS;
+ _rUniqueId.clear();
+ return false;
+ }
+
+ struct FilterByEntryDataId : public IEntryFilter
+ {
+ OUString sId;
+ explicit FilterByEntryDataId( const OUString& _rId ) : sId( _rId ) { }
+
+ virtual ~FilterByEntryDataId() {}
+
+ virtual bool includeEntry(const void* pEntry) const override;
+ };
+
+ bool FilterByEntryDataId::includeEntry(const void* pUserData) const
+ {
+ const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData);
+ return ( !pData || ( pData->sAccessor == sId ) );
+ }
+}
+
+OUString SbaTableQueryBrowser::getDataSourceAccessor(const weld::TreeIter& rDataSourceEntry) const
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rDataSourceEntry));
+ OSL_ENSURE( pData, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry data!" );
+ OSL_ENSURE( pData->eType == etDatasource, "SbaTableQueryBrowser::getDataSourceAccessor: entry does not denote a data source!" );
+ return !pData->sAccessor.isEmpty() ? pData->sAccessor : GetEntryText(rDataSourceEntry);
+}
+
+std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 nCommandType,
+ std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry, bool bExpandAncestors,
+ const SharedConnection& _rxConnection )
+{
+ if (ppDataSourceEntry)
+ ppDataSourceEntry->reset();
+ if (ppContainerEntry)
+ ppContainerEntry->reset();
+
+ std::unique_ptr<weld::TreeIter> xObject;
+ if ( m_pTreeView )
+ {
+ // look for the data source entry
+ OUString sDisplayName, sDataSourceId;
+ bool bIsDataSourceURL = getDataSourceDisplayName_isURL( _rDataSource, sDisplayName, sDataSourceId );
+ // the display name may differ from the URL for readability reasons
+ // #i33699#
+
+ FilterByEntryDataId aFilter( sDataSourceId );
+ std::unique_ptr<weld::TreeIter> xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter );
+ if (!xDataSource) // check if the data source name is a file location
+ {
+ if ( bIsDataSourceURL )
+ {
+ // special case, the data source is a URL
+ // add new entries to the list box model
+ implAddDatasource( _rDataSource, _rxConnection );
+ xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter );
+ OSL_ENSURE( xDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" );
+ }
+ }
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+
+ if (xDataSource)
+ {
+ if (ppDataSourceEntry)
+ {
+ // (caller wants to have it...)
+ *ppDataSourceEntry = rTreeView.make_iterator(xDataSource.get());
+ }
+
+ // expand if required so
+ if (bExpandAncestors)
+ rTreeView.expand_row(*xDataSource);
+
+ // look for the object container
+ std::unique_ptr<weld::TreeIter> xCommandType;
+ if (nCommandType == CommandType::QUERY || nCommandType == CommandType::TABLE)
+ {
+ xCommandType = rTreeView.make_iterator(xDataSource.get());
+ if (!rTreeView.iter_children(*xCommandType))
+ xCommandType.reset();
+ else
+ {
+ // 1st child is queries, so we're already done if looking for CommandType::QUERY
+
+ // 2nd child is tables
+ if (nCommandType == CommandType::TABLE && !rTreeView.iter_next_sibling(*xCommandType))
+ xCommandType.reset();
+ }
+ }
+
+ if (xCommandType)
+ {
+ if (ppContainerEntry)
+ {
+ // (caller wants to have it...)
+ *ppContainerEntry = rTreeView.make_iterator(xCommandType.get());
+ }
+
+ rTreeView.make_unsorted();
+
+ // expand if required so
+ if (bExpandAncestors)
+ {
+ rTreeView.expand_row(*xCommandType);
+ }
+
+ // look for the object
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString sPath;
+ switch (nCommandType)
+ {
+ case CommandType::TABLE:
+ sPath = _rCommand;
+ nIndex = -1;
+ break;
+
+ case CommandType::QUERY:
+ sPath = _rCommand.getToken( 0, '/', nIndex );
+ break;
+
+ default:
+ assert(false);
+ }
+ xObject = m_pTreeView->GetEntryPosByName(sPath, xCommandType.get());
+ if (xObject)
+ rTreeView.copy_iterator(*xObject, *xCommandType);
+ else
+ xCommandType.reset();
+ if ( nIndex >= 0 )
+ {
+ if (ensureEntryObject(*xObject))
+ {
+ DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xObject));
+ Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
+ sal_Int32 nIndex2 = nIndex;
+ sPath = _rCommand.getToken( 0, '/', nIndex2 );
+ try
+ {
+ if ( xCollection->hasByName(sPath) )
+ {
+ if(!m_pTreeView->GetEntryPosByName(sPath, xObject.get()))
+ {
+ Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY);
+ DBTreeListUserData* pEntryData = new DBTreeListUserData;
+ pEntryData->eType = etQuery;
+ if ( xChild.is() )
+ {
+ pEntryData->eType = etQueryContainer;
+ }
+ implAppendEntry(xObject.get(), sPath, pEntryData);
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
+ }
+ }
+ }
+ }
+ while ( nIndex >= 0 );
+
+ rTreeView.make_sorted();
+ }
+ }
+ }
+ return xObject;
+}
+
+std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor,
+ std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry)
+{
+ // extract the props from the descriptor
+ OUString sDataSource;
+ OUString sCommand;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ bool bEscapeProcessing = true;
+ extractDescriptorProps(rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);
+
+ return getObjectEntry(sDataSource, sCommand, nCommandType, ppDataSourceEntry, ppContainerEntry, false /*bExpandAncestors*/);
+}
+
+void SbaTableQueryBrowser::connectExternalDispatches()
+{
+ Reference< XDispatchProvider > xProvider( getFrame(), UNO_QUERY );
+ OSL_ENSURE(xProvider.is(), "SbaTableQueryBrowser::connectExternalDispatches: no DispatchProvider !");
+ if (!xProvider.is())
+ return;
+
+ if ( m_aExternalFeatures.empty() )
+ {
+ const char* pURLs[] = {
+ ".uno:DataSourceBrowser/DocumentDataSource",
+ ".uno:DataSourceBrowser/FormLetter",
+ ".uno:DataSourceBrowser/InsertColumns",
+ ".uno:DataSourceBrowser/InsertContent",
+ };
+ const sal_uInt16 nIds[] = {
+ ID_BROWSER_DOCUMENT_DATASOURCE,
+ ID_BROWSER_FORMLETTER,
+ ID_BROWSER_INSERTCOLUMNS,
+ ID_BROWSER_INSERTCONTENT
+ };
+
+ for ( size_t i=0; i < SAL_N_ELEMENTS( pURLs ); ++i )
+ {
+ URL aURL;
+ aURL.Complete = OUString::createFromAscii( pURLs[i] );
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aURL );
+ m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( aURL );
+ }
+ }
+
+ for (auto & externalFeature : m_aExternalFeatures)
+ {
+ externalFeature.second.xDispatcher = xProvider->queryDispatch(
+ externalFeature.second.aURL, "_parent", FrameSearchFlag::PARENT
+ );
+
+ if ( externalFeature.second.xDispatcher.get() == static_cast< XDispatch* >( this ) )
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::connectExternalDispatches: this should not happen anymore!" );
+ // (nowadays, the URLs aren't in our SupportedFeatures list anymore, so we should
+ // not supply a dispatcher for this)
+ externalFeature.second.xDispatcher.clear();
+ }
+
+ if ( externalFeature.second.xDispatcher.is() )
+ {
+ try
+ {
+ externalFeature.second.xDispatcher->addStatusListener( this, externalFeature.second.aURL );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ implCheckExternalSlot( externalFeature.first );
+ }
+}
+
+void SbaTableQueryBrowser::implCheckExternalSlot( sal_uInt16 _nId )
+{
+ if ( !m_xMainToolbar.is() )
+ return;
+
+ VclPtr<vcl::Window> pToolboxWindow = VCLUnoHelper::GetWindow( m_xMainToolbar );
+ ToolBox* pToolbox = dynamic_cast< ToolBox* >( pToolboxWindow.get() );
+ OSL_ENSURE( pToolbox, "SbaTableQueryBrowser::implCheckExternalSlot: cannot obtain the toolbox window!" );
+
+ // check if we have to hide this item from the toolbox
+ if ( pToolbox )
+ {
+ bool bHaveDispatcher = m_aExternalFeatures[ _nId ].xDispatcher.is();
+ if ( bHaveDispatcher != pToolbox->IsItemVisible( ToolBoxItemId(_nId) ) )
+ bHaveDispatcher ? pToolbox->ShowItem( ToolBoxItemId(_nId) ) : pToolbox->HideItem( ToolBoxItemId(_nId) );
+ }
+
+ // and invalidate this feature in general
+ InvalidateFeature( _nId );
+}
+
+void SAL_CALL SbaTableQueryBrowser::disposing( const css::lang::EventObject& _rSource )
+{
+ // our frame ?
+ Reference< css::frame::XFrame > xSourceFrame(_rSource.Source, UNO_QUERY);
+ if (m_xCurrentFrameParent.is() && (xSourceFrame == m_xCurrentFrameParent))
+ m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
+ else
+ {
+ // search the external dispatcher causing this call in our map
+ Reference< XDispatch > xSource(_rSource.Source, UNO_QUERY);
+ if(xSource.is())
+ {
+ ExternalFeaturesMap::const_iterator aLoop = m_aExternalFeatures.begin();
+ ExternalFeaturesMap::const_iterator aEnd = m_aExternalFeatures.end();
+ while (aLoop != aEnd)
+ {
+ if ( aLoop->second.xDispatcher.get() == xSource.get() )
+ {
+ sal_uInt16 nSlot = aLoop->first;
+
+ // remove it
+ aLoop = m_aExternalFeatures.erase(aLoop);
+
+ // maybe update the UI
+ implCheckExternalSlot(nSlot);
+
+ // continue, the same XDispatch may be responsible for more than one URL
+ }
+ ++aLoop;
+ }
+ }
+ else
+ {
+ Reference<XConnection> xCon(_rSource.Source, UNO_QUERY);
+ if ( xCon.is() && m_pTreeView )
+ {
+ // our connection is in dispose so we have to find the entry equal with this connection
+ // and close it what means to collapse the entry
+ // get the top-level representing the removed data source
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xDSLoop))
+ {
+ do
+ {
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSLoop));
+ if ( pData && pData->xConnection == xCon )
+ {
+ // we set the connection to null to avoid a second disposing of the connection
+ pData->xConnection.clear();
+ closeConnection(*xDSLoop, false);
+ break;
+ }
+ }
+ while (rTreeView.iter_next_sibling(*xDSLoop));
+ }
+ }
+ else
+ SbaXDataBrowserController::disposing(_rSource);
+ }
+ }
+}
+
+void SbaTableQueryBrowser::implRemoveStatusListeners()
+{
+ // clear all old dispatches
+ for (auto const& externalFeature : m_aExternalFeatures)
+ {
+ if ( externalFeature.second.xDispatcher.is() )
+ {
+ try
+ {
+ externalFeature.second.xDispatcher->removeStatusListener( this, externalFeature.second.aURL );
+ }
+ catch (Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implRemoveStatusListeners: could not remove a status listener!");
+ }
+ }
+ }
+ m_aExternalFeatures.clear();
+}
+
+sal_Bool SAL_CALL SbaTableQueryBrowser::select( const Any& _rSelection )
+{
+ SolarMutexGuard aGuard;
+ // doin' a lot of VCL stuff here -> lock the SolarMutex
+
+ Sequence< PropertyValue > aDescriptorSequence;
+ if (!(_rSelection >>= aDescriptorSequence))
+ throw IllegalArgumentException(OUString(), *this, 1);
+ // TODO: error message
+
+ ODataAccessDescriptor aDescriptor;
+ try
+ {
+ aDescriptor = ODataAccessDescriptor(aDescriptorSequence);
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::select: could not extract the descriptor!");
+ }
+
+ // check the presence of the props we need
+ if ( !(aDescriptor.has(DataAccessDescriptorProperty::DataSource) || aDescriptor.has(DataAccessDescriptorProperty::DatabaseLocation)) || !aDescriptor.has(DataAccessDescriptorProperty::Command) || !aDescriptor.has(DataAccessDescriptorProperty::CommandType))
+ throw IllegalArgumentException(OUString(), *this, 1);
+ // TODO: error message
+
+ return implSelect(aDescriptor,true);
+}
+
+Any SAL_CALL SbaTableQueryBrowser::getSelection( )
+{
+ Any aReturn;
+
+ try
+ {
+ Reference< XLoadable > xLoadable(getRowSet(), UNO_QUERY);
+ if (xLoadable.is() && xLoadable->isLoaded())
+ {
+ Reference< XPropertySet > aFormProps(getRowSet(), UNO_QUERY);
+ ODataAccessDescriptor aDescriptor(aFormProps);
+ // remove properties which are not part of our "selection"
+ aDescriptor.erase(DataAccessDescriptorProperty::Connection);
+ aDescriptor.erase(DataAccessDescriptorProperty::Cursor);
+
+ aReturn <<= aDescriptor.createPropertyValueSequence();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return aReturn;
+}
+
+void SAL_CALL SbaTableQueryBrowser::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
+{
+ m_aSelectionListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL SbaTableQueryBrowser::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
+{
+ m_aSelectionListeners.removeInterface(_rxListener);
+}
+
+void SbaTableQueryBrowser::attachFrame(const Reference< css::frame::XFrame > & _xFrame)
+{
+ implRemoveStatusListeners();
+
+ if (m_xCurrentFrameParent.is())
+ m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
+
+ SbaXDataBrowserController::attachFrame(_xFrame);
+
+ Reference< XFrame > xCurrentFrame( getFrame() );
+ if ( xCurrentFrame.is() )
+ {
+ m_xCurrentFrameParent = xCurrentFrame->findFrame("_parent",FrameSearchFlag::PARENT);
+ if ( m_xCurrentFrameParent.is() )
+ m_xCurrentFrameParent->addFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
+
+ // obtain our toolbox
+ try
+ {
+ Reference< XPropertySet > xFrameProps( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW );
+ Reference< XLayoutManager > xLayouter(
+ xFrameProps->getPropertyValue("LayoutManager"),
+ UNO_QUERY );
+
+ if ( xLayouter.is() )
+ {
+ Reference< XUIElement > xUI(
+ xLayouter->getElement( "private:resource/toolbar/toolbar" ),
+ UNO_SET_THROW );
+ m_xMainToolbar.set(xUI->getRealInterface(), css::uno::UNO_QUERY);
+ OSL_ENSURE( m_xMainToolbar.is(), "SbaTableQueryBrowser::attachFrame: where's my toolbox?" );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ // get the dispatchers for the external slots
+ connectExternalDispatches();
+}
+
+void SbaTableQueryBrowser::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
+{
+ SbaXDataBrowserController::addModelListeners(_xGridControlModel);
+ Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY);
+ if (xSourceSet.is())
+ {
+ xSourceSet->addPropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->addPropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->addPropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->addPropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->addPropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->addPropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
+ }
+
+}
+
+void SbaTableQueryBrowser::removeModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
+{
+ SbaXDataBrowserController::removeModelListeners(_xGridControlModel);
+ Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY);
+ if (xSourceSet.is())
+ {
+ xSourceSet->removePropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
+ xSourceSet->removePropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
+ }
+}
+
+void SbaTableQueryBrowser::RowChanged()
+{
+ if(getBrowserView())
+ {
+ SbaGridControl* pControl = getBrowserView()->getVclControl();
+ if (!pControl->IsEditing())
+ InvalidateFeature(ID_BROWSER_COPY);
+ }
+ SbaXDataBrowserController::RowChanged();
+}
+
+void SbaTableQueryBrowser::ColumnChanged()
+{
+ if(getBrowserView())
+ {
+ SbaGridControl* pControl = getBrowserView()->getVclControl();
+ if (!pControl->IsEditing())
+ InvalidateFeature(ID_BROWSER_COPY);
+ }
+ SbaXDataBrowserController::ColumnChanged();
+}
+
+void SbaTableQueryBrowser::AddColumnListener(const Reference< XPropertySet > & xCol)
+{
+ SbaXDataBrowserController::AddColumnListener(xCol);
+ SafeAddPropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
+ SafeAddPropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
+ SafeAddPropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
+ SafeAddPropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
+}
+
+void SbaTableQueryBrowser::RemoveColumnListener(const Reference< XPropertySet > & xCol)
+{
+ SbaXDataBrowserController::RemoveColumnListener(xCol);
+ SafeRemovePropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
+ SafeRemovePropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
+ SafeRemovePropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
+ SafeRemovePropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
+}
+
+void SbaTableQueryBrowser::criticalFail()
+{
+ SbaXDataBrowserController::criticalFail();
+ unloadAndCleanup( false );
+}
+
+void SbaTableQueryBrowser::LoadFinished(bool _bWasSynch)
+{
+ SbaXDataBrowserController::LoadFinished(_bWasSynch);
+
+ m_sQueryCommand.clear();
+ m_bQueryEscapeProcessing = false;
+
+ if (isValid() && !loadingCancelled())
+ {
+ // did we load a query?
+ bool bTemporary; // needed because we m_bQueryEscapeProcessing is only one bit wide (and we want to pass it by reference)
+ if ( implGetQuerySignature( m_sQueryCommand, bTemporary ) )
+ m_bQueryEscapeProcessing = bTemporary;
+ }
+
+ // if the form has been loaded, this means that our "selection" has changed
+ css::lang::EventObject aEvent( *this );
+ m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent );
+}
+
+bool SbaTableQueryBrowser::getExternalSlotState( sal_uInt16 _nId ) const
+{
+ bool bEnabled = false;
+ ExternalFeaturesMap::const_iterator aPos = m_aExternalFeatures.find( _nId );
+ if ( ( m_aExternalFeatures.end() != aPos ) && aPos->second.xDispatcher.is() )
+ bEnabled = aPos->second.bEnabled;
+ return bEnabled;
+}
+
+FeatureState SbaTableQueryBrowser::GetState(sal_uInt16 nId) const
+{
+ FeatureState aReturn;
+ // (disabled automatically)
+
+ // no chance without a view
+ if (!getBrowserView() || !getBrowserView()->getVclControl())
+ return aReturn;
+
+ switch ( nId )
+ {
+ case ID_TREE_ADMINISTRATE:
+ aReturn.bEnabled = true;
+ return aReturn;
+
+ case ID_BROWSER_CLOSE:
+ // the close button should always be enabled
+ aReturn.bEnabled = !m_bEnableBrowser;
+ return aReturn;
+
+ // "toggle explorer" is always enabled (if we have an explorer)
+ case ID_BROWSER_EXPLORER:
+ aReturn.bEnabled = m_bEnableBrowser;
+ aReturn.bChecked = haveExplorer();
+ return aReturn;
+
+ case ID_BROWSER_REMOVEFILTER:
+ return SbaXDataBrowserController::GetState( nId );
+
+ case ID_BROWSER_COPY:
+ if ( !m_pTreeView->HasChildPathFocus() )
+ // handled below
+ break;
+ [[fallthrough]];
+ case ID_TREE_CLOSE_CONN:
+ case ID_TREE_EDIT_DATABASE:
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator());
+ if (!rTreeView.get_cursor(xCurrentEntry.get()))
+ return aReturn;
+
+ EntryType eType = getEntryType(*xCurrentEntry);
+ if ( eType == etUnknown )
+ return aReturn;
+
+ std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(xCurrentEntry.get());
+ DBTreeListUserData* pDSData
+ = xDataSourceEntry
+ ? weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry))
+ : nullptr;
+
+ if ( nId == ID_TREE_CLOSE_CONN )
+ {
+ aReturn.bEnabled = ( pDSData != nullptr ) && pDSData->xConnection.is();
+ }
+ else if ( nId == ID_TREE_EDIT_DATABASE )
+ {
+ ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( getORB(),
+ "/org.openoffice.Office.DataAccess/Policies/Features/Common" ) );
+ bool bHaveEditDatabase( true );
+ OSL_VERIFY( aConfig.getNodeValue( "EditDatabaseFromDataSourceView" ) >>= bHaveEditDatabase );
+ aReturn.bEnabled = getORB().is() && xDataSourceEntry && bHaveEditDatabase;
+ }
+ else if ( nId == ID_BROWSER_COPY )
+ {
+ aReturn.bEnabled = isEntryCopyAllowed(*xCurrentEntry);
+ }
+
+ return aReturn;
+ }
+ }
+
+ // all slots not handled above are not available if no form is loaded
+ if (!isLoaded())
+ return aReturn;
+
+ try
+ {
+ bool bHandled = false;
+ switch (nId)
+ {
+ case ID_BROWSER_DOCUMENT_DATASOURCE:
+ // the slot is enabled if we have an external dispatcher able to handle it,
+ // and the dispatcher must have enabled the slot in general
+ aReturn.bEnabled = getExternalSlotState( ID_BROWSER_DOCUMENT_DATASOURCE );
+ bHandled = true;
+ break;
+ case ID_BROWSER_REFRESH:
+ aReturn.bEnabled = true;
+ bHandled = true;
+ break;
+ }
+
+ if (bHandled)
+ return aReturn;
+
+ // no chance without valid models
+ if (isValid() && !isValidCursor() && nId != ID_BROWSER_CLOSE)
+ return aReturn;
+
+ switch (nId)
+ {
+ case ID_BROWSER_INSERTCOLUMNS:
+ case ID_BROWSER_INSERTCONTENT:
+ case ID_BROWSER_FORMLETTER:
+ {
+ // the slot is enabled if we have an external dispatcher able to handle it,
+ // and the dispatcher must have enabled the slot in general
+ aReturn.bEnabled = getExternalSlotState( nId );
+
+ // for the Insert* slots, we need at least one selected row
+ if (ID_BROWSER_FORMLETTER != nId)
+ aReturn.bEnabled = aReturn.bEnabled && getBrowserView()->getVclControl()->GetSelectRowCount();
+
+ // disabled for native queries which are not saved within the database
+ Reference< XPropertySet > xDataSource(getRowSet(), UNO_QUERY);
+ try
+ {
+ aReturn.bEnabled = aReturn.bEnabled && xDataSource.is();
+
+ if (xDataSource.is())
+ {
+ sal_Int32 nType = ::comphelper::getINT32(xDataSource->getPropertyValue(PROPERTY_COMMAND_TYPE));
+ aReturn.bEnabled = aReturn.bEnabled &&
+ ( ::comphelper::getBOOL(xDataSource->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) ||
+ (nType == css::sdb::CommandType::QUERY) );
+ }
+ }
+ catch(DisposedException&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: object already disposed!");
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ break;
+
+ case ID_BROWSER_TITLE:
+ {
+ Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
+ sal_Int32 nCommandType = CommandType::TABLE;
+ xProp->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nCommandType;
+ OUString sTitle;
+ switch (nCommandType)
+ {
+ case CommandType::TABLE:
+ sTitle = DBA_RES(STR_TBL_TITLE); break;
+ case CommandType::QUERY:
+ case CommandType::COMMAND:
+ sTitle = DBA_RES(STR_QRY_TITLE); break;
+ default:
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: unknown command type!");
+ }
+ OUString aName;
+ xProp->getPropertyValue(PROPERTY_COMMAND) >>= aName;
+ OUString sObject(aName);
+
+ aReturn.sTitle = sTitle.replaceFirst("#", sObject);
+ aReturn.bEnabled = true;
+ }
+ break;
+ case ID_BROWSER_TABLEATTR:
+ case ID_BROWSER_ROWHEIGHT:
+ case ID_BROWSER_COLATTRSET:
+ case ID_BROWSER_COLWIDTH:
+ aReturn.bEnabled = getBrowserView()->getVclControl() && isValid() && isValidCursor();
+ // aReturn.bEnabled &= getDefinition() && !getDefinition()->GetDatabase()->IsReadOnly();
+ break;
+
+ case ID_BROWSER_COPY:
+ OSL_ENSURE( !m_pTreeView->HasChildPathFocus(), "SbaTableQueryBrowser::GetState( ID_BROWSER_COPY ): this should have been handled above!" );
+ if (getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing())
+ {
+ SbaGridControl* pControl = getBrowserView()->getVclControl();
+ if ( pControl->GetSelectRowCount() )
+ {
+ aReturn.bEnabled = m_aCurrentFrame.isActive();
+ break;
+ }
+ else
+ aReturn.bEnabled = pControl->canCopyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ return SbaXDataBrowserController::GetState(nId);
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return aReturn;
+
+}
+
+void SbaTableQueryBrowser::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& aArgs)
+{
+ switch (nId)
+ {
+ default:
+ SbaXDataBrowserController::Execute(nId,aArgs);
+ break;
+
+ case ID_TREE_EDIT_DATABASE:
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_cursor(xIter.get()))
+ implAdministrate(*xIter);
+ break;
+ }
+ case ID_TREE_CLOSE_CONN:
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_cursor(xIter.get()))
+ {
+ xIter = m_pTreeView->GetRootLevelParent(xIter.get());
+ closeConnection(*xIter);
+ }
+ break;
+ }
+ case ID_TREE_ADMINISTRATE:
+ svx::administrateDatabaseRegistration( getFrameWeld() );
+ break;
+
+ case ID_BROWSER_REFRESH:
+ {
+ if ( !SaveModified( ) )
+ // nothing to do
+ break;
+
+ bool bFullReinit = false;
+ // check if the query signature (if the form is based on a query) has changed
+ if ( !m_sQueryCommand.isEmpty() )
+ {
+ OUString sNewQueryCommand;
+ bool bNewQueryEP;
+
+ bool bIsQuery =
+ implGetQuerySignature( sNewQueryCommand, bNewQueryEP );
+ OSL_ENSURE( bIsQuery, "SbaTableQueryBrowser::Execute: was a query before, but is not anymore?" );
+
+ bFullReinit = ( sNewQueryCommand != m_sQueryCommand ) || ( m_bQueryEscapeProcessing != bNewQueryEP );
+ }
+ if ( !bFullReinit )
+ {
+ // let the base class do a simple reload
+ SbaXDataBrowserController::Execute(nId,aArgs);
+ break;
+ }
+ [[fallthrough]];
+ }
+
+ case ID_BROWSER_REFRESH_REBUILD:
+ {
+ if ( !SaveModified() )
+ // nothing to do
+ break;
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xSelected = m_xCurrentlyDisplayed ?
+ rTreeView.make_iterator(m_xCurrentlyDisplayed.get()) : nullptr;
+
+ // unload
+ unloadAndCleanup( false );
+
+ // reselect the entry
+ if ( xSelected )
+ {
+ implSelect(xSelected.get());
+ }
+ else
+ {
+ Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
+ implSelect(svx::ODataAccessDescriptor(xProp));
+ }
+ }
+ break;
+
+ case ID_BROWSER_EXPLORER:
+ toggleExplorer();
+ break;
+
+ case ID_BROWSER_DOCUMENT_DATASOURCE:
+ implSelect(m_aDocumentDataSource);
+ break;
+
+ case ID_BROWSER_INSERTCOLUMNS:
+ case ID_BROWSER_INSERTCONTENT:
+ case ID_BROWSER_FORMLETTER:
+ if (getBrowserView() && isValidCursor())
+ {
+ // the URL the slot id is assigned to
+ OSL_ENSURE( m_aExternalFeatures.find( nId ) != m_aExternalFeatures.end(),
+ "SbaTableQueryBrowser::Execute( ID_BROWSER_?): how could this ever be enabled?" );
+ URL aParentUrl = m_aExternalFeatures[ nId ].aURL;
+
+ // let the dispatcher execute the slot
+ Reference< XDispatch > xDispatch( m_aExternalFeatures[ nId ].xDispatcher );
+ if (xDispatch.is())
+ {
+ // set the properties for the dispatch
+
+ // first fill the selection
+ SbaGridControl* pGrid = getBrowserView()->getVclControl();
+ MultiSelection* pSelection = const_cast<MultiSelection*>(pGrid->GetSelection());
+ Sequence< Any > aSelection;
+ if ( !pGrid->IsAllSelected() )
+ { // transfer the selected rows only if not all rows are selected
+ // (all rows means the whole table)
+ // #i3832#
+ if (pSelection != nullptr)
+ {
+ aSelection.realloc(pSelection->GetSelectCount());
+ tools::Long nIdx = pSelection->FirstSelected();
+ Any* pSelectionNos = aSelection.getArray();
+ while (nIdx != SFX_ENDOFSELECTION)
+ {
+ *pSelectionNos++ <<= static_cast<sal_Int32>(nIdx + 1);
+ nIdx = pSelection->NextSelected();
+ }
+ }
+ }
+
+ Reference< XResultSet > xCursorClone;
+ try
+ {
+ Reference< XResultSetAccess > xResultSetAccess(getRowSet(),UNO_QUERY);
+ if (xResultSetAccess.is())
+ xCursorClone = xResultSetAccess->createResultSet();
+ }
+ catch(DisposedException&)
+ {
+ SAL_WARN("dbaccess.ui", "Object already disposed!");
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Execute(ID_BROWSER_?): could not clone the cursor!");
+ }
+
+ Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
+
+ try
+ {
+ ODataAccessDescriptor aDescriptor;
+ OUString sDataSourceName;
+ xProp->getPropertyValue(PROPERTY_DATASOURCENAME) >>= sDataSourceName;
+
+ aDescriptor.setDataSource(sDataSourceName);
+ aDescriptor[DataAccessDescriptorProperty::Command] = xProp->getPropertyValue(PROPERTY_COMMAND);
+ aDescriptor[DataAccessDescriptorProperty::CommandType] = xProp->getPropertyValue(PROPERTY_COMMAND_TYPE);
+ aDescriptor[DataAccessDescriptorProperty::Connection] = xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION);
+ aDescriptor[DataAccessDescriptorProperty::Cursor] <<= xCursorClone;
+ if ( aSelection.hasElements() )
+ {
+ aDescriptor[DataAccessDescriptorProperty::Selection] <<= aSelection;
+ aDescriptor[DataAccessDescriptorProperty::BookmarkSelection] <<= false;
+ // these are selection indices
+ // before we change this, all clients have to be adjusted
+ // so that they recognize the new BookmarkSelection property!
+ }
+
+ xDispatch->dispatch(aParentUrl, aDescriptor.createPropertyValueSequence());
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ break;
+
+ case ID_BROWSER_CLOSE:
+ closeTask();
+ // if it's not 0, such an async close is already pending
+ break;
+
+ case ID_BROWSER_COPY:
+ if(m_pTreeView->HasChildPathFocus())
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xCursor(rTreeView.make_iterator());
+ if (rTreeView.get_cursor(xCursor.get()))
+ copyEntry(*xCursor);
+ }
+ else if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing() && getBrowserView()->getVclControl()->GetSelectRowCount() < 1)
+ {
+ SbaGridControl* pControl = getBrowserView()->getVclControl();
+ pControl->copyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
+ }
+ else
+ SbaXDataBrowserController::Execute(nId,aArgs);
+ break;
+ }
+}
+
+void SbaTableQueryBrowser::implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection )
+{
+ OUString a, b, c, d, e;
+ implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection );
+}
+
+void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, OUString& _rDbImage,
+ OUString& _rQueryName, OUString& _rQueryImage, OUString& _rTableName, OUString& _rTableImage,
+ const SharedConnection& _rxConnection)
+{
+ SolarMutexGuard aGuard;
+ // initialize the names/images if necessary
+ if (_rQueryName.isEmpty())
+ _rQueryName = DBA_RES(RID_STR_QUERIES_CONTAINER);
+ if (_rTableName.isEmpty())
+ _rTableName = DBA_RES(RID_STR_TABLES_CONTAINER);
+
+ if (_rQueryImage.isEmpty())
+ _rQueryImage = ImageProvider::getFolderImageId(DatabaseObject::QUERY);
+ if (_rTableImage.isEmpty())
+ _rTableImage = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
+
+ if (_rDbImage.isEmpty())
+ _rDbImage = ImageProvider::getDatabaseImage();
+
+ // add the entry for the data source
+ // special handling for data sources denoted by URLs - we do not want to display this ugly URL, do we?
+ // #i33699#
+ OUString sDSDisplayName, sDataSourceId;
+ getDataSourceDisplayName_isURL( _rDbName, sDSDisplayName, sDataSourceId );
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pDSData = new DBTreeListUserData;
+ pDSData->eType = etDatasource;
+ pDSData->sAccessor = sDataSourceId;
+ pDSData->xConnection = _rxConnection;
+ OUString sId(weld::toId(pDSData));
+
+ std::unique_ptr<weld::TreeIter> xDatasourceEntry(rTreeView.make_iterator());
+ rTreeView.insert(nullptr, -1, &sDSDisplayName, &sId, nullptr, nullptr, false, xDatasourceEntry.get());
+ rTreeView.set_image(*xDatasourceEntry, _rDbImage);
+ rTreeView.set_text_emphasis(*xDatasourceEntry, false, 0);
+
+ // the child for the queries container
+ {
+ DBTreeListUserData* pQueriesData = new DBTreeListUserData;
+ pQueriesData->eType = etQueryContainer;
+ sId = weld::toId(pQueriesData);
+
+ std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator());
+ rTreeView.insert(xDatasourceEntry.get(), -1, &_rQueryName, &sId,
+ nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get());
+ rTreeView.set_image(*xRet, _rQueryImage);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ }
+
+ // the child for the tables container
+ {
+ DBTreeListUserData* pTablesData = new DBTreeListUserData;
+ pTablesData->eType = etTableContainer;
+ sId = weld::toId(pTablesData);
+
+ std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator());
+ rTreeView.insert(xDatasourceEntry.get(), -1, &_rTableName, &sId,
+ nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get());
+ rTreeView.set_image(*xRet, _rTableImage);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ }
+}
+
+void SbaTableQueryBrowser::initializeTreeModel()
+{
+ if (m_xDatabaseContext.is())
+ {
+ OUString aDBImage, aQueriesImage, aTablesImage;
+ OUString sQueriesName, sTablesName;
+
+ // fill the model with the names of the registered datasources
+ const Sequence<OUString> aDatasourceNames = m_xDatabaseContext->getElementNames();
+ for (const OUString& rDatasource : aDatasourceNames)
+ implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() );
+ }
+}
+
+void SbaTableQueryBrowser::populateTree(const Reference<XNameAccess>& _xNameAccess,
+ const weld::TreeIter& rParent,
+ EntryType eEntryType)
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ rTreeView.make_unsorted();
+
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
+ if (pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables
+ pData->xContainer = _xNameAccess;
+
+ try
+ {
+ const Sequence<OUString> aNames = _xNameAccess->getElementNames();
+ for (const OUString& rName : aNames)
+ {
+ if( !m_pTreeView->GetEntryPosByName(rName, &rParent))
+ {
+ DBTreeListUserData* pEntryData = new DBTreeListUserData;
+ pEntryData->eType = eEntryType;
+ if ( eEntryType == etQuery )
+ {
+ Reference<XNameAccess> xChild(_xNameAccess->getByName(rName),UNO_QUERY);
+ if ( xChild.is() )
+ pEntryData->eType = etQueryContainer;
+ }
+ implAppendEntry(&rParent, rName, pEntryData);
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
+ }
+
+ rTreeView.make_sorted();
+}
+
+std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implAppendEntry(const weld::TreeIter* pParent, const OUString& rName, const DBTreeListUserData* pUserData)
+{
+ EntryType eEntryType = pUserData->eType;
+
+ std::unique_ptr<ImageProvider> xImageProvider(getImageProviderFor(pParent));
+
+ OUString aImage = xImageProvider->getImageId(rName, getDatabaseObjectType(eEntryType));
+
+ OUString sId(weld::toId(pUserData));
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xNewEntry(rTreeView.make_iterator());
+ rTreeView.insert(pParent, -1, &rName, &sId, nullptr, nullptr, eEntryType == etQueryContainer, xNewEntry.get());
+ rTreeView.set_image(*xNewEntry, aImage);
+ rTreeView.set_text_emphasis(*xNewEntry, false, 0);
+
+ return xNewEntry;
+}
+
+IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, const weld::TreeIter&, rParent, bool)
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ if (rTreeView.iter_has_child(rParent))
+ {
+ // nothing to do...
+ return true;
+ }
+
+ std::unique_ptr<weld::TreeIter> xFirstParent = m_pTreeView->GetRootLevelParent(&rParent);
+ OSL_ENSURE(xFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!");
+
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
+ assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!");
+
+ if (etTableContainer == pData->eType)
+ {
+ weld::WaitObject aWaitCursor(getFrameWeld());
+
+ // it could be that we already have a connection
+ SharedConnection xConnection;
+ ensureConnection(xFirstParent.get(), xConnection);
+
+ if ( xConnection.is() )
+ {
+ SQLExceptionInfo aInfo;
+ try
+ {
+ Reference< XWarningsSupplier > xWarnings(xConnection, UNO_QUERY);
+ if (xWarnings.is())
+ xWarnings->clearWarnings();
+
+ // first insert the views because the tables can also include
+ // views but that time the bitmap is the wrong one
+ // the nameaccess will be overwritten in populateTree
+ Reference<XViewsSupplier> xViewSup(xConnection,UNO_QUERY);
+ if(xViewSup.is())
+ populateTree( xViewSup->getViews(), rParent, etTableOrView );
+
+ Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY);
+ if(xTabSup.is())
+ {
+ populateTree( xTabSup->getTables(), rParent, etTableOrView );
+ Reference<XContainer> xCont(xTabSup->getTables(),UNO_QUERY);
+ if(xCont.is())
+ // add as listener to know when elements are inserted or removed
+ xCont->addContainerListener(this);
+ }
+
+ if (xWarnings.is())
+ {
+#if 0
+ SQLExceptionInfo aWarnings(xWarnings->getWarnings());
+// Obviously this if test is always false. So to avoid a Clang warning
+// "use of logical '&&' with constant operand" I put this in #if
+// 0. Yeah, I know it is fairly likely nobody will ever read this
+// comment and make a decision what to do here, so I could as well
+// have just binned this...
+ if (aWarnings.isValid() && sal_False)
+ {
+ SQLContext aContext;
+ aContext.Message = DBA_RES(STR_OPENTABLES_WARNINGS);
+ aContext.Details = DBA_RES(STR_OPENTABLES_WARNINGS_DETAILS);
+ aContext.NextException = aWarnings.get();
+ aWarnings = aContext;
+ showError(aWarnings);
+ }
+#endif
+ // TODO: we need a better concept for these warnings:
+ // something like "don't show any warnings for this datasource, again" would be nice
+ // But this requires an extension of the InteractionHandler and an additional property on the data source
+ }
+ }
+ catch(const SQLContext& e) { aInfo = e; }
+ catch(const SQLWarning& e) { aInfo = e; }
+ catch(const SQLException& e) { aInfo = e; }
+ catch(const WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if(e.TargetException >>= aSql)
+ aInfo = aSql;
+ else
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: something strange happened!");
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ if (aInfo.isValid())
+ showError(aInfo);
+ }
+ else
+ return false;
+ // 0 indicates that an error occurred
+ }
+ else
+ {
+ // we have to expand the queries or bookmarks
+ if (ensureEntryObject(rParent))
+ {
+ DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
+ Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
+ populateTree(xCollection, rParent, etQuery);
+ }
+ }
+ return true;
+}
+
+bool SbaTableQueryBrowser::ensureEntryObject(const weld::TreeIter& rEntry)
+{
+ EntryType eType = getEntryType(rEntry);
+
+ // the user data of the entry
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntry));
+ OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!");
+
+ std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(&rEntry);
+
+ bool bSuccess = false;
+ switch (eType)
+ {
+ case etQueryContainer:
+ {
+ if ( pEntryData->xContainer.is() )
+ {
+ // nothing to do
+ bSuccess = true;
+ break;
+ }
+
+ std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
+ if (rTreeView.iter_parent(*xParent))
+ {
+ if (rTreeView.iter_compare(*xParent, *xDataSourceEntry) != 0)
+ {
+ OUString aName(rTreeView.get_text(rEntry));
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xParent));
+ try
+ {
+ Reference< XNameAccess > xNameAccess(pData->xContainer,UNO_QUERY);
+ if ( xNameAccess.is() )
+ pEntryData->xContainer.set(xNameAccess->getByName(aName),UNO_QUERY);
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ bSuccess = pEntryData->xContainer.is();
+ }
+ else
+ {
+ try
+ {
+ Reference< XQueryDefinitionsSupplier > xQuerySup;
+ m_xDatabaseContext->getByName(getDataSourceAccessor(*xDataSourceEntry)) >>= xQuerySup;
+ if (xQuerySup.is())
+ {
+ Reference< XNameAccess > xQueryDefs = xQuerySup->getQueryDefinitions();
+ Reference< XContainer > xCont(xQueryDefs, UNO_QUERY);
+ if (xCont.is())
+ // add as listener to get notified if elements are inserted or removed
+ xCont->addContainerListener(this);
+
+ pEntryData->xContainer = xQueryDefs;
+ bSuccess = pEntryData->xContainer.is();
+ }
+ else {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: no XQueryDefinitionsSupplier interface!");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ break;
+ }
+ default:
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: ooops ... missing some implementation here!");
+ // TODO ...
+ break;
+ }
+ return bSuccess;
+}
+
+bool SbaTableQueryBrowser::implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect)
+{
+ // extract the props
+ OUString sDataSource;
+ OUString sCommand;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ bool bEscapeProcessing = true;
+ extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);
+
+ // select it
+ return implSelect( sDataSource, sCommand, nCommandType, bEscapeProcessing, SharedConnection(), _bSelectDirect );
+}
+
+bool SbaTableQueryBrowser::implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand,
+ const sal_Int32 nCommandType, const bool _bEscapeProcessing, const SharedConnection& _rxConnection)
+{
+ try
+ {
+ Reference<XPropertySet> xProp( getRowSet(), UNO_QUERY_THROW );
+ Reference< XLoadable > xLoadable( xProp, UNO_QUERY_THROW );
+ // the values allowing the RowSet to re-execute
+ xProp->setPropertyValue(PROPERTY_DATASOURCENAME, Any(_rDataSourceName));
+ if(_rxConnection.is())
+ xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( _rxConnection.getTyped() ) );
+
+ // set this _before_ setting the connection, else the rowset would rebuild it ...
+ xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, Any(nCommandType));
+ xProp->setPropertyValue(PROPERTY_COMMAND, Any(_rCommand));
+ xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::Any(_bEscapeProcessing));
+ if ( m_bPreview )
+ {
+ xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, Any(FetchDirection::FORWARD));
+ }
+
+ // the formatter depends on the data source we're working on, so rebuild it here ...
+ initFormatter();
+
+ // switch the grid to design mode while loading
+ getBrowserView()->getGridControl()->setDesignMode(true);
+ InitializeForm( xProp );
+
+ bool bSuccess = true;
+
+ {
+ {
+ Reference< XNameContainer > xColContainer(getFormComponent(), UNO_QUERY);
+ // first we have to clear the grid
+ clearGridColumns(xColContainer);
+ }
+ FormErrorHelper aHelper(this);
+ // load the form
+ bSuccess = reloadForm(xLoadable);
+
+ // initialize the model
+ InitializeGridModel(getFormComponent());
+
+ Any aVal = xProp->getPropertyValue(PROPERTY_ISNEW);
+ if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
+ {
+ // then set the default values and the parameters given from the parent
+ Reference< XReset> xReset(xProp, UNO_QUERY);
+ xReset->reset();
+ }
+
+ if ( m_bPreview )
+ initializePreviewMode();
+
+ LoadFinished(true);
+ }
+
+ InvalidateAll();
+ return bSuccess;
+ }
+ catch( const SQLException& )
+ {
+ Any aException( ::cppu::getCaughtException() );
+ showError( SQLExceptionInfo( aException ) );
+ }
+ catch( const WrappedTargetException& e )
+ {
+ if ( e.TargetException.isExtractableTo( ::cppu::UnoType< SQLException >::get() ) )
+ showError( SQLExceptionInfo( e.TargetException ) );
+ else
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "");
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ InvalidateAll();
+ return false;
+}
+
+bool SbaTableQueryBrowser::implSelect(const OUString& _rDataSourceName, const OUString& _rCommand,
+ const sal_Int32 nCommandType, const bool _bEscapeProcessing,
+ const SharedConnection& _rxConnection,
+ bool _bSelectDirect)
+{
+ if (!_rDataSourceName.getLength() || !_rCommand.getLength() || (-1 == nCommandType))
+ return false;
+
+ std::unique_ptr<weld::TreeIter> xDataSource;
+ std::unique_ptr<weld::TreeIter> xCommandType;
+ std::unique_ptr<weld::TreeIter> xCommand = getObjectEntry( _rDataSourceName, _rCommand, nCommandType, &xDataSource, &xCommandType, true, _rxConnection );
+
+ if (xCommand)
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+
+ bool bSuccess = true;
+ if ( _bSelectDirect )
+ {
+ bSuccess = implSelect(xCommand.get());
+ }
+ else
+ {
+ rTreeView.select(*xCommand);
+ }
+
+ if ( bSuccess )
+ {
+ rTreeView.scroll_to_row(*xCommand);
+ rTreeView.set_cursor(*xCommand);
+ }
+ }
+ else if (!xCommandType)
+ {
+ if (m_xCurrentlyDisplayed)
+ {
+ // tell the old entry (if any) it has been deselected
+ selectPath(m_xCurrentlyDisplayed.get(), false);
+ m_xCurrentlyDisplayed.reset();
+ }
+
+ // we have a command and need to display this in the rowset
+ return implLoadAnything(_rDataSourceName, _rCommand, nCommandType, _bEscapeProcessing, _rxConnection);
+ }
+ return false;
+}
+
+IMPL_LINK_NOARG(SbaTableQueryBrowser, OnSelectionChange, LinkParamNone*, void)
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xSelection(rTreeView.make_iterator());
+ if (!rTreeView.get_selected(xSelection.get()))
+ xSelection.reset();
+ implSelect(xSelection.get());
+}
+
+std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implGetConnectionEntry(const weld::TreeIter& rEntry) const
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator(&rEntry));
+ DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry));
+ while (pEntryData->eType != etDatasource)
+ {
+ rTreeView.iter_parent(*xCurrentEntry);
+ pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry));
+ }
+ return xCurrentEntry;
+}
+
+bool SbaTableQueryBrowser::implSelect(const weld::TreeIter* pEntry)
+{
+ if ( !pEntry )
+ return false;
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pEntry));
+ switch (pEntryData->eType)
+ {
+ case etTableOrView:
+ case etQuery:
+ break;
+ default:
+ // nothing to do
+ return false;
+ }
+
+ OSL_ENSURE(rTreeView.get_iter_depth(*pEntry) >= 2, "SbaTableQueryBrowser::implSelect: invalid entry!");
+
+ // get the entry for the tables or queries
+ std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(pEntry);
+ rTreeView.iter_parent(*xContainer);
+ DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer));
+
+ // get the entry for the datasource
+ std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer);
+ DBTreeListUserData* pConData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xConnection));
+
+ // reinitialize the rowset
+ // but first check if it is necessary
+ // get all old properties
+ Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
+ OUString aOldName;
+ xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName;
+ sal_Int32 nOldType = 0;
+ xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType;
+ Reference<XConnection> xOldConnection(xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
+
+ // the name of the table or query
+ const OUString sSimpleName = rTreeView.get_text(*pEntry);
+ OUStringBuffer sNameBuffer(sSimpleName);
+ if ( etQueryContainer == pContainerData->eType )
+ {
+ std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(xContainer.get());
+ std::unique_ptr<weld::TreeIter> xNextTemp = rTreeView.make_iterator(xTemp.get());
+ if (rTreeView.iter_parent(*xNextTemp))
+ {
+ while (rTreeView.iter_compare(*xNextTemp, *xConnection) != 0)
+ {
+ sNameBuffer.insert(0,'/');
+ sNameBuffer.insert(0, rTreeView.get_text(*xTemp));
+ rTreeView.copy_iterator(*xNextTemp, *xTemp);
+ if (!rTreeView.iter_parent(*xNextTemp))
+ break;
+ }
+ }
+ }
+ OUString aName = sNameBuffer.makeStringAndClear();
+
+ sal_Int32 nCommandType = ( etTableContainer == pContainerData->eType)
+ ? CommandType::TABLE
+ : CommandType::QUERY;
+
+ // check if need to rebuild the rowset
+ bool bRebuild = ( xOldConnection != pConData->xConnection )
+ || ( nOldType != nCommandType )
+ || ( aName != aOldName );
+
+ Reference< css::form::XLoadable > xLoadable = getLoadable();
+ bRebuild |= !xLoadable->isLoaded();
+ bool bSuccess = true;
+ if ( bRebuild )
+ {
+ try
+ {
+ weld::WaitObject aWaitCursor(getFrameWeld());
+
+ // tell the old entry it has been deselected
+ selectPath(m_xCurrentlyDisplayed.get(), false);
+ m_xCurrentlyDisplayed.reset();
+
+ // not really loaded
+ m_xCurrentlyDisplayed = rTreeView.make_iterator(pEntry);
+ // tell the new entry it has been selected
+ selectPath(m_xCurrentlyDisplayed.get());
+
+ // get the name of the data source currently selected
+ ensureConnection(m_xCurrentlyDisplayed.get(), pConData->xConnection);
+
+ if ( !pConData->xConnection.is() )
+ {
+ unloadAndCleanup( false );
+ return false;
+ }
+
+ Reference<XNameAccess> xNameAccess;
+ switch(nCommandType)
+ {
+ case CommandType::TABLE:
+ {
+ // only for tables
+ if ( !pContainerData->xContainer.is() )
+ {
+ Reference<XTablesSupplier> xSup( pConData->xConnection, UNO_QUERY );
+ if(xSup.is())
+ xNameAccess = xSup->getTables();
+
+ pContainerData->xContainer = xNameAccess;
+ }
+ else
+ xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
+ }
+ break;
+ case CommandType::QUERY:
+ {
+ if ( pContainerData->xContainer.is() )
+ xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
+ else
+ {
+ Reference<XQueriesSupplier> xSup( pConData->xConnection, UNO_QUERY );
+ if(xSup.is())
+ xNameAccess = xSup->getQueries();
+ }
+ }
+ break;
+ }
+ OUString sStatus(DBA_RES(CommandType::TABLE == nCommandType ? STR_LOADING_TABLE : STR_LOADING_QUERY));
+ sStatus = sStatus.replaceFirst("$name$", aName);
+ BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sStatus);
+
+ bool bEscapeProcessing = true;
+ if(xNameAccess.is() && xNameAccess->hasByName(sSimpleName))
+ {
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pEntry));
+ if ( !pData->xObjectProperties.is() )
+ {
+ Reference<XInterface> xObject;
+ if(xNameAccess->getByName(sSimpleName) >>= xObject) // remember the table or query object
+ {
+ pData->xObjectProperties.set(xObject, css::uno::UNO_QUERY);
+ // if the query contains a parameterized statement and preview is enabled we won't get any data.
+ if ( nCommandType == CommandType::QUERY && xObject.is() )
+ {
+ Reference<XPropertySet> xObjectProps(xObject,UNO_QUERY);
+ xObjectProps->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bEscapeProcessing;
+ if ( m_bPreview )
+ {
+ OUString sSql;
+ xObjectProps->getPropertyValue(PROPERTY_COMMAND) >>= sSql;
+ Reference< XMultiServiceFactory > xFactory( pConData->xConnection, UNO_QUERY );
+ if (xFactory.is())
+ {
+ try
+ {
+ Reference<XSingleSelectQueryAnalyzer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ if ( xAnalyzer.is() )
+ {
+ xAnalyzer->setQuery(sSql);
+ Reference<XParametersSupplier> xParSup(xAnalyzer,UNO_QUERY);
+ if ( xParSup->getParameters()->getCount() > 0 )
+ {
+ OUString sFilter = " WHERE " + xAnalyzer->getFilter();
+ OUString sReplace = sSql.replaceFirst(sFilter, "");
+ xAnalyzer->setQuery(sReplace);
+ Reference<XSingleSelectQueryComposer> xComposer(xAnalyzer,UNO_QUERY);
+ xComposer->setFilter("0=1");
+ aName = xAnalyzer->getQuery();
+ nCommandType = CommandType::COMMAND;
+ }
+ }
+ }
+ catch (Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ OUString sDataSourceName(getDataSourceAccessor(*xConnection));
+ bSuccess = implLoadAnything( sDataSourceName, aName, nCommandType, bEscapeProcessing, pConData->xConnection );
+ if ( !bSuccess )
+ { // clean up
+ criticalFail();
+ }
+ }
+ catch(const SQLException& e)
+ {
+ showError(SQLExceptionInfo(e));
+ // reset the values
+ xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
+ xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
+ bSuccess = false;
+ }
+ catch(WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if(e.TargetException >>= aSql)
+ showError(SQLExceptionInfo(aSql));
+ else
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implSelect: something strange happened!");
+ // reset the values
+ xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
+ xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
+ bSuccess = false;
+ }
+ catch(const Exception&)
+ {
+ // reset the values
+ xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
+ xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
+ bSuccess = false;
+ }
+ }
+ return bSuccess;
+}
+
+std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getEntryFromContainer(const Reference<XNameAccess>& rxNameAccess)
+{
+ std::unique_ptr<weld::TreeIter> xContainer;
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator(xContainer.get()));
+ if (rTreeView.get_iter_first(*xDSLoop))
+ {
+ do
+ {
+ xContainer = rTreeView.make_iterator(xDSLoop.get());
+ if (rTreeView.iter_children(*xContainer))
+ {
+ // 1st child is queries
+ DBTreeListUserData* pQueriesData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer));
+ if (pQueriesData && pQueriesData->xContainer == rxNameAccess)
+ break;
+
+ if (rTreeView.iter_next_sibling(*xContainer))
+ {
+ // 2nd child is tables
+ DBTreeListUserData* pTablesData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer));
+ if (pTablesData && pTablesData->xContainer == rxNameAccess)
+ break;
+ }
+ }
+ xContainer.reset();
+ }
+ while (rTreeView.iter_next_sibling(*xDSLoop));
+ }
+
+ return xContainer;
+}
+
+void SAL_CALL SbaTableQueryBrowser::elementInserted(const ContainerEvent& rEvent)
+{
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XNameAccess > xNames(rEvent.Source, UNO_QUERY);
+ // first search for a definition container where we can insert this element
+
+ std::unique_ptr<weld::TreeIter> xEntry = getEntryFromContainer(xNames);
+ if (xEntry) // found one
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ rTreeView.make_unsorted();
+
+ // insert the new entry into the tree
+ DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xEntry));
+ OSL_ENSURE(pContainerData, "elementInserted: There must be user data for this type!");
+
+ DBTreeListUserData* pNewData = new DBTreeListUserData;
+ bool bIsTable = etTableContainer == pContainerData->eType;
+ if ( bIsTable )
+ {
+ rEvent.Element >>= pNewData->xObjectProperties;// remember the new element
+ pNewData->eType = etTableOrView;
+ }
+ else
+ {
+ if (rTreeView.iter_n_children(*xEntry) < xNames->getElementNames().getLength() - 1)
+ {
+ // the item inserts its children on demand, but it has not been expanded yet. So ensure here and
+ // now that it has all items
+ populateTree(xNames, *xEntry, etQuery);
+ }
+ pNewData->eType = etQuery;
+ }
+ implAppendEntry(xEntry.get(), ::comphelper::getString(rEvent.Accessor), pNewData);
+
+ rTreeView.make_sorted();
+ }
+ else
+ SbaXDataBrowserController::elementInserted(rEvent);
+}
+
+bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(std::u16string_view rName, const weld::TreeIter& rContainer)
+{
+ if (!m_xCurrentlyDisplayed)
+ return false;
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ if (getEntryType(*m_xCurrentlyDisplayed) != getChildType(rContainer))
+ return false;
+ if (rTreeView.get_text(*m_xCurrentlyDisplayed) != rName)
+ return false;
+ std::unique_ptr<weld::TreeIter> xParent = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
+ return rTreeView.iter_parent(*xParent) && rTreeView.iter_compare(*xParent, rContainer) == 0;
+}
+
+void SAL_CALL SbaTableQueryBrowser::elementRemoved( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
+ // get the top-level representing the removed data source
+ // and search for the queries and tables
+ std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames);
+ if (xContainer)
+ {
+ // a query or table has been removed
+ OUString aName = ::comphelper::getString(_rEvent.Accessor);
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ if (isCurrentlyDisplayedChanged(aName, *xContainer))
+ {
+ // the element displayed currently has been replaced
+
+ // we need to remember the old value
+ std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
+
+ // unload
+ unloadAndCleanup( false ); // don't dispose the connection
+
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp));
+ rTreeView.set_id(*xTemp, OUString());
+ delete pData; // the data could be null because we have a table which isn't correct
+ rTreeView.remove(*xTemp);
+ }
+ else
+ {
+ // remove the entry from the model
+ std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get()));
+ if (rTreeView.get_iter_first(*xChild))
+ {
+ do
+ {
+ if (rTreeView.get_text(*xChild) == aName)
+ {
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild));
+ rTreeView.set_id(*xChild, OUString());
+ delete pData;
+ rTreeView.remove(*xChild);
+ break;
+ }
+ } while (rTreeView.iter_next_sibling(*xChild));
+ }
+ }
+
+ // maybe the object which is part of the document data source has been removed
+ checkDocumentDataSource();
+ }
+ else
+ SbaXDataBrowserController::elementRemoved(_rEvent);
+}
+
+void SAL_CALL SbaTableQueryBrowser::elementReplaced( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
+ std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames);
+ if (xContainer)
+ {
+ // a table or query as been replaced
+ OUString aName = ::comphelper::getString(_rEvent.Accessor);
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ if (isCurrentlyDisplayedChanged(aName, *xContainer))
+ { // the element displayed currently has been replaced
+
+ // we need to remember the old value
+ std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
+ unloadAndCleanup( false ); // don't dispose the connection
+
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp));
+ if (pData)
+ {
+ if ( etTableOrView == pData->eType )
+ {
+ // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
+ _rEvent.Element >>= pData->xObjectProperties; // remember the new element
+ }
+ else
+ {
+ rTreeView.set_id(*xTemp, OUString());
+ delete pData;
+ }
+ }
+ }
+ else
+ {
+ // find the entry for this name
+ std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get()));
+ if (rTreeView.get_iter_first(*xChild))
+ {
+ do
+ {
+ if (rTreeView.get_text(*xChild) == aName)
+ {
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild));
+ if (pData)
+ {
+ if ( etTableOrView == pData->eType )
+ {
+ // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
+ _rEvent.Element >>= pData->xObjectProperties; // remember the new element
+ }
+ else
+ {
+ rTreeView.set_id(*xChild, OUString());
+ delete pData;
+ }
+ }
+ break;
+ }
+ } while (rTreeView.iter_next_sibling(*xChild));
+ }
+ }
+
+ // maybe the object which is part of the document data source has been removed
+ checkDocumentDataSource();
+ }
+ else if (xNames.get() == m_xDatabaseContext.get())
+ { // a datasource has been replaced in the context
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::elementReplaced: no support for replaced data sources!");
+ // very suspicious: the database context should not allow to replace data source, only to register
+ // and revoke them
+ }
+ else
+ SbaXDataBrowserController::elementReplaced(_rEvent);
+}
+
+void SbaTableQueryBrowser::impl_releaseConnection( SharedConnection& _rxConnection )
+{
+ // remove as event listener
+ Reference< XComponent > xComponent( _rxConnection, UNO_QUERY );
+ if ( xComponent.is() )
+ {
+ Reference< XEventListener > xListener( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY );
+ xComponent->removeEventListener( xListener );
+ }
+
+ try
+ {
+ // temporary (hopefully!) hack for #i55274#
+ Reference< XFlushable > xFlush( _rxConnection, UNO_QUERY );
+ if ( xFlush.is() )
+ xFlush->flush();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // clear
+ _rxConnection.clear();
+ // will implicitly dispose if we have the ownership, since xConnection is a SharedConnection
+}
+
+void SbaTableQueryBrowser::disposeConnection(const weld::TreeIter* pDSEntry)
+{
+ OSL_ENSURE( pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" );
+ OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" );
+
+ if (pDSEntry)
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pTreeListData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pDSEntry));
+ if (pTreeListData)
+ impl_releaseConnection(pTreeListData->xConnection);
+ }
+}
+
+void SbaTableQueryBrowser::closeConnection(const weld::TreeIter& rDSEntry, bool _bDisposeConnection)
+{
+ OSL_ENSURE(impl_isDataSourceEntry(&rDSEntry), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!");
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+
+ // if one of the entries of the given DS is displayed currently, unload the form
+ if (m_xCurrentlyDisplayed)
+ {
+ std::unique_ptr<weld::TreeIter> xRoot = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get());
+ if (rTreeView.iter_compare(*xRoot, rDSEntry) == 0)
+ unloadAndCleanup(_bDisposeConnection);
+ }
+
+ // collapse the query/table container
+ std::unique_ptr<weld::TreeIter> xContainers(rTreeView.make_iterator(&rDSEntry));
+ if (rTreeView.iter_children(*xContainers))
+ {
+ do
+ {
+ std::unique_ptr<weld::TreeIter> xElements(rTreeView.make_iterator(xContainers.get()));
+ if (rTreeView.iter_children(*xElements))
+ {
+ rTreeView.collapse_row(*xContainers);
+ // and delete their children (they are connection-relative)
+ bool bElements = true;
+ while (bElements)
+ {
+ std::unique_ptr<weld::TreeIter> xRemove(rTreeView.make_iterator(xElements.get()));
+ bElements = rTreeView.iter_next_sibling(*xElements);
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xRemove));
+ rTreeView.set_id(*xRemove, OUString());
+ delete pData;
+ rTreeView.remove(*xRemove);
+ }
+ }
+ }
+ while (rTreeView.iter_next_sibling(*xContainers));
+ }
+
+ // collapse the entry itself
+ rTreeView.collapse_row(rDSEntry);
+
+ // dispose/reset the connection
+ if ( _bDisposeConnection )
+ disposeConnection(&rDSEntry);
+}
+
+void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection )
+{
+ if (!m_xCurrentlyDisplayed)
+ // nothing to do
+ return;
+
+ std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get());
+
+ // de-select the path for the currently displayed table/query
+ selectPath(m_xCurrentlyDisplayed.get(), false);
+ m_xCurrentlyDisplayed.reset();
+
+ try
+ {
+ // get the active connection. We need to dispose it.
+
+ // unload the form
+ Reference< XLoadable > xLoadable = getLoadable();
+ if (xLoadable->isLoaded())
+ xLoadable->unload();
+
+ // clear the grid control
+ Reference< XNameContainer > xConta(getControlModel(),UNO_QUERY);
+ clearGridColumns(xConta);
+
+ // dispose the connection
+ if(_bDisposeConnection)
+ disposeConnection(xDSEntry.get());
+ }
+ catch(SQLException& e)
+ {
+ showError(SQLExceptionInfo(e));
+ }
+ catch(WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if(e.TargetException >>= aSql)
+ showError(SQLExceptionInfo(aSql));
+ else
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: something strange happened!");
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: could not reset the form");
+ }
+}
+
+namespace
+{
+ Reference< XInterface > lcl_getDataSource( const Reference< XDatabaseContext >& _rxDatabaseContext,
+ const OUString& _rDataSourceName, const Reference< XConnection >& _rxConnection )
+ {
+ Reference< XDataSource > xDataSource;
+ try
+ {
+ if ( !_rDataSourceName.isEmpty() && _rxDatabaseContext->hasByName( _rDataSourceName ) )
+ xDataSource.set( _rxDatabaseContext->getByName( _rDataSourceName ), UNO_QUERY_THROW );
+
+ if ( !xDataSource.is() )
+ {
+ Reference< XChild > xConnAsChild( _rxConnection, UNO_QUERY );
+ if ( xConnAsChild.is() )
+ xDataSource.set( xConnAsChild->getParent(), UNO_QUERY_THROW );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xDataSource;
+ }
+}
+
+void SbaTableQueryBrowser::impl_initialize()
+{
+ SolarMutexGuard aGuard;
+ // doin' a lot of VCL stuff here -> lock the SolarMutex
+
+ // first initialize the parent
+ SbaXDataBrowserController::impl_initialize();
+
+ Reference<XConnection> xForeignConnection;
+ Reference< XFrame > xFrame;
+
+ OUString aTableName, aCatalogName, aSchemaName;
+
+ bool bEscapeProcessing = true;
+ sal_Int32 nInitialDisplayCommandType = CommandType::COMMAND;
+ OUString sInitialDataSourceName;
+ OUString sInitialCommand;
+
+ const NamedValueCollection& rArguments( getInitParams() );
+
+ rArguments.get_ensureType( PROPERTY_DATASOURCENAME, sInitialDataSourceName );
+ rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, nInitialDisplayCommandType );
+ rArguments.get_ensureType( PROPERTY_COMMAND, sInitialCommand );
+ rArguments.get_ensureType( PROPERTY_ACTIVE_CONNECTION, xForeignConnection );
+ rArguments.get_ensureType( PROPERTY_UPDATE_CATALOGNAME, aCatalogName );
+ rArguments.get_ensureType( PROPERTY_UPDATE_SCHEMANAME, aSchemaName );
+ rArguments.get_ensureType( PROPERTY_UPDATE_TABLENAME, aTableName );
+ rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing );
+ rArguments.get_ensureType( "Frame", xFrame );
+ rArguments.get_ensureType( PROPERTY_SHOWMENU, m_bShowMenu );
+
+ // disable the browser if either of ShowTreeViewButton (compatibility name) or EnableBrowser
+ // is present and set to FALSE
+ bool bDisableBrowser = !rArguments.getOrDefault( "ShowTreeViewButton", true ) // compatibility name
+ || !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true );
+ OSL_ENSURE( !rArguments.has( "ShowTreeViewButton" ),
+ "SbaTableQueryBrowser::impl_initialize: ShowTreeViewButton is superseded by EnableBrowser!" );
+ m_bEnableBrowser = !bDisableBrowser;
+
+ // hide the tree view it is disabled in general, or if the settings tell to hide it initially
+ bool bHideTreeView = ( !m_bEnableBrowser )
+ || !rArguments.getOrDefault( "ShowTreeView", true ) // compatibility name
+ || !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true );
+ OSL_ENSURE( !rArguments.has( "ShowTreeView" ),
+ "SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" );
+
+ if ( bHideTreeView )
+ hideExplorer();
+ else
+ showExplorer();
+
+ if ( m_bPreview )
+ {
+ try
+ {
+ Sequence< OUString> aProperties
+ {
+ "AlwaysShowCursor", PROPERTY_BORDER, "HasNavigationBar", "HasRecordMarker", "Tabstop"
+ };
+ Sequence< Any> aValues
+ {
+ Any(false), Any(sal_Int16(0)), Any(false), Any(false), Any(false)
+ };
+ Reference< XMultiPropertySet > xFormMultiSet(getFormComponent(), UNO_QUERY);
+ if ( xFormMultiSet.is() )
+ xFormMultiSet->setPropertyValues(aProperties, aValues);
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ // are we loaded into a (sub)frame of an embedded document (i.e. a form belonging to a database
+ // document)?
+ bool bSubFrameOfEmbeddedDocument = false;
+ if ( xFrame.is() )
+ {
+ Reference<XFramesSupplier> xSup = xFrame->getCreator();
+ Reference<XController> xCont = xSup.is() ? xSup->getController() : Reference<XController>();
+
+ bSubFrameOfEmbeddedDocument = xCont.is() && ::dbtools::isEmbeddedInDatabase( xCont->getModel(), xForeignConnection );
+ }
+
+ // if we have a connection at this point, it was either passed from outside, our
+ // determined from an outer DB document. In both cases, do not dispose it later on.
+ SharedConnection xConnection( xForeignConnection, SharedConnection::NoTakeOwnership );
+
+ // should we display all registered databases in the left hand side tree?
+ // or only *one* special?
+ bool bLimitedTreeEntries = false;
+ // if we're part of a frame which is a secondary frame of a database document, then only
+ // display the database for this document, not all registered ones
+ bLimitedTreeEntries |= bSubFrameOfEmbeddedDocument;
+ // if the tree view is not to be displayed at all, then only display the data source
+ // which was given as initial selection
+ bLimitedTreeEntries |= !m_bEnableBrowser;
+
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ rTreeView.make_unsorted();
+
+ if ( bLimitedTreeEntries )
+ {
+ if ( xConnection.is() )
+ {
+ startConnectionListening( xConnection );
+
+ // if no initial name was given, try to obtain one from the data source
+ if ( sInitialDataSourceName.isEmpty() )
+ {
+ Reference< XChild > xChild( xConnection, UNO_QUERY );
+ Reference< XPropertySet > xDataSourceProperties;
+ if ( xChild.is() )
+ xDataSourceProperties.set(xChild->getParent(), css::uno::UNO_QUERY);
+ if ( xDataSourceProperties.is() )
+ {
+ try
+ {
+ OSL_VERIFY( xDataSourceProperties->getPropertyValue( PROPERTY_NAME ) >>= sInitialDataSourceName );
+ }
+ catch( const Exception& )
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: a connection parent which does not have a 'Name'!??" );
+ }
+ }
+ }
+ }
+
+ implAddDatasource( sInitialDataSourceName, xConnection );
+
+ std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xFirst))
+ rTreeView.expand_row(*xFirst);
+ }
+ else
+ initializeTreeModel();
+
+ rTreeView.make_sorted();
+
+ if ( m_bEnableBrowser )
+ {
+ m_aDocScriptSupport = ::std::optional< bool >( false );
+ }
+ else
+ {
+ // we are not used as "browser", but as mere view for a single table/query/command. In particular,
+ // there is a specific database document which we belong to.
+ Reference< XOfficeDatabaseDocument > xDocument( getDataSourceOrModel(
+ lcl_getDataSource( m_xDatabaseContext, sInitialDataSourceName, xConnection ) ), UNO_QUERY );
+ m_aDocScriptSupport = ::std::optional< bool >( Reference< XEmbeddedScripts >( xDocument, UNO_QUERY ).is() );
+ }
+
+ if ( implSelect( sInitialDataSourceName, sInitialCommand, nInitialDisplayCommandType, bEscapeProcessing, xConnection, true ) )
+ {
+ try
+ {
+ Reference< XPropertySet > xRowSetProps(getRowSet(), UNO_QUERY);
+ xRowSetProps->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,Any(aCatalogName));
+ xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,Any(aSchemaName));
+ xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,Any(aTableName));
+
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: could not set the update related names!");
+ }
+ }
+
+ InvalidateAll();
+}
+
+bool SbaTableQueryBrowser::haveExplorer() const
+{
+ return m_pTreeView && m_pTreeView->IsVisible();
+}
+
+void SbaTableQueryBrowser::hideExplorer()
+{
+ if (!haveExplorer())
+ return;
+ if (!getBrowserView())
+ return;
+
+ m_pTreeView->Hide();
+ m_pSplitter->Hide();
+ getBrowserView()->Resize();
+
+ InvalidateFeature(ID_BROWSER_EXPLORER);
+}
+
+void SbaTableQueryBrowser::showExplorer()
+{
+ if (haveExplorer())
+ return;
+
+ if (!getBrowserView())
+ return;
+
+ m_pTreeView->Show();
+ m_pSplitter->Show();
+ getBrowserView()->Resize();
+
+ InvalidateFeature(ID_BROWSER_EXPLORER);
+}
+
+bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection)
+{
+ std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry);
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pDSData =
+ xDSEntry
+ ? weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry))
+ : nullptr;
+
+ return ensureConnection(xDSEntry.get(), pDSData, rConnection);
+}
+
+std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor(const weld::TreeIter* pAnyEntry)
+{
+ std::unique_ptr<ImageProvider> xImageProvider(new ImageProvider);
+ SharedConnection xConnection;
+ if (getExistentConnectionFor(pAnyEntry, xConnection))
+ xImageProvider.reset(new ImageProvider(xConnection));
+ return xImageProvider;
+}
+
+bool SbaTableQueryBrowser::getExistentConnectionFor(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection)
+{
+ std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry);
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ DBTreeListUserData* pDSData =
+ xDSEntry
+ ? weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry))
+ : nullptr;
+ if (pDSData)
+ rConnection = pDSData->xConnection;
+ return rConnection.is();
+}
+
+bool SbaTableQueryBrowser::impl_isDataSourceEntry(const weld::TreeIter* pEntry) const
+{
+ if (!pEntry)
+ return false;
+ std::unique_ptr<weld::TreeIter> xRoot(m_pTreeView->GetRootLevelParent(pEntry));
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ return rTreeView.iter_compare(*xRoot, *pEntry) == 0;
+}
+
+bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pDSEntry, void* pDSData, SharedConnection& rConnection)
+{
+ OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" );
+ if (pDSEntry)
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ OUString aDSName = rTreeView.get_text(*pDSEntry);
+
+ DBTreeListUserData* pTreeListData = static_cast<DBTreeListUserData*>(pDSData);
+ if ( pTreeListData )
+ rConnection = pTreeListData->xConnection;
+
+ if ( !rConnection.is() && pTreeListData )
+ {
+ // show the "connecting to ..." status
+ OUString sConnecting(DBA_RES(STR_CONNECTING_DATASOURCE));
+ sConnecting = sConnecting.replaceFirst("$name$", aDSName);
+ BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sConnecting);
+
+ // build a string showing context information in case of error
+ OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE));
+ sConnectingContext = sConnectingContext.replaceFirst("$name$", aDSName);
+
+ // connect
+ rConnection.reset(
+ connect(getDataSourceAccessor(*pDSEntry), sConnectingContext, nullptr),
+ SharedConnection::TakeOwnership);
+
+ // remember the connection
+ pTreeListData->xConnection = rConnection;
+ }
+ }
+ return rConnection.is();
+}
+
+int SbaTableQueryBrowser::OnTreeEntryCompare(const weld::TreeIter& rLHS, const weld::TreeIter& rRHS)
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+
+ // we want the table entry and the end so we have to do a check
+ if (isContainer(rRHS))
+ {
+ // don't use getEntryType (directly or indirectly) for the LHS:
+ // LHS is currently being inserted, so it is not "completely valid" at the moment
+
+ const EntryType eRight = getEntryType(rRHS);
+ if (etTableContainer == eRight)
+ // every other container should be placed _before_ the bookmark container
+ return -1;
+
+ const OUString sLeft = rTreeView.get_text(rLHS);
+
+ EntryType eLeft = etTableContainer;
+ if (DBA_RES(RID_STR_TABLES_CONTAINER) == sLeft)
+ eLeft = etTableContainer;
+ else if (DBA_RES(RID_STR_QUERIES_CONTAINER) == sLeft)
+ eLeft = etQueryContainer;
+
+ if ( eLeft == eRight )
+ return 0;
+
+ if ( ( eLeft == etTableContainer ) && ( eRight == etQueryContainer ) )
+ return 1;
+
+ if ( ( eLeft == etQueryContainer ) && ( eRight == etTableContainer ) )
+ return -1;
+
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnTreeEntryCompare: unexpected case!" );
+ return 0;
+ }
+
+ OUString sLeftText = rTreeView.get_text(rLHS);
+ OUString sRightText = rTreeView.get_text(rRHS);
+
+ sal_Int32 nCompareResult = 0; // equal by default
+
+ if (m_xCollator.is())
+ {
+ try
+ {
+ nCompareResult = m_xCollator->compareString(sLeftText, sRightText);
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ else
+ // default behaviour if we do not have a collator -> do the simple string compare
+ nCompareResult = sLeftText.compareTo(sRightText);
+
+ return nCompareResult;
+}
+
+void SbaTableQueryBrowser::implAdministrate(const weld::TreeIter& rApplyTo)
+{
+ try
+ {
+ // get the desktop object
+ Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() );
+
+ // the initial selection
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xTopLevelSelected(rTreeView.make_iterator(&rApplyTo));
+
+ while (rTreeView.get_iter_depth(*xTopLevelSelected))
+ rTreeView.iter_parent(*xTopLevelSelected);
+
+ OUString sInitialSelection = getDataSourceAccessor(*xTopLevelSelected);
+
+ Reference< XDataSource > xDataSource( getDataSourceByName( sInitialSelection, getFrameWeld(), getORB(), nullptr ) );
+ Reference< XModel > xDocumentModel( getDataSourceOrModel( xDataSource ), UNO_QUERY );
+
+ if ( xDocumentModel.is() )
+ {
+ Reference< XInteractionHandler2 > xInteractionHandler(
+ InteractionHandler::createWithParent(getORB(), nullptr) );
+
+ ::comphelper::NamedValueCollection aLoadArgs;
+ aLoadArgs.put( "Model", xDocumentModel );
+ aLoadArgs.put( "InteractionHandler", xInteractionHandler );
+ aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
+
+ Sequence< PropertyValue > aLoadArgPV;
+ aLoadArgs >>= aLoadArgPV;
+
+ xFrameLoader->loadComponentFromURL(
+ xDocumentModel->getURL(),
+ "_default",
+ FrameSearchFlag::ALL | FrameSearchFlag::GLOBAL,
+ aLoadArgPV
+ );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+bool SbaTableQueryBrowser::requestQuickHelp(const void* pUserData, OUString& rText) const
+{
+ const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData);
+ if (pData->eType == etDatasource && !pData->sAccessor.isEmpty())
+ {
+ rText = ::svt::OFileNotation(pData->sAccessor).get( ::svt::OFileNotation::N_SYSTEM);
+ return true;
+ }
+ return false;
+}
+
+OUString SbaTableQueryBrowser::getContextMenuResourceName() const
+{
+ return "explorer";
+}
+
+IController& SbaTableQueryBrowser::getCommandController()
+{
+ return *this;
+}
+
+::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors()
+{
+ return &m_aContextMenuInterceptors;
+}
+
+Any SbaTableQueryBrowser::getCurrentSelection(weld::TreeView& rControl) const
+{
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+
+ OSL_PRECOND( &rTreeView == &rControl,
+ "SbaTableQueryBrowser::getCurrentSelection: where does this come from?" );
+
+ if (&rTreeView != &rControl)
+ return Any();
+
+ std::unique_ptr<weld::TreeIter> xSelected(rTreeView.make_iterator());
+ if (!rTreeView.get_selected(xSelected.get()))
+ return Any();
+
+ NamedDatabaseObject aSelectedObject;
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xSelected));
+ aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType );
+
+ switch ( aSelectedObject.Type )
+ {
+ case DatabaseObject::QUERY:
+ case DatabaseObject::TABLE:
+ aSelectedObject.Name = rTreeView.get_text(*xSelected);
+ break;
+
+ case DatabaseObjectContainer::DATA_SOURCE:
+ case DatabaseObjectContainer::QUERIES:
+ case DatabaseObjectContainer::TABLES:
+ aSelectedObject.Name = getDataSourceAccessor(*xSelected);
+ break;
+
+ default:
+ SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" );
+ break;
+ }
+
+ return Any( aSelectedObject );
+}
+
+vcl::Window* SbaTableQueryBrowser::getMenuParent() const
+{
+ return m_pTreeView;
+}
+
+void SbaTableQueryBrowser::adjustMenuPosition(const weld::TreeView&, ::Point&) const
+{
+}
+
+bool SbaTableQueryBrowser::implGetQuerySignature( OUString& _rCommand, bool& _bEscapeProcessing )
+{
+ _rCommand.clear();
+ _bEscapeProcessing = false;
+
+ try
+ {
+ // contain the dss (data source signature) of the form
+ OUString sDataSourceName;
+ OUString sCommand;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ Reference< XPropertySet > xRowsetProps( getRowSet(), UNO_QUERY );
+ ODataAccessDescriptor aDesc( xRowsetProps );
+ sDataSourceName = aDesc.getDataSource();
+ aDesc[ DataAccessDescriptorProperty::Command ] >>= sCommand;
+ aDesc[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
+
+ // do we need to do anything?
+ if ( CommandType::QUERY != nCommandType )
+ return false;
+
+ // get the query object
+ Reference< XQueryDefinitionsSupplier > xSuppQueries;
+ Reference< XNameAccess > xQueries;
+ Reference< XPropertySet > xQuery;
+ m_xDatabaseContext->getByName( sDataSourceName ) >>= xSuppQueries;
+ if ( xSuppQueries.is() )
+ xQueries = xSuppQueries->getQueryDefinitions();
+ if ( xQueries.is() )
+ xQueries->getByName( sCommand ) >>= xQuery;
+ OSL_ENSURE( xQuery.is(), "SbaTableQueryBrowser::implGetQuerySignature: could not retrieve the query object!" );
+
+ // get the two properties we need
+ if ( xQuery.is() )
+ {
+ xQuery->getPropertyValue( PROPERTY_COMMAND ) >>= _rCommand;
+ _bEscapeProcessing = ::cppu::any2bool( xQuery->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) );
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return false;
+}
+
+void SbaTableQueryBrowser::frameAction(const css::frame::FrameActionEvent& aEvent)
+{
+ if (aEvent.Frame == m_xCurrentFrameParent)
+ {
+ if(aEvent.Action == FrameAction_COMPONENT_DETACHING)
+ implRemoveStatusListeners();
+ else if (aEvent.Action == FrameAction_COMPONENT_REATTACHED)
+ connectExternalDispatches();
+ }
+ else
+ SbaXDataBrowserController::frameAction(aEvent);
+
+}
+
+void SbaTableQueryBrowser::clearGridColumns(const Reference< XNameContainer >& _xColContainer)
+{
+ // first we have to clear the grid
+ Reference< XInterface > xColumn;
+ const Sequence<OUString> aColNames = _xColContainer->getElementNames();
+ for (const OUString& rName : aColNames)
+ {
+ _xColContainer->getByName(rName) >>= xColumn;
+ _xColContainer->removeByName(rName);
+ ::comphelper::disposeComponent(xColumn);
+ }
+}
+
+void SbaTableQueryBrowser::loadMenu(const Reference< XFrame >& _xFrame)
+{
+ if ( m_bShowMenu )
+ {
+ OGenericUnoController::loadMenu(_xFrame);
+ }
+ else if ( !m_bPreview )
+ {
+ Reference< css::frame::XLayoutManager > xLayoutManager = getLayoutManager(_xFrame);
+
+ if ( xLayoutManager.is() )
+ {
+ xLayoutManager->lock();
+ xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
+ xLayoutManager->unlock();
+ xLayoutManager->doLayout();
+ }
+ onLoadedMenu( xLayoutManager );
+ }
+}
+
+OUString SbaTableQueryBrowser::getPrivateTitle() const
+{
+ OUString sTitle;
+ if (m_xCurrentlyDisplayed)
+ {
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
+ if (!rTreeView.iter_parent(*xContainer))
+ return OUString();
+ // get the entry for the datasource
+ std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer);
+ OUString sName = rTreeView.get_text(*m_xCurrentlyDisplayed);
+ sTitle = GetEntryText(*xConnection);
+ INetURLObject aURL(sTitle);
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ sTitle = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
+ if ( !sName.isEmpty() )
+ {
+ sName += " - " + sTitle;
+ sTitle = sName;
+ }
+ }
+
+ return sTitle;
+}
+
+bool SbaTableQueryBrowser::preReloadForm()
+{
+ bool bIni = false;
+ if (!m_xCurrentlyDisplayed)
+ {
+ // switch the grid to design mode while loading
+ getBrowserView()->getGridControl()->setDesignMode(true);
+ // we had an invalid statement so we need to connect the column models
+ Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
+ svx::ODataAccessDescriptor aDesc(xRowSetProps);
+ // extract the props
+ OUString sDataSource;
+ OUString sCommand;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ bool bEscapeProcessing = true;
+ extractDescriptorProps(aDesc, sDataSource, sCommand, nCommandType, bEscapeProcessing);
+ if ( !sDataSource.isEmpty() && !sCommand.isEmpty() && (-1 != nCommandType) )
+ {
+ m_xCurrentlyDisplayed = getObjectEntry(sDataSource, sCommand, nCommandType, nullptr, nullptr);
+ bIni = true;
+ }
+ }
+ return bIni;
+}
+
+void SbaTableQueryBrowser::postReloadForm()
+{
+ InitializeGridModel(getFormComponent());
+ LoadFinished(true);
+}
+
+Reference< XEmbeddedScripts > SAL_CALL SbaTableQueryBrowser::getScriptContainer()
+{
+ // update our database document
+ Reference< XModel > xDocument;
+ try
+ {
+ Reference< XPropertySet > xCursorProps( getRowSet(), UNO_QUERY_THROW );
+ Reference< XConnection > xConnection( xCursorProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY );
+ if ( xConnection.is() )
+ {
+ Reference< XChild > xChild( xConnection, UNO_QUERY_THROW );
+ Reference< XDocumentDataSource > xDataSource( xChild->getParent(), UNO_QUERY_THROW );
+ xDocument.set( xDataSource->getDatabaseDocument(), UNO_QUERY_THROW );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ Reference< XEmbeddedScripts > xScripts( xDocument, UNO_QUERY );
+ OSL_ENSURE( xScripts.is() || !xDocument.is(),
+ "SbaTableQueryBrowser::getScriptContainer: invalid database document!" );
+ return xScripts;
+}
+
+void SAL_CALL SbaTableQueryBrowser::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
+{
+ if ( Interceptor.is() )
+ m_aContextMenuInterceptors.addInterface( Interceptor );
+}
+
+void SAL_CALL SbaTableQueryBrowser::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
+{
+ if ( Interceptor.is() )
+ m_aContextMenuInterceptors.removeInterface( Interceptor );
+}
+
+void SAL_CALL SbaTableQueryBrowser::registeredDatabaseLocation( const DatabaseRegistrationEvent& Event )
+{
+ SolarMutexGuard aGuard;
+ implAddDatasource( Event.Name, SharedConnection() );
+}
+
+void SbaTableQueryBrowser::impl_cleanupDataSourceEntry(std::u16string_view rDataSourceName)
+{
+ // get the top-level representing the removed data source
+ weld::TreeView& rTreeView = m_pTreeView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xDataSourceEntry(rTreeView.make_iterator());
+ bool bDataSourceEntry = rTreeView.get_iter_first(*xDataSourceEntry);
+ while (bDataSourceEntry)
+ {
+ if (rTreeView.get_text(*xDataSourceEntry) == rDataSourceName)
+ break;
+ bDataSourceEntry = rTreeView.iter_next_sibling(*xDataSourceEntry);
+ }
+
+ OSL_ENSURE( bDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" );
+ if (!bDataSourceEntry)
+ return;
+
+ if (isSelected(*xDataSourceEntry))
+ {
+ // a table or query belonging to the deleted data source is currently being displayed.
+ unloadAndCleanup();
+ }
+
+ std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xDataSourceEntry.get()));
+ if (rTreeView.iter_children(*xChild))
+ {
+ do
+ {
+ // delete any user data of the child entries of the to-be-removed entry
+ const DBTreeListUserData* pData = weld::fromId<const DBTreeListUserData*>(rTreeView.get_id(*xChild));
+ rTreeView.set_id(*xChild, OUString());
+ delete pData;
+ } while (rTreeView.iter_next_sibling(*xChild));
+ }
+
+ // remove the entry
+ DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry));
+ rTreeView.set_id(*xDataSourceEntry, OUString());
+ delete pData;
+ rTreeView.remove(*xDataSourceEntry);
+}
+
+void SAL_CALL SbaTableQueryBrowser::revokedDatabaseLocation( const DatabaseRegistrationEvent& Event )
+{
+ SolarMutexGuard aGuard;
+
+ impl_cleanupDataSourceEntry( Event.Name );
+
+ // maybe the object which is part of the document data source has been removed
+ checkDocumentDataSource();
+}
+
+void SAL_CALL SbaTableQueryBrowser::changedDatabaseLocation( const DatabaseRegistrationEvent& Event )
+{
+ SolarMutexGuard aGuard;
+
+ // in case the data source was expanded, and connected, we need to clean it up
+ // for simplicity, just do as if the data source were completely removed and re-added
+ impl_cleanupDataSourceEntry( Event.Name );
+ implAddDatasource( Event.Name, SharedConnection() );
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/ColumnControlWindow.cxx b/dbaccess/source/ui/control/ColumnControlWindow.cxx
new file mode 100644
index 000000000..f9f786f22
--- /dev/null
+++ b/dbaccess/source/ui/control/ColumnControlWindow.cxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ColumnControlWindow.hxx>
+#include <unotools/syslocale.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <connectivity/dbtools.hxx>
+#include <o3tl/safeint.hxx>
+#include <UITools.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <com/sun/star/util/NumberFormatter.hpp>
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+OColumnControlTopLevel::OColumnControlTopLevel(vcl::Window* pParent,
+ const Reference<XComponentContext>& _rxContext)
+ : InterimItemWindow(pParent, "dbaccess/ui/colcontrolbox.ui", "ColControlBox")
+ , m_xControl(new OColumnControlWindow(m_xContainer.get(), _rxContext))
+{
+}
+
+void OColumnControlTopLevel::dispose()
+{
+ m_xControl.reset();
+ InterimItemWindow::dispose();
+}
+
+void OColumnControlTopLevel::GetFocus()
+{
+ m_xControl->GrabFocus();
+}
+
+// OColumnControlWindow
+OColumnControlWindow::OColumnControlWindow(weld::Container* pParent,
+ const Reference<XComponentContext>& _rxContext)
+ : OFieldDescControl(pParent, nullptr)
+ , m_xContext(_rxContext)
+ , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES))
+ , m_bAutoIncrementEnabled(true)
+{
+ m_aLocale = SvtSysLocale().GetLanguageTag().getLocale();
+}
+
+void OColumnControlWindow::ActivateAggregate( EControlType eType )
+{
+ switch(eType )
+ {
+ case tpFormat:
+ case tpDefault:
+ case tpColumnName:
+ break;
+ default:
+ OFieldDescControl::ActivateAggregate( eType );
+ }
+}
+
+void OColumnControlWindow::DeactivateAggregate( EControlType eType )
+{
+ switch(eType )
+ {
+ case tpFormat:
+ case tpDefault:
+ case tpColumnName:
+ break;
+ default:
+ OFieldDescControl::DeactivateAggregate( eType );
+ }
+}
+
+void OColumnControlWindow::CellModified(sal_Int32 /*nRow*/, sal_uInt16 /*nColId*/ )
+{
+ saveCurrentFieldDescData();
+}
+
+css::lang::Locale OColumnControlWindow::GetLocale() const
+{
+ return m_aLocale;
+}
+
+Reference< XNumberFormatter > OColumnControlWindow::GetFormatter() const
+{
+ if ( !m_xFormatter.is() )
+ try
+ {
+ Reference< XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(m_xConnection, true, m_xContext));
+
+ if ( xSupplier.is() )
+ {
+ // create a new formatter
+ m_xFormatter.set( NumberFormatter::create(m_xContext), UNO_QUERY_THROW);
+ m_xFormatter->attachNumberFormatsSupplier(xSupplier);
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ return m_xFormatter;
+}
+
+TOTypeInfoSP OColumnControlWindow::getTypeInfo(sal_Int32 _nPos)
+{
+ return ( _nPos >= 0 && o3tl::make_unsigned(_nPos) < m_aDestTypeInfoIndex.size()) ? m_aDestTypeInfoIndex[_nPos]->second : TOTypeInfoSP();
+}
+
+const OTypeInfoMap* OColumnControlWindow::getTypeInfo() const
+{
+ return &m_aDestTypeInfo;
+}
+
+Reference< XDatabaseMetaData> OColumnControlWindow::getMetaData()
+{
+ if ( m_xConnection.is() )
+ return m_xConnection->getMetaData();
+ return Reference< XDatabaseMetaData>();
+}
+
+Reference< XConnection> OColumnControlWindow::getConnection()
+{
+ return m_xConnection;
+}
+
+void OColumnControlWindow::setConnection(const Reference< XConnection>& _xCon)
+{
+ m_xConnection = _xCon;
+ m_xFormatter = nullptr;
+ m_aDestTypeInfoIndex.clear();
+ m_aDestTypeInfo.clear();
+
+ if ( m_xConnection.is() )
+ {
+ Init();
+
+ ::dbaui::fillTypeInfo(m_xConnection,m_sTypeNames,m_aDestTypeInfo,m_aDestTypeInfoIndex);
+ // read autoincrement value set in the datasource
+ ::dbaui::fillAutoIncrementValue(m_xConnection,m_bAutoIncrementEnabled,m_sAutoIncrementValue);
+ }
+}
+
+bool OColumnControlWindow::isAutoIncrementValueEnabled() const
+{
+ return m_bAutoIncrementEnabled;
+}
+
+OUString OColumnControlWindow::getAutoIncrementValue() const
+{
+ return m_sAutoIncrementValue;
+}
+
+TOTypeInfoSP const & OColumnControlWindow::getDefaultTyp() const
+{
+ if ( !m_pTypeInfo )
+ {
+ m_pTypeInfo = std::make_shared<OTypeInfo>();
+ m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';');
+ }
+ return m_pTypeInfo;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/FieldControls.cxx b/dbaccess/source/ui/control/FieldControls.cxx
new file mode 100644
index 000000000..3f3553d56
--- /dev/null
+++ b/dbaccess/source/ui/control/FieldControls.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <FieldControls.hxx>
+#include <SqlNameEdit.hxx>
+#include <core_resource.hxx>
+
+namespace dbaui {
+
+OPropColumnEditCtrl::OPropColumnEditCtrl(std::unique_ptr<weld::Entry> xEntry,
+ OUString const & _rAllowedChars,
+ TranslateId pHelpId,
+ short nPosition)
+ : OSQLNameEntry(std::move(xEntry), _rAllowedChars)
+ , m_nPos(nPosition)
+{
+ m_strHelpText = DBA_RES(pHelpId);
+}
+
+OPropEditCtrl::OPropEditCtrl(std::unique_ptr<weld::Entry> xEntry, TranslateId pHelpId, short nPosition)
+ : OWidgetBase(xEntry.get())
+ , m_xEntry(std::move(xEntry))
+ , m_nPos(nPosition)
+{
+ m_strHelpText = DBA_RES(pHelpId);
+}
+
+OPropNumericEditCtrl::OPropNumericEditCtrl(std::unique_ptr<weld::SpinButton> xSpinButton, TranslateId pHelpId, short nPosition)
+ : OWidgetBase(xSpinButton.get())
+ , m_xSpinButton(std::move(xSpinButton))
+ , m_nPos(nPosition)
+{
+ m_strHelpText = DBA_RES(pHelpId);
+}
+
+OPropListBoxCtrl::OPropListBoxCtrl(std::unique_ptr<weld::ComboBox> xComboBox, TranslateId pHelpId, short nPosition)
+ : OWidgetBase(xComboBox.get())
+ , m_xComboBox(std::move(xComboBox))
+ , m_nPos(nPosition)
+{
+ m_strHelpText = DBA_RES(pHelpId);
+}
+
+} // end namespace dbaui
diff --git a/dbaccess/source/ui/control/FieldDescControl.cxx b/dbaccess/source/ui/control/FieldDescControl.cxx
new file mode 100644
index 000000000..331fbc5cb
--- /dev/null
+++ b/dbaccess/source/ui/control/FieldDescControl.cxx
@@ -0,0 +1,1384 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <FieldDescControl.hxx>
+#include <FieldControls.hxx>
+#include <tools/diagnose_ex.h>
+#include <TableDesignHelpBar.hxx>
+#include <vcl/svapp.hxx>
+#include <FieldDescriptions.hxx>
+#include <svl/numuno.hxx>
+#include <vcl/transfer.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatPreviewer.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <QEnumTypes.hxx>
+#include <helpids.h>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/types.hxx>
+#include <UITools.hxx>
+#include <strings.hrc>
+#include <osl/diagnose.h>
+
+using namespace dbaui;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::util;
+
+namespace
+{
+ template< typename T1, typename T2> void lcl_HideAndDeleteControl(short& _nPos,std::unique_ptr<T1>& _pControl, std::unique_ptr<T2>& _pControlText)
+ {
+ if ( _pControl )
+ {
+ --_nPos;
+ _pControl->hide();
+ _pControlText->hide();
+ _pControl.reset();
+ _pControlText.reset();
+ }
+ }
+}
+
+OFieldDescControl::OFieldDescControl(weld::Container* pPage, OTableDesignHelpBar* pHelpBar)
+ : m_xBuilder(Application::CreateBuilder(pPage, "dbaccess/ui/fielddescpage.ui"))
+ , m_xContainer(m_xBuilder->weld_container("FieldDescPage"))
+ , m_pHelp( pHelpBar )
+ , m_pLastFocusWindow(nullptr)
+ , m_pActFocusWindow(nullptr)
+ , m_nPos(-1)
+ , aYes(DBA_RES(STR_VALUE_YES))
+ , aNo(DBA_RES(STR_VALUE_NO))
+ , m_nEditWidth(50)
+ , pActFieldDescr(nullptr)
+{
+ if (m_pHelp)
+ m_pHelp->connect_focus_out(LINK(this, OFieldDescControl, HelpFocusOut));
+}
+
+OFieldDescControl::~OFieldDescControl()
+{
+ dispose();
+}
+
+void OFieldDescControl::dispose()
+{
+ // Destroy children
+ DeactivateAggregate( tpDefault );
+ DeactivateAggregate( tpRequired );
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpNumType );
+ DeactivateAggregate( tpScale );
+ DeactivateAggregate( tpLength );
+ DeactivateAggregate( tpFormat );
+ DeactivateAggregate( tpAutoIncrement );
+ DeactivateAggregate( tpBoolDefault );
+ DeactivateAggregate( tpColumnName );
+ DeactivateAggregate( tpType );
+ DeactivateAggregate( tpAutoIncrementValue );
+ m_pHelp = nullptr;
+ m_pLastFocusWindow = nullptr;
+ m_pActFocusWindow = nullptr;
+ m_xDefaultText.reset();
+ m_xRequiredText.reset();
+ m_xAutoIncrementText.reset();
+ m_xTextLenText.reset();
+ m_xNumTypeText.reset();
+ m_xLengthText.reset();
+ m_xScaleText.reset();
+ m_xFormatText.reset();
+ m_xBoolDefaultText.reset();
+ m_xColumnNameText.reset();
+ m_xTypeText.reset();
+ m_xAutoIncrementValueText.reset();
+ m_xRequired.reset();
+ m_xNumType.reset();
+ m_xAutoIncrement.reset();
+ m_xDefault.reset();
+ m_xTextLen.reset();
+ m_xLength.reset();
+ m_xScale.reset();
+ m_xFormatSample.reset();
+ m_xBoolDefault.reset();
+ m_xColumnName.reset();
+ m_xType.reset();
+ m_xAutoIncrementValue.reset();
+ m_xFormat.reset();
+ m_xContainer.reset();
+ m_xBuilder.reset();
+}
+
+OUString OFieldDescControl::BoolStringPersistent(std::u16string_view rUIString) const
+{
+ if (rUIString == aNo)
+ return OUString('0');
+ if (rUIString == aYes)
+ return OUString('1');
+ return OUString();
+}
+
+OUString OFieldDescControl::BoolStringUI(const OUString& rPersistentString) const
+{
+ // Older versions may store a language dependent string as a default
+ if (rPersistentString == aYes || rPersistentString == aNo)
+ return rPersistentString;
+
+ if (rPersistentString == "0")
+ return aNo;
+ if (rPersistentString == "1")
+ return aYes;
+
+ return DBA_RES(STR_VALUE_NONE);
+}
+
+void OFieldDescControl::Init()
+{
+ Reference< css::util::XNumberFormatter > xFormatter = GetFormatter();
+ ::dbaui::setEvalDateFormatForFormatter(xFormatter);
+}
+
+void OFieldDescControl::SetReadOnly( bool bReadOnly )
+{
+ // Enable/disable Controls
+ OWidgetBase* ppAggregates[] = { m_xRequired.get(), m_xNumType.get()
+ , m_xAutoIncrement.get(), m_xDefault.get()
+ , m_xTextLen.get(), m_xLength.get()
+ , m_xScale.get(), m_xColumnName.get()
+ , m_xType.get(), m_xAutoIncrementValue.get()
+ };
+ weld::Widget* ppAggregatesText[] = { m_xRequiredText.get(), m_xNumTypeText.get()
+ , m_xAutoIncrementText.get(), m_xDefaultText.get()
+ , m_xTextLenText.get(), m_xLengthText.get()
+ , m_xScaleText.get(), m_xColumnNameText.get()
+ , m_xTypeText.get(), m_xAutoIncrementValueText.get()
+ };
+
+ OSL_ENSURE(SAL_N_ELEMENTS(ppAggregates) == SAL_N_ELEMENTS(ppAggregatesText),"Lists are not identical!");
+
+ for (size_t i=0; i<SAL_N_ELEMENTS(ppAggregates); ++i)
+ {
+ if ( ppAggregatesText[i] )
+ ppAggregatesText[i]->set_sensitive( !bReadOnly );
+ if ( ppAggregates[i] )
+ ppAggregates[i]->set_sensitive( !bReadOnly );
+ }
+
+ if (m_xFormat)
+ {
+ assert(m_xFormatText);
+ m_xFormat->set_sensitive(!bReadOnly);
+ m_xFormatText->set_sensitive(!bReadOnly);
+ }
+}
+
+void OFieldDescControl::SetControlText( sal_uInt16 nControlId, const OUString& rText )
+{
+ // Set the Controls' texts
+ switch( nControlId )
+ {
+ case FIELD_PROPERTY_BOOL_DEFAULT:
+ if (m_xBoolDefault)
+ {
+ OUString sOld = m_xBoolDefault->get_active_text();
+ m_xBoolDefault->set_active_text(rText);
+ if (sOld != rText)
+ ChangeHdl(m_xBoolDefault->GetComboBox());
+ }
+ break;
+ case FIELD_PROPERTY_DEFAULT:
+ if (m_xDefault)
+ {
+ m_xDefault->set_text(rText);
+ UpdateFormatSample(pActFieldDescr);
+ }
+ break;
+
+ case FIELD_PROPERTY_REQUIRED:
+ if (m_xRequired)
+ m_xRequired->set_active_text(rText);
+ break;
+
+ case FIELD_PROPERTY_TEXTLEN:
+ if (m_xTextLen)
+ m_xTextLen->set_text(rText);
+ break;
+
+ case FIELD_PROPERTY_NUMTYPE:
+ if (m_xNumType)
+ m_xNumType->set_active_text(rText);
+ break;
+
+ case FIELD_PROPERTY_AUTOINC:
+ if (m_xAutoIncrement)
+ {
+ OUString sOld = m_xAutoIncrement->get_active_text();
+ m_xAutoIncrement->set_active_text(rText);
+ if (sOld != rText)
+ ChangeHdl(m_xAutoIncrement->GetComboBox());
+ }
+ break;
+
+ case FIELD_PROPERTY_LENGTH:
+ if (m_xLength)
+ m_xLength->set_text(rText);
+ break;
+
+ case FIELD_PROPERTY_SCALE:
+ if (m_xScale)
+ m_xScale->set_text(rText);
+ break;
+
+ case FIELD_PROPERTY_FORMAT:
+ if (pActFieldDescr)
+ UpdateFormatSample(pActFieldDescr);
+ break;
+ case FIELD_PROPERTY_COLUMNNAME:
+ if (m_xColumnName)
+ m_xColumnName->set_text(rText);
+ break;
+ case FIELD_PROPERTY_TYPE:
+ if (m_xType)
+ m_xType->set_active_text(rText);
+ break;
+ case FIELD_PROPERTY_AUTOINCREMENT:
+ if (m_xAutoIncrementValue)
+ m_xAutoIncrementValue->set_text(rText);
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(OFieldDescControl, FormatClickHdl, weld::Button&, void)
+{
+ // Create temporary Column, which is used for data exchange with Dialog
+ if( !pActFieldDescr )
+ return;
+
+ sal_Int32 nOldFormatKey(pActFieldDescr->GetFormatKey());
+ SvxCellHorJustify rOldJustify = pActFieldDescr->GetHorJustify();
+ Reference< XNumberFormatsSupplier > xSupplier = GetFormatter()->getNumberFormatsSupplier();
+ SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier );
+ if (!pSupplierImpl)
+ return;
+
+ SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter();
+ if(!::dbaui::callColumnFormatDialog(m_xContainer.get(),pFormatter,pActFieldDescr->GetType(),nOldFormatKey,rOldJustify,true))
+ return;
+
+ bool bModified = false;
+ if(nOldFormatKey != pActFieldDescr->GetFormatKey())
+ {
+ pActFieldDescr->SetFormatKey( nOldFormatKey );
+ bModified = true;
+ }
+ if(rOldJustify != pActFieldDescr->GetHorJustify())
+ {
+ pActFieldDescr->SetHorJustify( rOldJustify );
+ bModified = true;
+ }
+
+ if(bModified)
+ {
+ SetModified(true);
+ UpdateFormatSample(pActFieldDescr);
+ }
+}
+
+void OFieldDescControl::SetModified(bool /*bModified*/)
+{
+}
+
+IMPL_LINK(OFieldDescControl, ChangeHdl, weld::ComboBox&, rListBox, void)
+{
+ if (!pActFieldDescr)
+ return;
+
+ if (rListBox.get_value_changed_from_saved())
+ SetModified(true);
+
+ // Special treatment for Bool fields
+ if (m_xRequired && &rListBox == m_xRequired->GetWidget() && m_xBoolDefault)
+ {
+ // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>>
+ OUString sDef = BoolStringUI(::comphelper::getString(pActFieldDescr->GetControlDefault()));
+
+ if (m_xRequired->get_active() == 0) // Yes
+ {
+ m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE));
+ if (sDef != aYes && sDef != aNo)
+ m_xBoolDefault->set_active(1); // No as a default
+ else
+ m_xBoolDefault->set_active_text(sDef);
+ }
+ else if (m_xBoolDefault->get_count() < 3)
+ {
+ m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE));
+ m_xBoolDefault->set_active_text(sDef);
+ }
+ }
+
+ // A special treatment only for AutoIncrement
+ if (m_xAutoIncrement && &rListBox == m_xAutoIncrement->GetWidget())
+ {
+ if (rListBox.get_active() == 1)
+ { // no
+ DeactivateAggregate( tpAutoIncrementValue );
+ if(pActFieldDescr->IsPrimaryKey())
+ DeactivateAggregate( tpRequired );
+ else if( pActFieldDescr->getTypeInfo()->bNullable )
+ {
+ ActivateAggregate( tpRequired );
+ if (m_xRequired)
+ {
+ if( pActFieldDescr->IsNullable() )
+ m_xRequired->set_active(1); // no
+ else
+ m_xRequired->set_active(0); // yes
+ }
+ }
+ ActivateAggregate( tpDefault );
+ }
+ else
+ {
+ DeactivateAggregate( tpRequired );
+ DeactivateAggregate( tpDefault );
+ ActivateAggregate( tpAutoIncrementValue );
+ }
+ }
+
+ if (m_xType && &rListBox == m_xType->GetWidget())
+ {
+ TOTypeInfoSP pTypeInfo = getTypeInfo(m_xType->get_active());
+ pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); // SetType(pTypeInfo);
+
+ DisplayData(pActFieldDescr);
+ CellModified(-1, m_xType->GetPos());
+ }
+}
+
+void OFieldDescControl::ActivateAggregate( EControlType eType )
+{
+ // Create Controls
+ switch( eType )
+ {
+ case tpDefault:
+ if (m_xDefault)
+ return;
+ m_nPos++;
+ m_xDefaultText = m_xBuilder->weld_label("DefaultValueText");
+ m_xDefaultText->show();
+ m_xDefault = std::make_unique<OPropEditCtrl>(
+ m_xBuilder->weld_entry("DefaultValue"), STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_DEFAULT);
+ InitializeControl(m_xDefault->GetWidget(),HID_TAB_ENT_DEFAULT);
+ m_xDefault->show();
+ break;
+ case tpAutoIncrementValue:
+ if (m_xAutoIncrementValue || !isAutoIncrementValueEnabled())
+ return;
+ m_nPos++;
+ m_xAutoIncrementValueText = m_xBuilder->weld_label("AutoIncrementValueText");
+ m_xAutoIncrementValueText->show();
+ m_xAutoIncrementValue = std::make_unique<OPropEditCtrl>(
+ m_xBuilder->weld_spin_button("AutoIncrementValue"), STR_HELP_AUTOINCREMENT_VALUE,
+ FIELD_PROPERTY_AUTOINCREMENT);
+ m_xAutoIncrementValue->set_text( getAutoIncrementValue() );
+ InitializeControl(m_xAutoIncrementValue->GetWidget(),HID_TAB_AUTOINCREMENTVALUE);
+ m_xAutoIncrementValue->show();
+ break;
+
+ case tpRequired:
+ {
+ if (m_xRequired)
+ return;
+ Reference< XDatabaseMetaData> xMetaData = getMetaData();
+
+ if(xMetaData.is() && xMetaData->supportsNonNullableColumns())
+ {
+ m_nPos++;
+ m_xRequiredText = m_xBuilder->weld_label("RequiredText");
+ m_xRequiredText->show();
+ m_xRequired = std::make_unique<OPropListBoxCtrl>(
+ m_xBuilder->weld_combo_box("Required"), STR_HELP_AUTOINCREMENT_VALUE,
+ FIELD_PROPERTY_AUTOINCREMENT);
+ m_xRequired->append_text(aYes);
+ m_xRequired->append_text(aNo);
+ m_xRequired->set_active(1);
+
+ InitializeControl(m_xRequired.get(),HID_TAB_ENT_REQUIRED, true);
+ m_xRequired->show();
+ }
+ }
+ break;
+ case tpAutoIncrement:
+ {
+ if (m_xAutoIncrement)
+ return;
+ m_nPos++;
+ m_xAutoIncrementText = m_xBuilder->weld_label("AutoIncrementText");
+ m_xAutoIncrementText->show();
+ m_xAutoIncrement = std::make_unique<OPropListBoxCtrl>(
+ m_xBuilder->weld_combo_box("AutoIncrement"), STR_HELP_AUTOINCREMENT,
+ FIELD_PROPERTY_AUTOINC);
+ m_xAutoIncrement->append_text(aYes);
+ m_xAutoIncrement->append_text(aNo);
+ m_xAutoIncrement->set_active(0);
+ InitializeControl(m_xAutoIncrement.get(),HID_TAB_ENT_AUTOINCREMENT, true);
+ m_xAutoIncrement->show();
+ }
+ break;
+ case tpTextLen:
+ if (m_xTextLen)
+ return;
+ m_nPos++;
+ m_xTextLenText = m_xBuilder->weld_label("TextLengthText");
+ m_xTextLenText->show();
+ m_xTextLen = CreateNumericControl("TextLength", STR_HELP_TEXT_LENGTH, FIELD_PROPERTY_TEXTLEN,HID_TAB_ENT_TEXT_LEN);
+ break;
+
+ case tpType:
+ if (m_xType)
+ return;
+ m_nPos++;
+ m_xTypeText = m_xBuilder->weld_label("TypeText");
+ m_xTypeText->show();
+ m_xType = std::make_unique<OPropListBoxCtrl>(
+ m_xBuilder->weld_combo_box("Type"), STR_HELP_AUTOINCREMENT, FIELD_PROPERTY_TYPE);
+ {
+ const OTypeInfoMap* pTypeInfo = getTypeInfo();
+ for (auto const& elem : *pTypeInfo)
+ m_xType->append_text(elem.second->aUIName);
+ }
+ m_xType->set_active(0);
+ InitializeControl(m_xType.get(),HID_TAB_ENT_TYPE, true);
+ m_xType->show();
+ break;
+ case tpColumnName:
+ if (m_xColumnName)
+ return;
+ m_nPos++;
+ {
+ sal_Int32 nMax(0);
+ OUString aTmpString;
+ try
+ {
+ Reference< XDatabaseMetaData> xMetaData = getMetaData();
+ if ( xMetaData.is() )
+ {
+ nMax = xMetaData->getMaxColumnNameLength();
+ aTmpString = xMetaData->getExtraNameCharacters();
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xColumnNameText = m_xBuilder->weld_label("ColumnNameText");
+ m_xColumnNameText->show();
+ m_xColumnName = std::make_unique<OPropColumnEditCtrl>(
+ m_xBuilder->weld_entry("ColumnName"), aTmpString,
+ STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_COLUMNNAME);
+ m_xColumnName->set_max_length(nMax);
+ m_xColumnName->setCheck( isSQL92CheckEnabled(getConnection()) );
+ }
+
+ InitializeControl(m_xColumnName->GetWidget(),HID_TAB_ENT_COLUMNNAME);
+ m_xColumnName->show();
+ break;
+ case tpNumType:
+ if (m_xNumType)
+ return;
+ m_nPos++;
+ m_xNumTypeText = m_xBuilder->weld_label("NumTypeText");
+ m_xNumTypeText->show();
+ m_xNumType = std::make_unique<OPropListBoxCtrl>(
+ m_xBuilder->weld_combo_box("NumType"), STR_HELP_NUMERIC_TYPE, FIELD_PROPERTY_NUMTYPE);
+ m_xNumType->append_text("Byte");
+ m_xNumType->append_text("SmallInt");
+ m_xNumType->append_text("Integer");
+ m_xNumType->append_text("Single");
+ m_xNumType->append_text("Double");
+ m_xNumType->set_active(2);
+ InitializeControl(m_xNumType.get(),HID_TAB_ENT_NUMTYP, true);
+ m_xNumType->show();
+ break;
+
+ case tpLength:
+ if (m_xLength)
+ return;
+ m_nPos++;
+ m_xLengthText = m_xBuilder->weld_label("LengthText");
+ m_xLengthText->show();
+ m_xLength = CreateNumericControl("Length", STR_HELP_LENGTH, FIELD_PROPERTY_LENGTH,HID_TAB_ENT_LEN);
+ break;
+
+ case tpScale:
+ if (m_xScale)
+ return;
+ m_nPos++;
+ m_xScaleText = m_xBuilder->weld_label("ScaleText");
+ m_xScaleText->show();
+ m_xScale = CreateNumericControl("Scale", STR_HELP_SCALE, FIELD_PROPERTY_SCALE,HID_TAB_ENT_SCALE);
+ break;
+
+ case tpFormat:
+ if (!m_xFormat)
+ {
+ m_nPos++;
+ m_xFormatText = m_xBuilder->weld_label("FormatTextText");
+ m_xFormatText->show();
+
+ m_xFormatSample = std::make_unique<OPropEditCtrl>(
+ m_xBuilder->weld_entry("FormatText"), STR_HELP_FORMAT_CODE, -1);
+ m_xFormatSample->set_editable(false);
+ m_xFormatSample->set_sensitive(false);
+ InitializeControl(m_xFormatSample->GetWidget(),HID_TAB_ENT_FORMAT_SAMPLE);
+ m_xFormatSample->show();
+
+ m_xFormat = m_xBuilder->weld_button("FormatButton");
+ m_xFormat->connect_clicked( LINK( this, OFieldDescControl, FormatClickHdl ) );
+ InitializeControl(m_xFormat.get(),HID_TAB_ENT_FORMAT);
+ m_xFormat->show();
+ }
+
+ UpdateFormatSample(pActFieldDescr);
+ break;
+ case tpBoolDefault:
+ if (m_xBoolDefault)
+ return;
+
+ m_nPos++;
+ m_xBoolDefaultText = m_xBuilder->weld_label("BoolDefaultText");
+ m_xBoolDefaultText->show();
+ m_xBoolDefault = std::make_unique<OPropListBoxCtrl>(
+ m_xBuilder->weld_combo_box("BoolDefault"), STR_HELP_BOOL_DEFAULT,
+ FIELD_PROPERTY_BOOL_DEFAULT);
+ m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE));
+ m_xBoolDefault->append_text(aYes);
+ m_xBoolDefault->append_text(aNo);
+ InitializeControl(m_xBoolDefault->GetWidget(),HID_TAB_ENT_BOOL_DEFAULT);
+ m_xBoolDefault->show();
+ break;
+ }
+}
+
+void OFieldDescControl::InitializeControl(OPropListBoxCtrl* _pControl,const OString& _sHelpId,bool _bAddChangeHandler)
+{
+ if ( _bAddChangeHandler )
+ _pControl->GetComboBox().connect_changed(LINK(this,OFieldDescControl,ChangeHdl));
+
+ InitializeControl(_pControl->GetWidget(), _sHelpId);
+}
+
+void OFieldDescControl::InitializeControl(weld::Widget* pControl,const OString& _sHelpId)
+{
+ pControl->set_help_id(_sHelpId);
+ pControl->connect_focus_in(LINK(this, OFieldDescControl, OnControlFocusGot));
+ pControl->connect_focus_out(LINK(this, OFieldDescControl, OnControlFocusLost));
+
+ if (dynamic_cast<weld::Entry*>(pControl))
+ {
+ int nWidthRequest = Application::GetDefaultDevice()->LogicToPixel(Size(m_nEditWidth, 0), MapMode(MapUnit::MapAppFont)).Width();
+ pControl->set_size_request(nWidthRequest, -1);
+ }
+}
+
+std::unique_ptr<OPropNumericEditCtrl> OFieldDescControl::CreateNumericControl(const OString& rId, TranslateId pHelpId, short _nProperty, const OString& _sHelpId)
+{
+ auto xControl = std::make_unique<OPropNumericEditCtrl>(
+ m_xBuilder->weld_spin_button(rId), pHelpId, _nProperty);
+ xControl->set_digits(0);
+ xControl->set_range(0, 0x7FFFFFFF); // Should be changed outside, if needed
+ xControl->show();
+
+ InitializeControl(xControl->GetWidget(),_sHelpId);
+
+ return xControl;
+}
+
+void OFieldDescControl::DeactivateAggregate( EControlType eType )
+{
+ m_pLastFocusWindow = nullptr;
+ // Destroy Controls
+ switch( eType )
+ {
+ case tpDefault:
+ lcl_HideAndDeleteControl(m_nPos,m_xDefault,m_xDefaultText);
+ break;
+
+ case tpAutoIncrementValue:
+ lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrementValue,m_xAutoIncrementValueText);
+ break;
+
+ case tpColumnName:
+ lcl_HideAndDeleteControl(m_nPos,m_xColumnName,m_xColumnNameText);
+ break;
+
+ case tpType:
+ lcl_HideAndDeleteControl(m_nPos,m_xType,m_xTypeText);
+ break;
+
+ case tpAutoIncrement:
+ lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrement,m_xAutoIncrementText);
+ break;
+
+ case tpRequired:
+ lcl_HideAndDeleteControl(m_nPos,m_xRequired,m_xRequiredText);
+ break;
+
+ case tpTextLen:
+ lcl_HideAndDeleteControl(m_nPos,m_xTextLen,m_xTextLenText);
+ break;
+
+ case tpNumType:
+ lcl_HideAndDeleteControl(m_nPos,m_xNumType,m_xNumTypeText);
+ break;
+
+ case tpLength:
+ lcl_HideAndDeleteControl(m_nPos,m_xLength,m_xLengthText);
+ break;
+
+ case tpScale:
+ lcl_HideAndDeleteControl(m_nPos,m_xScale,m_xScaleText);
+ break;
+
+ case tpFormat:
+ // TODO: we have to check if we have to increment m_nPos again
+ lcl_HideAndDeleteControl(m_nPos,m_xFormat,m_xFormatText);
+ if (m_xFormatSample)
+ {
+ m_xFormatSample->hide();
+ m_xFormatSample.reset();
+ }
+ break;
+ case tpBoolDefault:
+ lcl_HideAndDeleteControl(m_nPos,m_xBoolDefault,m_xBoolDefaultText);
+ break;
+ }
+}
+
+void OFieldDescControl::DisplayData(OFieldDescription* pFieldDescr )
+{
+ pActFieldDescr = pFieldDescr;
+ if(!pFieldDescr)
+ {
+ if (m_pHelp)
+ m_pHelp->SetHelpText( OUString() );
+ DeactivateAggregate( tpDefault );
+ DeactivateAggregate( tpRequired );
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpNumType );
+ DeactivateAggregate( tpScale );
+ DeactivateAggregate( tpLength );
+ DeactivateAggregate( tpFormat );
+ DeactivateAggregate( tpAutoIncrement );
+ DeactivateAggregate( tpBoolDefault );
+ DeactivateAggregate( tpColumnName );
+ DeactivateAggregate( tpType );
+ DeactivateAggregate( tpAutoIncrementValue );
+ m_pPreviousType = TOTypeInfoSP();
+ // Reset the saved focus' pointer
+ m_pLastFocusWindow = nullptr;
+ return;
+ }
+
+ TOTypeInfoSP pFieldType(pFieldDescr->getTypeInfo());
+
+ ActivateAggregate( tpColumnName );
+ ActivateAggregate( tpType );
+
+ OSL_ENSURE(pFieldType,"We need a type information here!");
+ // If the type has changed, substitute Controls
+ if( m_pPreviousType != pFieldType )
+ {
+ // Reset the saved focus' pointer
+ m_pLastFocusWindow = nullptr;
+
+ // Controls, which must NOT be displayed again
+ DeactivateAggregate( tpNumType );
+
+ // determine which controls we should show and which not
+
+ // 1. the required control
+ if ( pFieldType->bNullable )
+ ActivateAggregate( tpRequired );
+ else
+ DeactivateAggregate( tpRequired );
+
+ // 2. the autoincrement
+ if ( pFieldType->bAutoIncrement )
+ {
+ DeactivateAggregate( tpRequired );
+ DeactivateAggregate( tpDefault );
+ ActivateAggregate( tpAutoIncrement );
+ ActivateAggregate( tpAutoIncrementValue );
+ }
+ else
+ {
+ DeactivateAggregate( tpAutoIncrement );
+ DeactivateAggregate( tpAutoIncrementValue );
+ if(pFieldType->bNullable)
+ ActivateAggregate( tpRequired );
+ else
+ DeactivateAggregate( tpRequired );
+ ActivateAggregate( tpDefault );
+ }
+ // 3. the scale and precision
+ if (pFieldType->nPrecision)
+ {
+ ActivateAggregate( tpLength );
+ m_xLength->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision()));
+ m_xLength->set_editable(!pFieldType->aCreateParams.isEmpty());
+ }
+ else
+ DeactivateAggregate( tpLength );
+
+ if (pFieldType->nMaximumScale)
+ {
+ ActivateAggregate( tpScale );
+ m_xScale->set_range(pFieldType->nMinimumScale,
+ std::max<sal_Int32>(pFieldType->nMaximumScale,pFieldDescr->GetScale()));
+ m_xScale->set_editable(!pFieldType->aCreateParams.isEmpty() && pFieldType->aCreateParams != "PRECISION");
+ }
+ else
+ DeactivateAggregate( tpScale );
+
+ // and now look for type specific things
+ switch( pFieldType->nType )
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ DeactivateAggregate( tpLength );
+ DeactivateAggregate( tpBoolDefault );
+
+ ActivateAggregate( tpDefault );
+ ActivateAggregate( tpFormat );
+ if (pFieldType->nPrecision)
+ {
+ ActivateAggregate( tpTextLen );
+ m_xTextLen->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision()));
+ m_xTextLen->set_editable(!pFieldType->aCreateParams.isEmpty());
+ }
+ else
+ DeactivateAggregate( tpTextLen );
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ DeactivateAggregate( tpLength ); // we don't need a length for date types
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpBoolDefault );
+
+ ActivateAggregate( tpDefault );
+ ActivateAggregate( tpFormat );
+ break;
+ case DataType::BIT:
+ if ( !pFieldType->aCreateParams.isEmpty() )
+ {
+ DeactivateAggregate( tpFormat );
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpBoolDefault );
+ break;
+ }
+ [[fallthrough]];
+ case DataType::BOOLEAN:
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpFormat );
+ DeactivateAggregate( tpDefault );
+
+ ActivateAggregate( tpBoolDefault );
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::REAL:
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpBoolDefault );
+
+ ActivateAggregate( tpFormat );
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ DeactivateAggregate( tpDefault );
+ DeactivateAggregate( tpRequired );
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpBoolDefault );
+
+ ActivateAggregate( tpFormat );
+ break;
+ case DataType::LONGVARBINARY:
+ case DataType::SQLNULL:
+ case DataType::OBJECT:
+ case DataType::DISTINCT:
+ case DataType::STRUCT:
+ case DataType::ARRAY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::REF:
+ case DataType::OTHER:
+ DeactivateAggregate( tpFormat );
+ DeactivateAggregate( tpTextLen );
+ DeactivateAggregate( tpBoolDefault );
+
+ break;
+ default:
+ OSL_FAIL("Unknown type");
+ }
+ m_pPreviousType = pFieldType;
+ }
+
+ if (pFieldDescr->IsPrimaryKey())
+ {
+ DeactivateAggregate(tpRequired);
+ }
+ else if (!m_xAutoIncrement && pFieldType)
+ {
+ if (pFieldType->bNullable)
+ ActivateAggregate(tpRequired);
+ else
+ DeactivateAggregate(tpRequired);
+ }
+ // Initialize Controls
+ if (m_xAutoIncrement)
+ {
+ if ( pFieldDescr->IsAutoIncrement() )
+ {
+ m_xAutoIncrement->set_active(0); // yes
+ ActivateAggregate( tpAutoIncrementValue );
+ if (m_xAutoIncrementValue)
+ m_xAutoIncrementValue->set_text(pFieldDescr->GetAutoIncrementValue());
+ DeactivateAggregate( tpRequired );
+ DeactivateAggregate( tpDefault );
+ }
+ else
+ {
+ // disable autoincrement value because it should only be visible when autoincrement is to true
+ DeactivateAggregate( tpAutoIncrementValue );
+ m_xAutoIncrement->set_active(1); // no
+ ActivateAggregate( tpDefault );
+ // Affects pRequired
+ if(!pFieldDescr->IsPrimaryKey())
+ ActivateAggregate( tpRequired );
+ }
+ }
+
+ if (m_xDefault)
+ {
+ m_xDefault->set_text(getControlDefault(pFieldDescr));
+ m_xDefault->save_value();
+ }
+
+ if (m_xBoolDefault)
+ {
+ // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>>
+ OUString sValue;
+ pFieldDescr->GetControlDefault() >>= sValue;
+ OUString sDef = BoolStringUI(sValue);
+
+ // Make sure that <<none>> is only present if the field can be NULL
+ if ( ( pFieldType && !pFieldType->bNullable ) || !pFieldDescr->IsNullable() )
+ {
+ pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); // The type says so
+
+ m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE));
+ if ( sDef != aYes && sDef != aNo )
+ m_xBoolDefault->set_active(1); // No as a default
+ else
+ m_xBoolDefault->set_active_text(sDef);
+
+ pFieldDescr->SetControlDefault(Any(BoolStringPersistent(m_xBoolDefault->get_active_text())));
+ }
+ else if (m_xBoolDefault->get_count() < 3)
+ {
+ m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE));
+ m_xBoolDefault->set_active_text(sDef);
+ }
+ else
+ m_xBoolDefault->set_active_text(sDef);
+ }
+
+ if (m_xRequired)
+ {
+ if( pFieldDescr->IsNullable() )
+ m_xRequired->set_active(1); // no
+ else
+ m_xRequired->set_active(0); // yes
+ }
+
+ if (m_xTextLen)
+ {
+ m_xTextLen->set_text(OUString::number(pFieldDescr->GetPrecision()));
+ m_xTextLen->save_value();
+ }
+
+ if( m_xNumType )
+ {
+ OSL_FAIL("OFieldDescControl::DisplayData: invalid num type!");
+ }
+
+ if (m_xLength)
+ m_xLength->set_text(OUString::number(pFieldDescr->GetPrecision()));
+
+ if (m_xScale)
+ m_xScale->set_text(OUString::number(pFieldDescr->GetScale()));
+
+ if (m_xFormat)
+ UpdateFormatSample(pFieldDescr);
+
+ if (m_xColumnName)
+ m_xColumnName->set_text(pFieldDescr->GetName());
+
+ if (m_xType)
+ {
+ sal_Int32 nPos = pFieldType ? m_xType->find_text(pFieldDescr->getTypeInfo()->aUIName) : -1;
+ if (nPos == -1)
+ {
+ const OTypeInfoMap* pMap = getTypeInfo();
+ OTypeInfoMap::const_iterator aIter = pMap->find(pFieldType ? pFieldDescr->getTypeInfo()->nType : pFieldDescr->GetType());
+ if(aIter == pMap->end() && !pMap->empty())
+ {
+ aIter = pMap->begin();
+ if(pFieldDescr->GetPrecision() > aIter->second->nPrecision)
+ pFieldDescr->SetPrecision(aIter->second->nPrecision);
+ if(pFieldDescr->GetScale() > aIter->second->nMaximumScale)
+ pFieldDescr->SetScale(0);
+ if(!aIter->second->bNullable && pFieldDescr->IsNullable())
+ pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
+ if(!aIter->second->bAutoIncrement && pFieldDescr->IsAutoIncrement())
+ pFieldDescr->SetAutoIncrement(false);
+ }
+ if ( aIter != pMap->end() )
+ {
+ pFieldDescr->SetType(aIter->second);
+ }
+ }
+ m_xType->set_active_text(pFieldDescr->getTypeInfo()->aUIName);
+ }
+
+ // Enable/disable Controls
+ bool bRead(IsReadOnly());
+
+ SetReadOnly( bRead );
+}
+
+IMPL_LINK(OFieldDescControl, OnControlFocusGot, weld::Widget&, rControl, void )
+{
+ OUString strHelpText;
+
+ if (m_xTextLen && &rControl == m_xTextLen->GetWidget())
+ {
+ m_xTextLen->save_value();
+ strHelpText = m_xTextLen->GetHelp();
+ }
+ else if (m_xLength && &rControl == m_xLength->GetWidget())
+ {
+ m_xLength->save_value();
+ strHelpText = m_xLength->GetHelp();
+ }
+ else if (m_xScale && &rControl == m_xScale->GetWidget())
+ {
+ m_xScale->save_value();
+ strHelpText = m_xScale->GetHelp();
+ }
+ else if (m_xColumnName && &rControl == m_xColumnName->GetWidget())
+ {
+ m_xColumnName->save_value();
+ strHelpText = m_xColumnName->GetHelp();
+ }
+ else if (m_xDefault && &rControl == m_xDefault->GetWidget())
+ {
+ m_xDefault->save_value();
+ strHelpText = m_xDefault->GetHelp();
+ }
+ else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget())
+ {
+ m_xFormatSample->save_value();
+ strHelpText = m_xFormatSample->GetHelp();
+ }
+ else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget())
+ {
+ m_xAutoIncrementValue->save_value();
+ strHelpText = m_xAutoIncrementValue->GetHelp();
+ }
+ else if (m_xRequired && &rControl == m_xRequired->GetWidget())
+ {
+ m_xRequired->save_value();
+ strHelpText = m_xRequired->GetHelp();
+ }
+ else if (m_xNumType && &rControl == m_xNumType->GetWidget())
+ {
+ m_xNumType->save_value();
+ strHelpText = m_xNumType->GetHelp();
+ }
+ else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget())
+ {
+ m_xAutoIncrement->save_value();
+ strHelpText = m_xAutoIncrement->GetHelp();
+ }
+ else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget())
+ {
+ m_xBoolDefault->save_value();
+ strHelpText = m_xBoolDefault->GetHelp();
+ }
+ else if (m_xType && &rControl == m_xType->GetWidget())
+ {
+ m_xType->save_value();
+ strHelpText = m_xType->GetHelp();
+ }
+ else if (m_xFormat && &rControl == m_xFormat.get())
+ strHelpText = DBA_RES(STR_HELP_FORMAT_BUTTON);
+
+ if (!strHelpText.isEmpty() && m_pHelp)
+ m_pHelp->SetHelpText(strHelpText);
+
+ m_pActFocusWindow = &rControl;
+
+ m_aControlFocusIn.Call(rControl);
+}
+
+IMPL_LINK(OFieldDescControl, OnControlFocusLost, weld::Widget&, rControl, void )
+{
+ if (m_xLength && &rControl == m_xLength->GetWidget() && m_xLength->get_value_changed_from_saved())
+ CellModified(-1, m_xLength->GetPos());
+ else if (m_xTextLen && &rControl == m_xTextLen->GetWidget() && m_xTextLen->get_value_changed_from_saved())
+ CellModified(-1, m_xTextLen->GetPos());
+ else if (m_xScale && &rControl == m_xScale->GetWidget() && m_xScale->get_value_changed_from_saved())
+ CellModified(-1, m_xScale->GetPos());
+ else if (m_xColumnName && &rControl == m_xColumnName->GetWidget() && m_xColumnName->get_value_changed_from_saved())
+ CellModified(-1, m_xColumnName->GetPos());
+ else if (m_xDefault && &rControl == m_xDefault->GetWidget() && m_xDefault->get_value_changed_from_saved())
+ CellModified(-1, m_xDefault->GetPos());
+ else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget() && m_xFormatSample->get_value_changed_from_saved())
+ CellModified(-1, m_xFormatSample->GetPos());
+ else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget() && m_xAutoIncrementValue->get_value_changed_from_saved())
+ CellModified(-1, m_xAutoIncrementValue->GetPos());
+ else if (m_xRequired && &rControl == m_xRequired->GetWidget() && m_xRequired->get_value_changed_from_saved())
+ CellModified(-1, m_xRequired->GetPos());
+ else if (m_xNumType && &rControl == m_xNumType->GetWidget() && m_xNumType->get_value_changed_from_saved())
+ CellModified(-1, m_xNumType->GetPos());
+ else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget() && m_xAutoIncrement->get_value_changed_from_saved())
+ CellModified(-1, m_xAutoIncrement->GetPos());
+ else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget() && m_xBoolDefault->get_value_changed_from_saved())
+ CellModified(-1, m_xBoolDefault->GetPos());
+ else if (m_xType && &rControl == m_xType->GetWidget() && m_xType->get_value_changed_from_saved())
+ CellModified(-1, m_xType->GetPos());
+ else if (m_xDefault && &rControl == m_xDefault->GetWidget())
+ UpdateFormatSample(pActFieldDescr);
+
+ implFocusLost(&rControl);
+}
+
+void OFieldDescControl::SaveData( OFieldDescription* pFieldDescr )
+{
+ if( !pFieldDescr )
+ return;
+
+ // Read out Controls
+ OUString sDefault;
+ if (m_xDefault)
+ {
+ // tdf#138409 take the control default in the UI Locale format, e.g. 12,34 and return a string
+ // suitable as the database default, e.g. 12.34
+ sDefault = CanonicalizeToControlDefault(pFieldDescr, m_xDefault->get_text());
+ }
+ else if (m_xBoolDefault)
+ {
+ sDefault = BoolStringPersistent(m_xBoolDefault->get_active_text());
+ }
+
+ if ( !sDefault.isEmpty() )
+ pFieldDescr->SetControlDefault(Any(sDefault));
+ else
+ pFieldDescr->SetControlDefault(Any());
+
+ if((m_xRequired && m_xRequired->get_active() == 0) || pFieldDescr->IsPrimaryKey() || (m_xBoolDefault && m_xBoolDefault->get_count() == 2)) // yes
+ pFieldDescr->SetIsNullable( ColumnValue::NO_NULLS );
+ else
+ pFieldDescr->SetIsNullable( ColumnValue::NULLABLE );
+
+ if (m_xAutoIncrement)
+ pFieldDescr->SetAutoIncrement(m_xAutoIncrement->get_active() == 0);
+
+ if( m_xTextLen )
+ pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xTextLen->get_value()) );
+ else if (m_xLength)
+ pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xLength->get_value()) );
+ if (m_xScale)
+ pFieldDescr->SetScale( static_cast<sal_Int32>(m_xScale->get_value()) );
+
+ if (m_xColumnName)
+ pFieldDescr->SetName(m_xColumnName->get_text());
+
+ if (m_xAutoIncrementValue && isAutoIncrementValueEnabled())
+ pFieldDescr->SetAutoIncrementValue(m_xAutoIncrementValue->get_text());
+}
+
+void OFieldDescControl::UpdateFormatSample(OFieldDescription const * pFieldDescr)
+{
+ if (pFieldDescr && m_xFormatSample)
+ m_xFormatSample->set_text(getControlDefault(pFieldDescr,false));
+}
+
+void OFieldDescControl::GrabFocus()
+{
+ m_xContainer->grab_focus();
+
+ // Set the Focus to the Control that has been active last
+ if (m_pLastFocusWindow)
+ {
+ m_pLastFocusWindow->grab_focus();
+ m_pLastFocusWindow = nullptr;
+ }
+}
+
+void OFieldDescControl::implFocusLost(weld::Widget* _pWhich)
+{
+ // Remember the active Control
+ if (!m_pLastFocusWindow)
+ m_pLastFocusWindow = _pWhich;
+
+ // Reset HelpText
+ if (m_pHelp && !m_pHelp->HasFocus())
+ m_pHelp->SetHelpText( OUString() );
+}
+
+IMPL_LINK_NOARG(OFieldDescControl, HelpFocusOut, weld::Widget&, void)
+{
+ m_pHelp->SetHelpText(OUString());
+}
+
+bool OFieldDescControl::IsFocusInEditableWidget() const
+{
+ if (m_xDefault && m_pActFocusWindow == m_xDefault->GetWidget())
+ return true;
+ if (m_xFormatSample && m_pActFocusWindow == m_xFormatSample->GetWidget())
+ return true;
+ if (m_xTextLen && m_pActFocusWindow == m_xTextLen->GetWidget())
+ return true;
+ if (m_xLength && m_pActFocusWindow == m_xLength->GetWidget())
+ return true;
+ if (m_xScale && m_pActFocusWindow == m_xScale->GetWidget())
+ return true;
+ if (m_xColumnName && m_pActFocusWindow == m_xColumnName->GetWidget())
+ return true;
+ if (m_xAutoIncrementValue && m_pActFocusWindow == m_xAutoIncrementValue->GetWidget())
+ return true;
+ return false;
+}
+
+bool OFieldDescControl::HasChildPathFocus() const
+{
+ return m_xContainer && m_xContainer->has_child_focus();
+}
+
+bool OFieldDescControl::isCopyAllowed()
+{
+ int nStartPos, nEndPos;
+ bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() &&
+ dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos);
+ return bAllowed;
+}
+
+bool OFieldDescControl::isCutAllowed()
+{
+ int nStartPos, nEndPos;
+ bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() &&
+ dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos);
+ return bAllowed;
+}
+
+bool OFieldDescControl::isPasteAllowed()
+{
+ bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget();
+ if ( bAllowed )
+ {
+ TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromClipboard(m_pActFocusWindow->get_clipboard()));
+ bAllowed = aTransferData.HasFormat(SotClipboardFormatId::STRING);
+ }
+ return bAllowed;
+}
+
+void OFieldDescControl::cut()
+{
+ if (isCutAllowed())
+ dynamic_cast<weld::Entry&>(*m_pActFocusWindow).cut_clipboard();
+}
+
+void OFieldDescControl::copy()
+{
+ if (isCopyAllowed()) // this only checks if the focus window is valid
+ dynamic_cast<weld::Entry&>(*m_pActFocusWindow).copy_clipboard();
+}
+
+void OFieldDescControl::paste()
+{
+ if (m_pActFocusWindow) // this only checks if the focus window is valid
+ dynamic_cast<weld::Entry&>(*m_pActFocusWindow).paste_clipboard();
+}
+
+bool OFieldDescControl::isTextFormat(const OFieldDescription* _pFieldDescr, sal_uInt32& _nFormatKey) const
+{
+ _nFormatKey = _pFieldDescr->GetFormatKey();
+ bool bTextFormat = true;
+
+ try
+ {
+ if (!_nFormatKey)
+ {
+ Reference< css::util::XNumberFormatTypes> xNumberTypes(GetFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY);
+ OSL_ENSURE(xNumberTypes.is(),"XNumberFormatTypes is null!");
+
+ _nFormatKey = ::dbtools::getDefaultNumberFormat( _pFieldDescr->GetType(),
+ _pFieldDescr->GetScale(),
+ _pFieldDescr->IsCurrency(),
+ xNumberTypes,
+ GetLocale());
+ }
+ sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(GetFormatter(),_nFormatKey);
+ bTextFormat = (nNumberFormat == css::util::NumberFormat::TEXT);
+ }
+ catch(const Exception&)
+ {
+
+ }
+
+ return bTextFormat;
+}
+
+OUString OFieldDescControl::getControlDefault( const OFieldDescription* _pFieldDescr, bool _bCheck) const
+{
+ OUString sDefault;
+ bool bCheck = !_bCheck || _pFieldDescr->GetControlDefault().hasValue();
+ if ( bCheck )
+ {
+ try
+ {
+ double nValue = 0.0;
+ sal_uInt32 nFormatKey;
+ bool bTextFormat = isTextFormat(_pFieldDescr,nFormatKey);
+ if ( _pFieldDescr->GetControlDefault() >>= sDefault )
+ {
+ if ( !bTextFormat )
+ {
+ if ( !sDefault.isEmpty() )
+ {
+ try
+ {
+ nValue = GetFormatter()->convertStringToNumber(nFormatKey,sDefault);
+ }
+ catch(const Exception&)
+ {
+ return OUString(); // return empty string for format example
+ }
+ }
+ }
+ }
+ else
+ _pFieldDescr->GetControlDefault() >>= nValue;
+
+ Reference< css::util::XNumberFormatter> xNumberFormatter = GetFormatter();
+ Reference<XPropertySet> xFormSet = xNumberFormatter->getNumberFormatsSupplier()->getNumberFormats()->getByKey(nFormatKey);
+ OSL_ENSURE(xFormSet.is(),"XPropertySet is null!");
+ OUString sFormat;
+ xFormSet->getPropertyValue("FormatString") >>= sFormat;
+
+ if ( !bTextFormat )
+ {
+ Locale aLocale;
+ ::comphelper::getNumberFormatProperty(xNumberFormatter,nFormatKey,"Locale") >>= aLocale;
+
+ sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(xNumberFormatter,nFormatKey);
+ if( (nNumberFormat & css::util::NumberFormat::DATE) == css::util::NumberFormat::DATE
+ || (nNumberFormat & css::util::NumberFormat::DATETIME) == css::util::NumberFormat::DATETIME )
+ {
+ nValue = DBTypeConversion::toNullDate(DBTypeConversion::getNULLDate(xNumberFormatter->getNumberFormatsSupplier()),nValue);
+ }
+
+ Reference< css::util::XNumberFormatPreviewer> xPreviewer(xNumberFormatter,UNO_QUERY);
+ OSL_ENSURE(xPreviewer.is(),"XNumberFormatPreviewer is null!");
+ sDefault = xPreviewer->convertNumberToPreviewString(sFormat,nValue,aLocale,true);
+ }
+ else if ( !(_bCheck && sDefault.isEmpty()) )
+ sDefault = xNumberFormatter->formatString(nFormatKey, sDefault.isEmpty() ? sFormat : sDefault);
+ }
+ catch(const Exception&)
+ {
+
+ }
+ }
+
+ return sDefault;
+}
+
+// tdf#138409 intended to be effectively the reverse of getControlDefault to
+// turn a user's possibly 12,34 format into 12.34 format for numerical types
+OUString OFieldDescControl::CanonicalizeToControlDefault(const OFieldDescription* pFieldDescr, const OUString& rDefault) const
+{
+ if (rDefault.isEmpty())
+ return rDefault;
+
+ bool bIsNumericalType = false;
+ switch (pFieldDescr->GetType())
+ {
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ bIsNumericalType = true;
+ break;
+ }
+
+ if (!bIsNumericalType)
+ return rDefault;
+
+ try
+ {
+ sal_uInt32 nFormatKey;
+ bool bTextFormat = isTextFormat(pFieldDescr, nFormatKey);
+ if (bTextFormat)
+ return rDefault;
+ double nValue = GetFormatter()->convertStringToNumber(nFormatKey, rDefault);
+ return OUString::number(nValue);
+ }
+ catch(const Exception&)
+ {
+ }
+
+ return rDefault;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/RelationControl.cxx b/dbaccess/source/ui/control/RelationControl.cxx
new file mode 100644
index 000000000..fc8bca178
--- /dev/null
+++ b/dbaccess/source/ui/control/RelationControl.cxx
@@ -0,0 +1,695 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <RelationControl.hxx>
+
+#include <svtools/editbrowsebox.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <tools/diagnose_ex.h>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <TableConnectionData.hxx>
+#include <TableConnection.hxx>
+#include <TableWindow.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <RelControliFace.hxx>
+#include <helpids.h>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+
+#include <vector>
+#include <utility>
+using std::pair;
+using std::make_pair;
+
+#define SOURCE_COLUMN 1
+#define DEST_COLUMN 2
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace svt;
+
+ typedef ::svt::EditBrowseBox ORelationControl_Base;
+ class ORelationControl : public ORelationControl_Base
+ {
+ friend class OTableListBoxControl;
+
+ VclPtr< ::svt::ListBoxControl> m_pListCell;
+ TTableConnectionData::value_type m_pConnData;
+ OTableListBoxControl* m_pBoxControl;
+ tools::Long m_nDataPos;
+ Reference< XPropertySet> m_xSourceDef;
+ Reference< XPropertySet> m_xDestDef;
+ enum opcode { DELETE, INSERT, MODIFY };
+ typedef std::vector< pair < opcode, pair < OConnectionLineDataVec::size_type, OConnectionLineDataVec::size_type> > > ops_type;
+ ops_type m_ops;
+
+ void fillListBox(const Reference< XPropertySet>& _xDest);
+ /** returns the column id for the editbrowsebox
+ @param _nColId
+ the column id SOURCE_COLUMN or DEST_COLUMN
+
+ @return the current column id either SOURCE_COLUMN or DEST_COLUMN depends on the connection data
+ */
+ sal_uInt16 getColumnIdent( sal_uInt16 _nColId ) const;
+ public:
+ explicit ORelationControl(const css::uno::Reference<css::awt::XWindow>& rParent);
+ void SetController(OTableListBoxControl* pController)
+ {
+ m_pBoxControl = pController;
+ }
+
+ /** searches for a connection between these two tables
+ @param _pSource
+ the left table
+ @param _pDest
+ the right window
+ */
+ void setWindowTables(const OTableWindow* _pSource,const OTableWindow* _pDest);
+
+ /** allows to access the connection data from outside
+
+ @return the connection data
+ */
+ const TTableConnectionData::value_type& getData() const { return m_pConnData; }
+
+ void lateInit();
+
+ protected:
+ virtual ~ORelationControl() override { disposeOnce(); }
+ virtual void dispose() override { m_pListCell.disposeAndClear(); ORelationControl_Base::dispose(); }
+ virtual void Resize() override;
+ virtual Size GetOptimalSize() const override;
+ virtual bool PreNotify(NotifyEvent& rNEvt ) override;
+
+ virtual bool IsTabAllowed(bool bForward) const override;
+
+ void Init(const TTableConnectionData::value_type& _pConnData);
+ using ORelationControl_Base::Init;
+ virtual void InitController( ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) override;
+ virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override;
+ virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override;
+ virtual bool SeekRow( sal_Int32 nRow ) override;
+ virtual bool SaveModified() override;
+ virtual OUString GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const override;
+
+ virtual void CellModified() override;
+
+ DECL_LINK( AsynchDeactivate, void*, void );
+ private:
+
+ DECL_LINK( AsynchActivate, void*, void );
+
+ };
+
+ ORelationControl::ORelationControl(const css::uno::Reference<css::awt::XWindow>& rParent)
+ : EditBrowseBox(VCLUnoHelper::GetWindow(rParent),
+ EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT,
+ WB_TABSTOP | WB_BORDER,
+ BrowserMode::AUTOSIZE_LASTCOL)
+ , m_pBoxControl(nullptr)
+ , m_nDataPos(0)
+ {
+ }
+
+ void ORelationControl::Init(const TTableConnectionData::value_type& _pConnData)
+ {
+
+ m_pConnData = _pConnData;
+ OSL_ENSURE(m_pConnData, "No data supplied!");
+
+ m_pConnData->normalizeLines();
+ }
+
+ void ORelationControl::lateInit()
+ {
+ if ( !m_pConnData )
+ return;
+ m_xSourceDef = m_pConnData->getReferencingTable()->getTable();
+ m_xDestDef = m_pConnData->getReferencedTable()->getTable();
+
+ if ( ColCount() == 0 )
+ {
+ InsertDataColumn( SOURCE_COLUMN, m_pConnData->getReferencingTable()->GetWinName(), 100);
+ InsertDataColumn( DEST_COLUMN, m_pConnData->getReferencedTable()->GetWinName(), 100);
+ // If the Defs do not yet exits, we need to set them with SetSource-/-DestDef
+
+ m_pListCell.reset( VclPtr<ListBoxControl>::Create( &GetDataWindow() ) );
+
+ // set browse mode
+ SetMode( BrowserMode::COLUMNSELECTION |
+ BrowserMode::HLINES |
+ BrowserMode::VLINES |
+ BrowserMode::HIDECURSOR |
+ BrowserMode::HIDESELECT |
+ BrowserMode::AUTO_HSCROLL |
+ BrowserMode::AUTO_VSCROLL);
+ }
+ else
+ // not the first call
+ RowRemoved(0, GetRowCount());
+
+ RowInserted(0, m_pConnData->GetConnLineDataList().size() + 1); // add one extra row
+ }
+
+ void ORelationControl::Resize()
+ {
+ EditBrowseBox::Resize();
+ tools::Long nOutputWidth = GetOutputSizePixel().Width() - 1;
+ SetColumnWidth(1, (nOutputWidth / 2));
+ SetColumnWidth(2, (nOutputWidth / 2));
+ }
+
+ bool ORelationControl::PreNotify(NotifyEvent& rNEvt)
+ {
+ if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && !HasChildPathFocus() && !ControlHasFocus())
+ PostUserEvent(LINK(this, ORelationControl, AsynchDeactivate), nullptr, true);
+ else if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
+ PostUserEvent(LINK(this, ORelationControl, AsynchActivate), nullptr, true);
+
+ return EditBrowseBox::PreNotify(rNEvt);
+ }
+
+ IMPL_LINK_NOARG(ORelationControl, AsynchActivate, void*, void)
+ {
+ ActivateCell();
+ }
+
+ IMPL_LINK_NOARG(ORelationControl, AsynchDeactivate, void*, void)
+ {
+ DeactivateCell();
+ }
+
+ bool ORelationControl::IsTabAllowed(bool bForward) const
+ {
+ sal_Int32 nRow = GetCurRow();
+ sal_uInt16 nCol = GetCurColumnId();
+
+ bool bRet = !( ( bForward && (nCol == DEST_COLUMN) && (nRow == GetRowCount() - 1))
+ || (!bForward && (nCol == SOURCE_COLUMN) && (nRow == 0)));
+
+ return bRet && EditBrowseBox::IsTabAllowed(bForward);
+ }
+
+ bool ORelationControl::SaveModified()
+ {
+ sal_Int32 nRow = GetCurRow();
+ if ( nRow != BROWSER_ENDOFSELECTION )
+ {
+ weld::ComboBox& rListBox = m_pListCell->get_widget();
+ OUString sFieldName(rListBox.get_active_text());
+ OConnectionLineDataVec& rLines = m_pConnData->GetConnLineDataList();
+ if ( rLines.size() <= o3tl::make_unsigned(nRow) )
+ {
+ rLines.push_back(new OConnectionLineData());
+ nRow = rLines.size() - 1;
+ // add new past-rLines row
+ m_ops.emplace_back(INSERT, make_pair(nRow+1, nRow+2));
+ }
+
+ OConnectionLineDataRef pConnLineData = rLines[nRow];
+
+ switch( getColumnIdent( GetCurColumnId() ) )
+ {
+ case SOURCE_COLUMN:
+ pConnLineData->SetSourceFieldName( sFieldName );
+ break;
+ case DEST_COLUMN:
+ pConnLineData->SetDestFieldName( sFieldName );
+ break;
+ }
+ // the modification we just did does *not* need to be registered in m_ops;
+ // it is already taken into account (by the codepath that called us)
+ //m_ops.push_back(make_pair(MODIFY, make_pair(nRow, nRow+1)));
+ }
+
+ const OConnectionLineDataVec::size_type oldSize = m_pConnData->GetConnLineDataList().size();
+ OConnectionLineDataVec::size_type line = m_pConnData->normalizeLines();
+ const OConnectionLineDataVec::size_type newSize = m_pConnData->GetConnLineDataList().size();
+ assert(newSize <= oldSize);
+ m_ops.emplace_back(MODIFY, make_pair(line, newSize));
+ m_ops.emplace_back(DELETE, make_pair(newSize, oldSize));
+
+ return true;
+ }
+
+ sal_uInt16 ORelationControl::getColumnIdent( sal_uInt16 _nColId ) const
+ {
+ sal_uInt16 nId = _nColId;
+ if ( m_pConnData->getReferencingTable() != m_pBoxControl->getReferencingTable() )
+ nId = ( _nColId == SOURCE_COLUMN) ? DEST_COLUMN : SOURCE_COLUMN;
+ return nId;
+ }
+
+ OUString ORelationControl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const
+ {
+ OUString sText;
+ if ( m_pConnData->GetConnLineDataList().size() > o3tl::make_unsigned(nRow) )
+ {
+ OConnectionLineDataRef pConnLineData = m_pConnData->GetConnLineDataList()[nRow];
+ switch( getColumnIdent( nColId ) )
+ {
+ case SOURCE_COLUMN:
+ sText = pConnLineData->GetSourceFieldName();
+ break;
+ case DEST_COLUMN:
+ sText = pConnLineData->GetDestFieldName();
+ break;
+ }
+ }
+ return sText;
+ }
+
+ void ORelationControl::InitController( CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColumnId )
+ {
+
+ OString sHelpId( HID_RELATIONDIALOG_LEFTFIELDCELL );
+
+ Reference< XPropertySet> xDef;
+ switch ( getColumnIdent(nColumnId) )
+ {
+ case SOURCE_COLUMN:
+ xDef = m_xSourceDef;
+ sHelpId = HID_RELATIONDIALOG_LEFTFIELDCELL;
+ break;
+ case DEST_COLUMN:
+ xDef = m_xDestDef;
+ sHelpId = HID_RELATIONDIALOG_RIGHTFIELDCELL;
+ break;
+ default:
+ // ?????????
+ break;
+ }
+
+ if ( !xDef.is() )
+ return;
+
+ fillListBox(xDef);
+ OUString sName = GetCellText( nRow, nColumnId );
+ weld::ComboBox& rList = m_pListCell->get_widget();
+ rList.set_active_text(sName);
+ if (rList.get_active_text() != sName)
+ {
+ rList.append_text(sName);
+ rList.set_active_text(sName);
+ }
+
+ rList.set_help_id(sHelpId);
+ }
+
+ CellController* ORelationControl::GetController( sal_Int32 /*nRow*/, sal_uInt16 /*nColumnId*/ )
+ {
+ return new ListBoxCellController( m_pListCell.get() );
+ }
+
+ bool ORelationControl::SeekRow( sal_Int32 nRow )
+ {
+ m_nDataPos = nRow;
+ return true;
+ }
+
+ void ORelationControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const
+ {
+ OUString aText = GetCellText( m_nDataPos, nColumnId );
+
+ Point aPos( rRect.TopLeft() );
+ Size aTextSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight() );
+
+ if( aPos.X() < rRect.Left() || aPos.X() + aTextSize.Width() > rRect.Right() ||
+ aPos.Y() < rRect.Top() || aPos.Y() + aTextSize.Height() > rRect.Bottom() )
+ {
+ rDev.SetClipRegion(vcl::Region(rRect));
+ }
+
+ rDev.DrawText( aPos, aText );
+
+ if( rDev.IsClipRegion() )
+ rDev.SetClipRegion();
+ }
+ void ORelationControl::fillListBox(const Reference< XPropertySet>& _xDest)
+ {
+ weld::ComboBox& rList = m_pListCell->get_widget();
+ rList.clear();
+ try
+ {
+ if ( _xDest.is() )
+ {
+ //sal_Int32 nRows = GetRowCount();
+ Reference<XColumnsSupplier> xSup(_xDest,UNO_QUERY);
+ Reference<XNameAccess> xColumns = xSup->getColumns();
+ Sequence< OUString> aNames = xColumns->getElementNames();
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ rList.append_text(*pIter);
+ }
+ rList.insert_text(0, OUString());
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ void ORelationControl::setWindowTables(const OTableWindow* _pSource,const OTableWindow* _pDest)
+ {
+ // If I edit here, hide
+ bool bWasEditing = IsEditing();
+ if ( bWasEditing )
+ DeactivateCell();
+
+ if ( _pSource && _pDest )
+ {
+ m_xSourceDef = _pSource->GetTable();
+ SetColumnTitle(1, _pSource->GetName());
+
+ m_xDestDef = _pDest->GetTable();
+ SetColumnTitle(2, _pDest->GetName());
+
+ const OJoinTableView* pView = _pSource->getTableView();
+ OTableConnection* pConn = pView->GetTabConn(_pSource,_pDest);
+ if ( pConn && !m_pConnData->GetConnLineDataList().empty() )
+ {
+ m_pConnData->CopyFrom(*pConn->GetData());
+ m_pBoxControl->getContainer()->notifyConnectionChange();
+ }
+ else
+ {
+ // no connection found so we clear our data
+ OConnectionLineDataVec& rLines = m_pConnData->GetConnLineDataList();
+ for( const auto& rLine : rLines )
+ {
+ rLine->Reset();
+ }
+
+ m_pConnData->setReferencingTable(_pSource->GetData());
+ m_pConnData->setReferencedTable(_pDest->GetData());
+ }
+ m_pConnData->normalizeLines();
+
+ }
+ // Repaint
+ Invalidate();
+
+ if ( bWasEditing )
+ {
+ GoToRow(0);
+ ActivateCell();
+ }
+ }
+
+ void ORelationControl::CellModified()
+ {
+ EditBrowseBox::CellModified();
+ SaveModified();
+ assert(m_pBoxControl);
+ m_pBoxControl->NotifyCellChange();
+ }
+
+ Size ORelationControl::GetOptimalSize() const
+ {
+ return LogicToPixel(Size(140, 80), MapMode(MapUnit::MapAppFont));
+ }
+
+ OTableListBoxControl::OTableListBoxControl(weld::Builder* _pParent,
+ const OJoinTableView::OTableWindowMap* _pTableMap,
+ IRelationControlInterface* _pParentDialog)
+ : m_xLeftTable(_pParent->weld_combo_box("table1"))
+ , m_xRightTable(_pParent->weld_combo_box("table2"))
+ , m_xTable(_pParent->weld_container("relations"))
+ , m_xTableCtrlParent(m_xTable->CreateChildFrame())
+ , m_xRC_Tables(VclPtr<ORelationControl>::Create(m_xTableCtrlParent))
+ , m_pTableMap(_pTableMap)
+ , m_pParentDialog(_pParentDialog)
+ {
+ Size aPrefSize = m_xRC_Tables->GetOptimalSize();
+ m_xTable->set_size_request(aPrefSize.Width(), aPrefSize.Height());
+
+ m_xRC_Tables->SetController(this);
+ m_xRC_Tables->Init();
+
+ lateUIInit();
+
+ Link<weld::ComboBox&,void> aLink(LINK(this, OTableListBoxControl, OnTableChanged));
+ m_xLeftTable->connect_changed(aLink);
+ m_xRightTable->connect_changed(aLink);
+ }
+
+ OTableListBoxControl::~OTableListBoxControl()
+ {
+ m_xRC_Tables.disposeAndClear();
+ m_xTableCtrlParent->dispose();
+ m_xTableCtrlParent.clear();
+ }
+
+ void OTableListBoxControl::fillListBoxes()
+ {
+ OSL_ENSURE( !m_pTableMap->empty(), "OTableListBoxControl::fillListBoxes: no table window!");
+ OTableWindow* pInitialLeft = nullptr;
+ OTableWindow* pInitialRight = nullptr;
+
+ // Collect the names of all TabWins
+ for (auto const& elem : *m_pTableMap)
+ {
+ m_xLeftTable->append_text(elem.first);
+ m_xRightTable->append_text(elem.first);
+
+ if (!pInitialLeft)
+ {
+ pInitialLeft = elem.second;
+ m_strCurrentLeft = elem.first;
+ }
+ else if (!pInitialRight)
+ {
+ pInitialRight = elem.second;
+ m_strCurrentRight = elem.first;
+ }
+ }
+
+ if ( !pInitialRight )
+ {
+ pInitialRight = pInitialLeft;
+ m_strCurrentRight = m_strCurrentLeft;
+ }
+
+ // The corresponding Defs for my Controls
+ m_xRC_Tables->setWindowTables(pInitialLeft,pInitialRight);
+
+ // The table selected in a ComboBox must not be available in the other
+
+ if ( m_pTableMap->size() > 2 )
+ {
+ m_xLeftTable->remove_text(m_strCurrentRight);
+ m_xRightTable->remove_text(m_strCurrentLeft);
+ }
+
+ // Select the first one on the left side and on the right side,
+ // select the second one
+ m_xLeftTable->set_active_text(m_strCurrentLeft);
+ m_xRightTable->set_active_text(m_strCurrentRight);
+
+ m_xLeftTable->grab_focus();
+ }
+
+ IMPL_LINK(OTableListBoxControl, OnTableChanged, weld::ComboBox&, rListBox, void)
+ {
+ OUString strSelected(rListBox.get_active_text());
+ OTableWindow* pLeft = nullptr;
+ OTableWindow* pRight = nullptr;
+
+ // Special treatment: If there are only two tables, we need to switch the other one too when changing in a LB
+ if ( m_pTableMap->size() == 2 )
+ {
+ weld::ComboBox* pOther;
+ if (&rListBox == m_xLeftTable.get())
+ pOther = m_xRightTable.get();
+ else
+ pOther = m_xLeftTable.get();
+ pOther->set_active(1 - pOther->get_active());
+
+ OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->begin();
+ OTableWindow* pFirst = aIter->second;
+ ++aIter;
+ OTableWindow* pSecond = aIter->second;
+
+ if (m_xLeftTable->get_active_text() == pFirst->GetName())
+ {
+ pLeft = pFirst;
+ pRight = pSecond;
+ }
+ else
+ {
+ pLeft = pSecond;
+ pRight = pFirst;
+ }
+ }
+ else
+ {
+ // First we need the TableDef to the Table and with it the TabWin
+ OJoinTableView::OTableWindowMap::const_iterator aFind = m_pTableMap->find(strSelected);
+ OTableWindow* pLoop = nullptr;
+ if( aFind != m_pTableMap->end() )
+ pLoop = aFind->second;
+ OSL_ENSURE(pLoop != nullptr, "ORelationDialog::OnTableChanged: invalid ListBox entry!");
+ // We need to find strSelect, because we filled the ListBoxes with the table names with which we compare now
+ if (&rListBox == m_xLeftTable.get())
+ {
+ // Insert the previously selected Entry on the left side on the right side
+ m_xRightTable->append_text(m_strCurrentLeft);
+ // Remove the currently selected Entry
+ m_xRightTable->remove_text(strSelected);
+ m_strCurrentLeft = strSelected;
+
+ pLeft = pLoop;
+
+ OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->find(m_xRightTable->get_active_text());
+ OSL_ENSURE( aIter != m_pTableMap->end(), "Invalid name");
+ if ( aIter != m_pTableMap->end() )
+ pRight = aIter->second;
+
+ m_xLeftTable->grab_focus();
+ }
+ else
+ {
+ // Insert the previously selected Entry on the right side on the left side
+ m_xLeftTable->append_text(m_strCurrentRight);
+ // Remove the currently selected Entry
+ m_xLeftTable->remove_text(strSelected);
+ m_strCurrentRight = strSelected;
+
+ pRight = pLoop;
+ OJoinTableView::OTableWindowMap::const_iterator aIter = m_pTableMap->find(m_xLeftTable->get_active_text());
+ OSL_ENSURE( aIter != m_pTableMap->end(), "Invalid name");
+ if ( aIter != m_pTableMap->end() )
+ pLeft = aIter->second;
+ }
+ }
+
+ rListBox.grab_focus();
+
+ m_xRC_Tables->setWindowTables(pLeft,pRight);
+
+ NotifyCellChange();
+ }
+
+ void OTableListBoxControl::NotifyCellChange()
+ {
+ // Enable/disable the OK button, depending on having a valid situation
+ TTableConnectionData::value_type pConnData = m_xRC_Tables->getData();
+ const OConnectionLineDataVec& rLines = pConnData->GetConnLineDataList();
+ bool bValid = !rLines.empty();
+ if (bValid)
+ {
+ for (auto const& line : rLines)
+ {
+ bValid = ! (line->GetSourceFieldName().isEmpty() || line->GetDestFieldName().isEmpty());
+ if (!bValid)
+ break;
+ }
+ }
+ m_pParentDialog->setValid(bValid);
+
+ m_xRC_Tables->DeactivateCell();
+ for (auto const& elem : m_xRC_Tables->m_ops)
+ {
+ switch(elem.first)
+ {
+ case ORelationControl::DELETE:
+ m_xRC_Tables->RowRemoved(elem.second.first, elem.second.second - elem.second.first);
+ break;
+ case ORelationControl::INSERT:
+ m_xRC_Tables->RowInserted(elem.second.first, elem.second.second - elem.second.first);
+ break;
+ case ORelationControl::MODIFY:
+ for(OConnectionLineDataVec::size_type j = elem.second.first; j < elem.second.second; ++j)
+ m_xRC_Tables->RowModified(j);
+ break;
+ }
+ }
+ m_xRC_Tables->ActivateCell();
+ m_xRC_Tables->m_ops.clear();
+ }
+
+ static void fillEntryAndDisable(weld::ComboBox& _rListBox,const OUString& _sEntry)
+ {
+ _rListBox.append_text(_sEntry);
+ _rListBox.set_active(0);
+ _rListBox.set_sensitive(false);
+ }
+
+ void OTableListBoxControl::fillAndDisable(const TTableConnectionData::value_type& _pConnectionData)
+ {
+ fillEntryAndDisable(*m_xLeftTable, _pConnectionData->getReferencingTable()->GetWinName());
+ fillEntryAndDisable(*m_xRightTable, _pConnectionData->getReferencedTable()->GetWinName());
+ }
+
+ void OTableListBoxControl::Init(const TTableConnectionData::value_type& _pConnData)
+ {
+ m_xRC_Tables->Init(_pConnData);
+ }
+
+ void OTableListBoxControl::lateUIInit()
+ {
+ m_xRC_Tables->Show();
+ lateInit();
+ }
+
+ void OTableListBoxControl::lateInit()
+ {
+ m_xRC_Tables->lateInit();
+ }
+
+ void OTableListBoxControl::Disable()
+ {
+ m_xLeftTable->set_sensitive(false);
+ m_xRightTable->set_sensitive(false);
+ m_xRC_Tables->Disable();
+ }
+
+ void OTableListBoxControl::Invalidate()
+ {
+ m_xRC_Tables->Invalidate();
+ }
+
+ void OTableListBoxControl::SaveModified()
+ {
+ m_xRC_Tables->SaveModified();
+ }
+
+ TTableWindowData::value_type const & OTableListBoxControl::getReferencingTable() const
+ {
+ return m_xRC_Tables->getData()->getReferencingTable();
+ }
+
+ void OTableListBoxControl::enableRelation(bool _bEnable)
+ {
+ if ( !_bEnable )
+ m_xRC_Tables->PostUserEvent(LINK(m_xRC_Tables, ORelationControl, AsynchDeactivate));
+ m_xRC_Tables->Enable(_bEnable);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/SqlNameEdit.cxx b/dbaccess/source/ui/control/SqlNameEdit.cxx
new file mode 100644
index 000000000..9d968a0fd
--- /dev/null
+++ b/dbaccess/source/ui/control/SqlNameEdit.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <SqlNameEdit.hxx>
+
+namespace dbaui
+{
+ static bool isCharOk(sal_Unicode _cChar,bool _bFirstChar, std::u16string_view _sAllowedChars)
+ {
+ return (
+ (_cChar >= 'A' && _cChar <= 'Z') ||
+ _cChar == '_' ||
+ _sAllowedChars.find(_cChar) != std::u16string_view::npos ||
+ (!_bFirstChar && (_cChar >= '0' && _cChar <= '9')) ||
+ (_cChar >= 'a' && _cChar <= 'z')
+ );
+ }
+ bool OSQLNameChecker::checkString(const OUString& _sToCheck,
+ OUString& _rsCorrected)
+ {
+ bool bCorrected = false;
+ if ( m_bCheck )
+ {
+ sal_Int32 nMatch = 0;
+ for (sal_Int32 i = nMatch; i < _sToCheck.getLength(); ++i)
+ {
+ if ( !isCharOk( _sToCheck[i], i == 0, m_sAllowedChars ) )
+ {
+ _rsCorrected += _sToCheck.subView(nMatch, i - nMatch);
+ bCorrected = true;
+ nMatch = i + 1;
+ }
+ }
+ _rsCorrected += _sToCheck.subView( nMatch );
+ }
+ return bCorrected;
+ }
+
+ namespace
+ {
+ void checkName(OSQLNameChecker& rChecker, weld::Entry& rEntry)
+ {
+ OUString sCorrected;
+ if (rChecker.checkString(rEntry.get_text(), sCorrected))
+ {
+ int nStartPos, nEndPos;
+ rEntry.get_selection_bounds(nStartPos, nEndPos);
+ int nMin = std::min(nStartPos, nEndPos);
+ rEntry.set_text(sCorrected);
+ rEntry.select_region(nMin, nMin);
+
+ rEntry.save_value();
+ }
+ }
+ }
+
+ IMPL_LINK(OSQLNameEditControl, ModifyHdl, weld::Entry&, rEntry, void)
+ {
+ checkName(*this, rEntry);
+ m_ChainChangedHdl.Call(rEntry);
+ }
+
+ IMPL_LINK(OSQLNameEntry, ModifyHdl, weld::Entry&, rEntry, void)
+ {
+ checkName(*this, rEntry);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/TableGrantCtrl.cxx b/dbaccess/source/ui/control/TableGrantCtrl.cxx
new file mode 100644
index 000000000..f4826e96d
--- /dev/null
+++ b/dbaccess/source/ui/control/TableGrantCtrl.cxx
@@ -0,0 +1,476 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableGrantCtrl.hxx>
+#include <core_resource.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XAuthorizable.hpp>
+#include <connectivity/dbtools.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <strings.hrc>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::dbaui;
+using namespace ::svt;
+
+const sal_uInt16 COL_TABLE_NAME = 1;
+const sal_uInt16 COL_SELECT = 2;
+const sal_uInt16 COL_INSERT = 3;
+const sal_uInt16 COL_DELETE = 4;
+const sal_uInt16 COL_UPDATE = 5;
+const sal_uInt16 COL_ALTER = 6;
+const sal_uInt16 COL_REF = 7;
+const sal_uInt16 COL_DROP = 8;
+
+
+// OTableGrantControl
+OTableGrantControl::OTableGrantControl(const css::uno::Reference<css::awt::XWindow> &rParent)
+ :EditBrowseBox(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, WB_TABSTOP)
+ ,m_pCheckCell( nullptr )
+ ,m_pEdit( nullptr )
+ ,m_nDataPos( 0 )
+ ,m_nDeactivateEvent(nullptr)
+{
+ // insert columns
+ sal_uInt16 i=1;
+ InsertDataColumn( i, DBA_RES(STR_TABLE_PRIV_NAME), 75);
+ FreezeColumn(i++);
+ InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_SELECT), 75);
+ InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_INSERT), 75);
+ InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_DELETE), 75);
+ InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_UPDATE), 75);
+ InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_ALTER), 75);
+ InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_REFERENCE), 75);
+ InsertDataColumn( i++, DBA_RES(STR_TABLE_PRIV_DROP), 75);
+
+ while(--i)
+ SetColumnWidth(i,GetAutoColumnWidth(i));
+}
+
+OTableGrantControl::~OTableGrantControl()
+{
+ disposeOnce();
+}
+
+void OTableGrantControl::dispose()
+{
+ if (m_nDeactivateEvent)
+ {
+ Application::RemoveUserEvent(m_nDeactivateEvent);
+ m_nDeactivateEvent = nullptr;
+ }
+
+ m_pCheckCell.disposeAndClear();
+ m_pEdit.disposeAndClear();
+
+ m_xTables = nullptr;
+ ::svt::EditBrowseBox::dispose();
+}
+
+void OTableGrantControl::setTablesSupplier(const Reference< XTablesSupplier >& _xTablesSup)
+{
+ // first we need the users
+ Reference< XUsersSupplier> xUserSup(_xTablesSup,UNO_QUERY);
+ if(xUserSup.is())
+ m_xUsers = xUserSup->getUsers();
+
+ // second we need the tables to determine which privileges the user has
+ if(_xTablesSup.is())
+ m_xTables = _xTablesSup->getTables();
+
+ if(m_xTables.is())
+ m_aTableNames = m_xTables->getElementNames();
+
+ OSL_ENSURE(m_xUsers.is(),"No user access supported!");
+ OSL_ENSURE(m_xTables.is(),"No tables supported!");
+}
+
+void OTableGrantControl::setComponentContext(const Reference< css::uno::XComponentContext>& _rxContext)
+{
+ m_xContext = _rxContext;
+}
+
+void OTableGrantControl::UpdateTables()
+{
+ RemoveRows();
+
+ if(m_xTables.is())
+ RowInserted(0, m_aTableNames.getLength());
+ // m_bEnable = m_xDb->GetUser() != ((OUserAdmin*)GetParent())->GetUser();
+}
+
+void OTableGrantControl::Init()
+{
+ EditBrowseBox::Init();
+
+ // instantiate ComboBox
+ if(!m_pCheckCell)
+ {
+ m_pCheckCell = VclPtr<CheckBoxControl>::Create( &GetDataWindow() );
+ m_pCheckCell->EnableTriState(false);
+
+ m_pEdit = VclPtr<EditControl>::Create(&GetDataWindow());
+ weld::Entry& rEntry = m_pEdit->get_widget();
+ rEntry.set_editable(false);
+ rEntry.set_sensitive(false);
+ }
+
+ UpdateTables();
+ // set browser mode
+ BrowserMode const nMode = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES |
+ BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT;
+
+ SetMode(nMode);
+}
+
+bool OTableGrantControl::PreNotify(NotifyEvent& rNEvt)
+{
+ if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS)
+ if (!HasChildPathFocus())
+ {
+ if (m_nDeactivateEvent)
+ Application::RemoveUserEvent(m_nDeactivateEvent);
+ m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchDeactivate), nullptr, true);
+ }
+ if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
+ {
+ if (m_nDeactivateEvent)
+ Application::RemoveUserEvent(m_nDeactivateEvent);
+ m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchActivate), nullptr, true);
+ }
+ return EditBrowseBox::PreNotify(rNEvt);
+}
+
+IMPL_LINK_NOARG(OTableGrantControl, AsynchActivate, void*, void)
+{
+ m_nDeactivateEvent = nullptr;
+ ActivateCell();
+}
+
+IMPL_LINK_NOARG(OTableGrantControl, AsynchDeactivate, void*, void)
+{
+ m_nDeactivateEvent = nullptr;
+ DeactivateCell();
+}
+
+bool OTableGrantControl::IsTabAllowed(bool bForward) const
+{
+ sal_Int32 nRow = GetCurRow();
+ sal_uInt16 nCol = GetCurColumnId();
+
+ if (bForward && (nCol == 2) && (nRow == GetRowCount() - 1))
+ return false;
+
+ if (!bForward && (nCol == 1) && (nRow == 0))
+ return false;
+
+ return EditBrowseBox::IsTabAllowed(bForward);
+}
+
+bool OTableGrantControl::SaveModified()
+{
+
+ sal_Int32 nRow = GetCurRow();
+ if(nRow == -1 || nRow >= m_aTableNames.getLength())
+ return false;
+
+ OUString sTableName = m_aTableNames[nRow];
+ bool bErg = true;
+ try
+ {
+
+ if ( m_xUsers->hasByName(m_sUserName) )
+ {
+ Reference<XAuthorizable> xAuth(m_xUsers->getByName(m_sUserName),UNO_QUERY);
+ if ( xAuth.is() )
+ {
+ switch( GetCurColumnId() )
+ {
+ case COL_INSERT:
+ if (m_pCheckCell->GetBox().get_active())
+ xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::INSERT);
+ else
+ xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::INSERT);
+ break;
+ case COL_DELETE:
+ if (m_pCheckCell->GetBox().get_active())
+ xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DELETE);
+ else
+ xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DELETE);
+ break;
+ case COL_UPDATE:
+ if (m_pCheckCell->GetBox().get_active())
+ xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::UPDATE);
+ else
+ xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::UPDATE);
+ break;
+ case COL_ALTER:
+ if (m_pCheckCell->GetBox().get_active())
+ xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::ALTER);
+ else
+ xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::ALTER);
+ break;
+ case COL_SELECT:
+ if (m_pCheckCell->GetBox().get_active())
+ xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::SELECT);
+ else
+ xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::SELECT);
+ break;
+ case COL_REF:
+ if (m_pCheckCell->GetBox().get_active())
+ xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::REFERENCE);
+ else
+ xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::REFERENCE);
+ break;
+ case COL_DROP:
+ if (m_pCheckCell->GetBox().get_active())
+ xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DROP);
+ else
+ xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,Privilege::DROP);
+ break;
+ }
+ fillPrivilege(nRow);
+ }
+ }
+ }
+ catch(SQLException& e)
+ {
+ bErg = false;
+ ::dbtools::showError(::dbtools::SQLExceptionInfo(e),VCLUnoHelper::GetInterface(GetParent()),m_xContext);
+ }
+ if(bErg && Controller().is())
+ Controller()->SaveValue();
+ if(!bErg)
+ UpdateTables();
+
+ return bErg;
+}
+
+OUString OTableGrantControl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const
+{
+ if(COL_TABLE_NAME == nColId)
+ return m_aTableNames[nRow];
+
+ sal_Int32 nPriv = 0;
+ TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow);
+ if(aFind != m_aPrivMap.end())
+ nPriv = aFind->second.nRights;
+
+ return OUString::number(isAllowed(nColId,nPriv) ? 1 :0);
+}
+
+void OTableGrantControl::InitController( CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColumnId )
+{
+ OUString sTablename = m_aTableNames[nRow];
+ // special case for tablename
+ if (nColumnId == COL_TABLE_NAME)
+ m_pEdit->get_widget().set_text(sTablename);
+ else
+ {
+ // get the privileges from the user
+ TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow);
+ m_pCheckCell->GetBox().set_active(aFind != m_aPrivMap.end() && isAllowed(nColumnId,aFind->second.nRights));
+ }
+}
+
+void OTableGrantControl::fillPrivilege(sal_Int32 _nRow) const
+{
+
+ if ( !m_xUsers->hasByName(m_sUserName) )
+ return;
+
+ try
+ {
+ Reference<XAuthorizable> xAuth(m_xUsers->getByName(m_sUserName),UNO_QUERY);
+ if ( xAuth.is() )
+ {
+ // get the privileges
+ TPrivileges nRights;
+ nRights.nRights = xAuth->getPrivileges(m_aTableNames[_nRow],PrivilegeObject::TABLE);
+ if(m_xGrantUser.is())
+ nRights.nWithGrant = m_xGrantUser->getGrantablePrivileges(m_aTableNames[_nRow],PrivilegeObject::TABLE);
+ else
+ nRights.nWithGrant = 0;
+
+ m_aPrivMap[m_aTableNames[_nRow]] = nRights;
+ }
+ }
+ catch(SQLException& e)
+ {
+ ::dbtools::showError(::dbtools::SQLExceptionInfo(e),VCLUnoHelper::GetInterface(GetParent()),m_xContext);
+ }
+ catch(Exception& )
+ {
+ }
+}
+
+bool OTableGrantControl::isAllowed(sal_uInt16 _nColumnId,sal_Int32 _nPrivilege)
+{
+ bool bAllowed = false;
+ switch (_nColumnId)
+ {
+ case COL_INSERT:
+ bAllowed = (Privilege::INSERT & _nPrivilege) == Privilege::INSERT;
+ break;
+ case COL_DELETE:
+ bAllowed = (Privilege::DELETE & _nPrivilege) == Privilege::DELETE;
+ break;
+ case COL_UPDATE:
+ bAllowed = (Privilege::UPDATE & _nPrivilege) == Privilege::UPDATE;
+ break;
+ case COL_ALTER:
+ bAllowed = (Privilege::ALTER & _nPrivilege) == Privilege::ALTER;
+ break;
+ case COL_SELECT:
+ bAllowed = (Privilege::SELECT & _nPrivilege) == Privilege::SELECT;
+ break;
+ case COL_REF:
+ bAllowed = (Privilege::REFERENCE & _nPrivilege) == Privilege::REFERENCE;
+ break;
+ case COL_DROP:
+ bAllowed = (Privilege::DROP & _nPrivilege) == Privilege::DROP;
+ break;
+ }
+ return bAllowed;
+}
+
+void OTableGrantControl::setUserName(const OUString& _sUserName)
+{
+ m_sUserName = _sUserName;
+ m_aPrivMap = TTablePrivilegeMap();
+}
+
+void OTableGrantControl::setGrantUser(const Reference< XAuthorizable>& _xGrantUser)
+{
+ OSL_ENSURE(_xGrantUser.is(),"OTableGrantControl::setGrantUser: GrantUser is null!");
+ m_xGrantUser = _xGrantUser;
+}
+
+CellController* OTableGrantControl::GetController( sal_Int32 nRow, sal_uInt16 nColumnId )
+{
+
+ CellController* pController = nullptr;
+ switch( nColumnId )
+ {
+ case COL_TABLE_NAME:
+ break;
+ case COL_INSERT:
+ case COL_DELETE:
+ case COL_UPDATE:
+ case COL_ALTER:
+ case COL_SELECT:
+ case COL_REF:
+ case COL_DROP:
+ {
+ TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow);
+ if(aFind != m_aPrivMap.end() && isAllowed(nColumnId,aFind->second.nWithGrant))
+ pController = new CheckBoxCellController( m_pCheckCell );
+ }
+ break;
+ default:
+ ;
+ }
+ return pController;
+}
+
+bool OTableGrantControl::SeekRow( sal_Int32 nRow )
+{
+ m_nDataPos = nRow;
+
+ return (nRow <= m_aTableNames.getLength());
+}
+
+void OTableGrantControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const
+{
+
+ if(nColumnId != COL_TABLE_NAME)
+ {
+ TTablePrivilegeMap::const_iterator aFind = findPrivilege(m_nDataPos);
+ if(aFind != m_aPrivMap.end())
+ PaintTristate(rRect, isAllowed(nColumnId,aFind->second.nRights) ? TRISTATE_TRUE : TRISTATE_FALSE,isAllowed(nColumnId,aFind->second.nWithGrant));
+ else
+ PaintTristate(rRect, TRISTATE_FALSE, false);
+ }
+ else
+ {
+ OUString aText(GetCellText( m_nDataPos, nColumnId ));
+ Point aPos( rRect.TopLeft() );
+ sal_Int32 nWidth = GetDataWindow().GetTextWidth( aText );
+ sal_Int32 nHeight = GetDataWindow().GetTextHeight();
+
+ if( aPos.X() < rRect.Left() || aPos.X() + nWidth > rRect.Right() ||
+ aPos.Y() < rRect.Top() || aPos.Y() + nHeight > rRect.Bottom() )
+ {
+ rDev.SetClipRegion(vcl::Region(rRect));
+ }
+
+ rDev.DrawText( aPos, aText );
+ }
+
+ if( rDev.IsClipRegion() )
+ rDev.SetClipRegion();
+}
+
+void OTableGrantControl::CellModified()
+{
+ EditBrowseBox::CellModified();
+ SaveModified();
+}
+
+OTableGrantControl::TTablePrivilegeMap::const_iterator OTableGrantControl::findPrivilege(sal_Int32 _nRow) const
+{
+ TTablePrivilegeMap::const_iterator aFind = m_aPrivMap.find(m_aTableNames[_nRow]);
+ if(aFind == m_aPrivMap.end())
+ {
+ fillPrivilege(_nRow);
+ aFind = m_aPrivMap.find(m_aTableNames[_nRow]);
+ }
+ return aFind;
+}
+
+Reference< XAccessible > OTableGrantControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
+{
+ sal_uInt16 nColumnId = GetColumnId( _nColumnPos );
+ if(nColumnId != COL_TABLE_NAME)
+ {
+ TriState eState = TRISTATE_FALSE;
+ TTablePrivilegeMap::const_iterator aFind = findPrivilege(_nRow);
+ if(aFind != m_aPrivMap.end())
+ {
+ eState = isAllowed(nColumnId,aFind->second.nRights) ? TRISTATE_TRUE : TRISTATE_FALSE;
+ }
+ else
+ eState = TRISTATE_FALSE;
+
+ return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eState );
+ }
+ return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/charsetlistbox.cxx b/dbaccess/source/ui/control/charsetlistbox.cxx
new file mode 100644
index 000000000..8915b65c9
--- /dev/null
+++ b/dbaccess/source/ui/control/charsetlistbox.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <charsetlistbox.hxx>
+
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <osl/diagnose.h>
+
+namespace dbaui
+{
+ CharSetListBox::CharSetListBox(std::unique_ptr<weld::ComboBox> xControl)
+ : m_xControl(std::move(xControl))
+ {
+ for (auto const& charset : m_aCharSets)
+ {
+ m_xControl->append_text(charset.getDisplayName());
+ }
+ }
+
+ void CharSetListBox::SelectEntryByIanaName( const OUString& _rIanaName )
+ {
+ OCharsetDisplay::const_iterator aFind = m_aCharSets.findIanaName( _rIanaName );
+ if (aFind == m_aCharSets.end())
+ {
+ OSL_FAIL( "CharSetListBox::SelectEntryByIanaName: unknown charset falling back to system language!" );
+ aFind = m_aCharSets.findEncoding( RTL_TEXTENCODING_DONTKNOW );
+ }
+
+ if (aFind == m_aCharSets.end())
+ m_xControl->set_active(-1);
+ else
+ m_xControl->set_active_text((*aFind).getDisplayName());
+ }
+
+ bool CharSetListBox::StoreSelectedCharSet( SfxItemSet& _rSet, const sal_uInt16 _nItemId )
+ {
+ bool bChangedSomething = false;
+ if (m_xControl->get_value_changed_from_saved())
+ {
+ OCharsetDisplay::const_iterator aFind = m_aCharSets.findDisplayName(m_xControl->get_active_text());
+ OSL_ENSURE( aFind != m_aCharSets.end(), "CharSetListBox::StoreSelectedCharSet: could not translate the selected character set!" );
+ if ( aFind != m_aCharSets.end() )
+ {
+ _rSet.Put( SfxStringItem( _nItemId, (*aFind).getIanaName() ) );
+ bChangedSomething = true;
+ }
+ }
+ return bChangedSomething;
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/curledit.cxx b/dbaccess/source/ui/control/curledit.cxx
new file mode 100644
index 000000000..9cccde370
--- /dev/null
+++ b/dbaccess/source/ui/control/curledit.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <curledit.hxx>
+
+namespace dbaui
+{
+
+OConnectionURLEdit::OConnectionURLEdit(std::unique_ptr<weld::Entry> xEntry, std::unique_ptr<weld::Label> xForcedPrefix)
+ : m_pTypeCollection(nullptr)
+ , m_bShowPrefix(false)
+ , m_xEntry(std::move(xEntry))
+ , m_xForcedPrefix(std::move(xForcedPrefix))
+{
+}
+
+OConnectionURLEdit::~OConnectionURLEdit()
+{
+}
+
+void OConnectionURLEdit::SetTextNoPrefix(const OUString& _rText)
+{
+ m_xEntry->set_text(_rText);
+}
+
+OUString OConnectionURLEdit::GetTextNoPrefix() const
+{
+ return m_xEntry->get_text();
+}
+
+void OConnectionURLEdit::SetText(const OUString& _rStr)
+{
+ Selection aNoSelection(0,0);
+ SetText(_rStr, aNoSelection);
+}
+
+void OConnectionURLEdit::SetText(const OUString& _rStr, const Selection& /*_rNewSelection*/)
+{
+ m_xForcedPrefix->set_visible(m_bShowPrefix);
+
+ bool bIsEmpty = _rStr.isEmpty();
+ // calc the prefix
+ OUString sPrefix;
+ if (!bIsEmpty)
+ {
+ // determine the type of the new URL described by the new text
+ sPrefix = m_pTypeCollection->getPrefix(_rStr);
+ }
+
+ // the fixed text gets the prefix
+ m_xForcedPrefix->set_label(sPrefix);
+
+ // do the real SetText
+ OUString sNewText( _rStr );
+ if ( !bIsEmpty )
+ sNewText = m_pTypeCollection->cutPrefix( _rStr );
+ m_xEntry->set_text(sNewText);
+}
+
+OUString OConnectionURLEdit::GetText() const
+{
+ return m_xForcedPrefix->strip_mnemonic(m_xForcedPrefix->get_label()) + m_xEntry->get_text();
+}
+
+void OConnectionURLEdit::ShowPrefix(bool _bShowPrefix)
+{
+ m_bShowPrefix = _bShowPrefix;
+ m_xForcedPrefix->set_visible(m_bShowPrefix);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/dbtreelistbox.cxx b/dbaccess/source/ui/control/dbtreelistbox.cxx
new file mode 100644
index 000000000..eb89e1fdb
--- /dev/null
+++ b/dbaccess/source/ui/control/dbtreelistbox.cxx
@@ -0,0 +1,512 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbtreelistbox.hxx>
+#include <dbexchange.hxx>
+#include <callbacks.hxx>
+
+#include <com/sun/star/awt/PopupMenuDirection.hpp>
+#include <com/sun/star/ui/XContextMenuInterceptor.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XPopupMenuController.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <dbaccess/IController.hxx>
+#include <framework/actiontriggerhelper.hxx>
+#include <toolkit/awt/vclxmenu.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svx/dbaobjectex.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+
+#include <memory>
+
+namespace dbaui
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::view;
+
+InterimDBTreeListBox::InterimDBTreeListBox(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "dbaccess/ui/dbtreelist.ui", "DBTreeList")
+ , TreeListBox(m_xBuilder->weld_tree_view("treeview"), true)
+ , m_xStatusBar(m_xBuilder->weld_label("statusbar"))
+{
+ InitControlBase(&GetWidget());
+}
+
+InterimDBTreeListBox::~InterimDBTreeListBox()
+{
+ disposeOnce();
+}
+
+void InterimDBTreeListBox::dispose()
+{
+ implStopSelectionTimer();
+ m_xStatusBar.reset();
+ m_xTreeView.reset();
+ InterimItemWindow::dispose();
+}
+
+bool InterimDBTreeListBox::DoChildKeyInput(const KeyEvent& rKEvt)
+{
+ return ChildKeyInput(rKEvt);
+}
+
+TreeListBoxDropTarget::TreeListBoxDropTarget(TreeListBox& rTreeView)
+ : DropTargetHelper(rTreeView.GetWidget().get_drop_target())
+ , m_rTreeView(rTreeView)
+{
+}
+
+sal_Int8 TreeListBoxDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
+
+ if (nAccept != DND_ACTION_NONE)
+ {
+ // to enable the autoscroll when we're close to the edges
+ weld::TreeView& rWidget = m_rTreeView.GetWidget();
+ rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
+ }
+
+ return nAccept;
+}
+
+sal_Int8 TreeListBoxDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ return m_rTreeView.ExecuteDrop(rEvt);
+}
+
+TreeListBox::TreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bSQLType)
+ : m_xTreeView(std::move(xTreeView))
+ , m_aDropTargetHelper(*this)
+ , m_pActionListener(nullptr)
+ , m_pContextMenuProvider(nullptr)
+ , m_aTimer("dbaccess TreeListBox m_aTimer")
+{
+ m_xTreeView->connect_key_press(LINK(this, TreeListBox, KeyInputHdl));
+ m_xTreeView->connect_changed(LINK(this, TreeListBox, SelectHdl));
+ m_xTreeView->connect_query_tooltip(LINK(this, TreeListBox, QueryTooltipHdl));
+ m_xTreeView->connect_popup_menu(LINK(this, TreeListBox, CommandHdl));
+
+ if (bSQLType)
+ m_xHelper.set(new ODataClipboard);
+ else
+ m_xHelper.set(new svx::OComponentTransferable);
+ m_xTreeView->enable_drag_source(m_xHelper, DND_ACTION_COPY);
+ m_xTreeView->connect_drag_begin(LINK(this, TreeListBox, DragBeginHdl));
+
+ m_aTimer.SetTimeout(900);
+ m_aTimer.SetInvokeHandler(LINK(this, TreeListBox, OnTimeOut));
+}
+
+bool TreeListBox::DoChildKeyInput(const KeyEvent& /*rKEvt*/)
+{
+ // nothing by default
+ return false;
+}
+
+IMPL_LINK(TreeListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
+ bool bHandled = false;
+
+ switch (eFunc)
+ {
+ case KeyFuncType::COPY:
+ bHandled = m_aCopyHandler.IsSet() && !m_xTreeView->get_selected(nullptr);
+ if (bHandled)
+ m_aCopyHandler.Call(nullptr);
+ break;
+ case KeyFuncType::PASTE:
+ bHandled = m_aPasteHandler.IsSet() && !m_xTreeView->get_selected(nullptr);
+ if (bHandled)
+ m_aPasteHandler.Call(nullptr);
+ break;
+ case KeyFuncType::DELETE:
+ bHandled = m_aDeleteHandler.IsSet() && !m_xTreeView->get_selected(nullptr);
+ if (bHandled)
+ m_aDeleteHandler.Call(nullptr);
+ break;
+ default:
+ break;
+ }
+
+ return bHandled || DoChildKeyInput(rKEvt);
+}
+
+void TreeListBox::implStopSelectionTimer()
+{
+ if ( m_aTimer.IsActive() )
+ m_aTimer.Stop();
+}
+
+void TreeListBox::implStartSelectionTimer()
+{
+ implStopSelectionTimer();
+ m_aTimer.Start();
+}
+
+IMPL_LINK_NOARG(TreeListBox, SelectHdl, weld::TreeView&, void)
+{
+ implStartSelectionTimer();
+}
+
+TreeListBox::~TreeListBox()
+{
+}
+
+std::unique_ptr<weld::TreeIter> TreeListBox::GetEntryPosByName(std::u16string_view aName, const weld::TreeIter* pStart, const IEntryFilter* _pFilter) const
+{
+ auto xEntry(m_xTreeView->make_iterator(pStart));
+ if (pStart)
+ {
+ if (!m_xTreeView->iter_children(*xEntry))
+ return nullptr;
+ }
+ else
+ {
+ if (!m_xTreeView->get_iter_first(*xEntry))
+ return nullptr;
+ }
+
+ do
+ {
+ if (m_xTreeView->get_text(*xEntry) == aName)
+ {
+ if (!_pFilter || _pFilter->includeEntry(weld::fromId<void*>(m_xTreeView->get_id(*xEntry))))
+ {
+ // found
+ return xEntry;
+ }
+ }
+ } while (m_xTreeView->iter_next_sibling(*xEntry));
+
+ return nullptr;
+}
+
+IMPL_LINK(TreeListBox, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+
+ if (m_pActionListener)
+ {
+ m_xDragedEntry = m_xTreeView->make_iterator();
+ if (!m_xTreeView->get_selected(m_xDragedEntry.get()))
+ m_xDragedEntry.reset();
+ if (m_xDragedEntry && m_pActionListener->requestDrag(*m_xDragedEntry))
+ {
+ // if the (asynchronous) drag started, stop the selection timer
+ implStopSelectionTimer();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+sal_Int8 TreeListBox::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ sal_Int8 nDropOption = DND_ACTION_NONE;
+ if ( m_pActionListener )
+ {
+ ::Point aDropPos = rEvt.maPosPixel;
+ std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), true))
+ xDropTarget.reset();
+
+ // check if drag is on child entry, which is not allowed
+ std::unique_ptr<weld::TreeIter> xParent;
+ if (rEvt.mnAction & DND_ACTION_MOVE)
+ {
+ if (!m_xDragedEntry) // no entry to move
+ return m_pActionListener->queryDrop(rEvt, m_aDropTargetHelper.GetDataFlavorExVector());
+
+ if (xDropTarget)
+ {
+ xParent = m_xTreeView->make_iterator(xDropTarget.get());
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+ }
+ while (xParent && m_xTreeView->iter_compare(*xParent, *m_xDragedEntry) != 0)
+ {
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+ }
+ }
+
+ if (!xParent)
+ {
+ nDropOption = m_pActionListener->queryDrop(rEvt, m_aDropTargetHelper.GetDataFlavorExVector());
+ // check if move is allowed
+ if ( nDropOption & DND_ACTION_MOVE )
+ {
+ if (!m_xDragedEntry || !xDropTarget ||
+ m_xTreeView->iter_compare(*m_xDragedEntry, *xDropTarget) == 0 ||
+ GetEntryPosByName(m_xTreeView->get_text(*m_xDragedEntry), xDropTarget.get()))
+ {
+ nDropOption = nDropOption & ~DND_ACTION_MOVE;//DND_ACTION_NONE;
+ }
+ }
+ }
+ }
+
+ return nDropOption;
+}
+
+sal_Int8 TreeListBox::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ if (m_pActionListener)
+ m_pActionListener->executeDrop(rEvt);
+ m_xTreeView->unset_drag_dest_row();
+ return DND_ACTION_NONE;
+}
+
+IMPL_LINK(TreeListBox, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString)
+{
+ OUString sQuickHelpText;
+ if (m_pActionListener &&
+ m_pActionListener->requestQuickHelp(weld::fromId<void*>(m_xTreeView->get_id(rIter)), sQuickHelpText))
+ {
+ return sQuickHelpText;
+ }
+ return m_xTreeView->get_tooltip_text();
+}
+
+namespace
+{
+ // SelectionSupplier
+ typedef ::cppu::WeakImplHelper< XSelectionSupplier
+ > SelectionSupplier_Base;
+ class SelectionSupplier : public SelectionSupplier_Base
+ {
+ public:
+ explicit SelectionSupplier( const Any& _rSelection )
+ :m_aSelection( _rSelection )
+ {
+ }
+
+ virtual sal_Bool SAL_CALL select( const Any& xSelection ) override;
+ virtual Any SAL_CALL getSelection( ) override;
+ virtual void SAL_CALL addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override;
+
+ protected:
+ virtual ~SelectionSupplier() override
+ {
+ }
+
+ private:
+ Any m_aSelection;
+ };
+
+ sal_Bool SAL_CALL SelectionSupplier::select( const Any& /*_Selection*/ )
+ {
+ throw IllegalArgumentException();
+ // API bug: this should be a NoSupportException
+ }
+
+ Any SAL_CALL SelectionSupplier::getSelection( )
+ {
+ return m_aSelection;
+ }
+
+ void SAL_CALL SelectionSupplier::addSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ )
+ {
+ OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" );
+ // API bug: this should be a NoSupportException
+ }
+
+ void SAL_CALL SelectionSupplier::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ )
+ {
+ OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" );
+ // API bug: this should be a NoSupportException
+ }
+}
+
+IMPL_LINK(TreeListBox, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ ::Point aPos = rCEvt.GetMousePosPixel();
+
+ std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
+ if (m_xTreeView->get_dest_row_at_pos(aPos, xIter.get(), false) && !m_xTreeView->is_selected(*xIter))
+ {
+ m_xTreeView->unselect_all();
+ m_xTreeView->set_cursor(*xIter);
+ m_xTreeView->select(*xIter);
+ SelectHdl(*m_xTreeView);
+ }
+
+ if (!m_pContextMenuProvider)
+ return false;
+
+ OUString aResourceName(m_pContextMenuProvider->getContextMenuResourceName());
+ if (aResourceName.isEmpty())
+ return false;
+
+ css::uno::Sequence< css::uno::Any > aArgs{
+ css::uno::Any(comphelper::makePropertyValue( "Value", aResourceName )),
+ css::uno::Any(comphelper::makePropertyValue( "Frame", m_pContextMenuProvider->getCommandController().getXController()->getFrame() )),
+ css::uno::Any(comphelper::makePropertyValue( "IsContextMenu", true ))
+ };
+
+ css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+ css::uno::Reference<css::frame::XPopupMenuController> xMenuController
+ (xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext), css::uno::UNO_QUERY);
+
+ if (!xMenuController.is())
+ return false;
+
+ VclPtr<vcl::Window> xMenuParent = m_pContextMenuProvider->getMenuParent();
+
+ css::uno::Reference< css::awt::XWindow> xSourceWindow = VCLUnoHelper::GetInterface(xMenuParent);
+
+ rtl::Reference xPopupMenu( new VCLXPopupMenu );
+ xMenuController->setPopupMenu( xPopupMenu );
+
+ // allow context menu interception
+ ::comphelper::OInterfaceContainerHelper2* pInterceptors = m_pContextMenuProvider->getContextMenuInterceptors();
+ if (pInterceptors && pInterceptors->getLength())
+ {
+ OUString aMenuIdentifier( "private:resource/popupmenu/" + aResourceName );
+
+ ContextMenuExecuteEvent aEvent;
+ aEvent.SourceWindow = xSourceWindow;
+ aEvent.ExecutePosition.X = -1;
+ aEvent.ExecutePosition.Y = -1;
+ aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
+ xPopupMenu, &aMenuIdentifier );
+ aEvent.Selection = new SelectionSupplier(m_pContextMenuProvider->getCurrentSelection(*m_xTreeView));
+
+ ::comphelper::OInterfaceIteratorHelper2 aIter( *pInterceptors );
+ bool bModifiedMenu = false;
+ bool bAskInterceptors = true;
+ while ( aIter.hasMoreElements() && bAskInterceptors )
+ {
+ Reference< XContextMenuInterceptor > xInterceptor( aIter.next(), UNO_QUERY );
+ if ( !xInterceptor.is() )
+ continue;
+
+ try
+ {
+ ContextMenuInterceptorAction eAction = xInterceptor->notifyContextMenuExecute( aEvent );
+ switch ( eAction )
+ {
+ case ContextMenuInterceptorAction_CANCELLED:
+ return false;
+
+ case ContextMenuInterceptorAction_EXECUTE_MODIFIED:
+ bModifiedMenu = true;
+ bAskInterceptors = false;
+ break;
+
+ case ContextMenuInterceptorAction_CONTINUE_MODIFIED:
+ bModifiedMenu = true;
+ bAskInterceptors = true;
+ break;
+
+ default:
+ OSL_FAIL( "DBTreeListBox::CreateContextMenu: unexpected return value of the interceptor call!" );
+ [[fallthrough]];
+ case ContextMenuInterceptorAction_IGNORED:
+ break;
+ }
+ }
+ catch( const DisposedException& e )
+ {
+ if ( e.Context == xInterceptor )
+ aIter.remove();
+ }
+ }
+
+ if ( bModifiedMenu )
+ {
+ xPopupMenu->clear();
+ ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer(
+ xPopupMenu, aEvent.ActionTriggerContainer );
+ aEvent.ActionTriggerContainer.clear();
+ }
+ }
+
+ // adjust pos relative to m_xTreeView to relative to xMenuParent
+ m_pContextMenuProvider->adjustMenuPosition(*m_xTreeView, aPos);
+
+ // do action for selected entry in popup menu
+ css::uno::Reference<css::awt::XWindowPeer> xParent(xSourceWindow, css::uno::UNO_QUERY);
+ xPopupMenu->execute(xParent, css::awt::Rectangle(aPos.X(), aPos.Y(), 1, 1), css::awt::PopupMenuDirection::EXECUTE_DOWN);
+
+ css::uno::Reference<css::lang::XComponent> xComponent(xMenuController, css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+ xMenuController.clear();
+
+ return true;
+}
+
+IMPL_LINK_NOARG(TreeListBox, OnTimeOut, Timer*, void)
+{
+ implStopSelectionTimer();
+
+ m_aSelChangeHdl.Call( nullptr );
+}
+
+std::unique_ptr<weld::TreeIter> TreeListBox::GetRootLevelParent(const weld::TreeIter* pEntry) const
+{
+ if (!pEntry)
+ return nullptr;
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pEntry));
+ while (m_xTreeView->get_iter_depth(*xEntry))
+ m_xTreeView->iter_parent(*xEntry);
+ return xEntry;
+}
+
+DBTreeViewBase::DBTreeViewBase(weld::Container* pContainer)
+ : m_xBuilder(Application::CreateBuilder(pContainer, "dbaccess/ui/dbtreelist.ui"))
+ , m_xContainer(m_xBuilder->weld_container("DBTreeList"))
+{
+}
+
+DBTreeViewBase::~DBTreeViewBase()
+{
+}
+
+DBTreeView::DBTreeView(weld::Container* pContainer, bool bSQLType)
+ : DBTreeViewBase(pContainer)
+{
+ m_xTreeListBox.reset(new TreeListBox(m_xBuilder->weld_tree_view("treeview"), bSQLType));
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/opendoccontrols.cxx b/dbaccess/source/ui/control/opendoccontrols.cxx
new file mode 100644
index 000000000..2fb86bdca
--- /dev/null
+++ b/dbaccess/source/ui/control/opendoccontrols.cxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <opendoccontrols.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/ui/XImageManager.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <unotools/historyoptions.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+namespace dbaui
+{
+
+ namespace
+ {
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::ui::theModuleUIConfigurationManagerSupplier;
+ using ::com::sun::star::ui::XModuleUIConfigurationManagerSupplier;
+ using ::com::sun::star::ui::XUIConfigurationManager;
+ using ::com::sun::star::ui::XImageManager;
+ using ::com::sun::star::graphic::XGraphic;
+
+ Reference< XGraphic> GetCommandIcon( const char* _pCommandURL, const OUString& _rModuleName )
+ {
+ if ( !_pCommandURL || !*_pCommandURL )
+ return nullptr;
+
+ OUString sCommandURL = OUString::createFromAscii( _pCommandURL );
+ try
+ {
+ do
+ {
+ // Retrieve popup menu labels
+ Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ if ( !xContext.is() )
+ break;
+
+ Reference< XModuleUIConfigurationManagerSupplier > xSupplier(
+ theModuleUIConfigurationManagerSupplier::get(xContext) );
+
+ Reference< XUIConfigurationManager > xManager( xSupplier->getUIConfigurationManager( _rModuleName ) );
+ Reference< XImageManager > xImageManager;
+ if ( xManager.is() )
+ xImageManager.set(xManager->getImageManager(), css::uno::UNO_QUERY);
+ if ( !xImageManager.is() )
+ break;
+
+ Sequence< OUString > aCommandList( &sCommandURL, 1 );
+ Sequence<Reference< XGraphic> > xIconList( xImageManager->getImages( 0, aCommandList ) );
+ if ( !xIconList.hasElements() )
+ break;
+
+ return xIconList[0];
+ }
+ while ( false );
+ }
+ catch ( Exception& ) {}
+
+ return nullptr;
+ }
+ }
+
+ // OpenButton
+
+ OpenDocumentButton::OpenDocumentButton(std::unique_ptr<weld::Button> xControl, const char* _pAsciiModuleName)
+ : m_xControl(std::move(xControl))
+ {
+ impl_init( _pAsciiModuleName );
+ }
+
+ void OpenDocumentButton::impl_init( const char* _pAsciiModuleName )
+ {
+ OSL_ENSURE( _pAsciiModuleName, "OpenDocumentButton::impl_init: invalid module name!" );
+ m_sModule = OUString::createFromAscii( _pAsciiModuleName );
+
+ // our label should equal the UI text of the "Open" command
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:Open", m_sModule);
+ OUString sLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
+ m_xControl->set_label(" " + sLabel.replaceAll("~", ""));
+
+ // Place icon left of text and both centered in the button.
+ m_xControl->set_image(GetCommandIcon(".uno:Open", m_sModule));
+ }
+
+ // OpenDocumentListBox
+
+ OpenDocumentListBox::OpenDocumentListBox(std::unique_ptr<weld::ComboBox> xControl, const char* _pAsciiModuleName )
+ : m_xControl(std::move(xControl))
+ {
+ // we need to limit the max auto width feature of the filter box
+ int nWidth = m_xControl->get_approximate_digit_width() * 50;
+ m_xControl->set_size_request(nWidth, -1);
+
+ impl_init( _pAsciiModuleName );
+ }
+
+ void OpenDocumentListBox::impl_init( const char* _pAsciiModuleName )
+ {
+ OSL_ENSURE( _pAsciiModuleName, "OpenDocumentListBox::impl_init: invalid module name!" );
+
+ std::vector< SvtHistoryOptions::HistoryItem > aHistory = SvtHistoryOptions::GetList( EHistoryType::PickList );
+ Reference< XNameAccess > xFilterFactory;
+ xFilterFactory.set(::comphelper::getProcessServiceFactory()->createInstance(
+ "com.sun.star.document.FilterFactory" ), css::uno::UNO_QUERY);
+
+ for ( const SvtHistoryOptions::HistoryItem& rHistoryItem : aHistory )
+ {
+ try
+ {
+ // Get the current history item's properties.
+ OUString sURL = rHistoryItem.sURL;
+ OUString sFilter = rHistoryItem.sFilter;
+ OUString sTitle = rHistoryItem.sTitle;
+ OUString sPassword = rHistoryItem.sPassword;
+
+ // If the entry is a Base file then insert it into the
+ // history list and the list box.
+ Sequence< PropertyValue > aProps;
+ xFilterFactory->getByName( sFilter ) >>= aProps;
+
+ ::comphelper::SequenceAsHashMap aFilterProperties( aProps );
+ OUString sDocumentService = aFilterProperties.getUnpackedValueOrDefault(
+ "DocumentService", OUString() );
+ if ( sDocumentService.equalsAscii( _pAsciiModuleName ) )
+ {
+ // yes, it's a Base document
+ INetURLObject aURL;
+ aURL.SetSmartURL( sURL );
+ // The password is set only when it is not empty.
+ if ( !sPassword.isEmpty() )
+ aURL.SetPass( sPassword );
+
+ if ( sTitle.isEmpty() )
+ sTitle = aURL.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
+
+ OUString sDecodedURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ m_xControl->append_text(sTitle);
+ m_aURLs.emplace_back(sDecodedURL, sFilter);
+ }
+ }
+ catch( Exception& ) {}
+ }
+ }
+
+ OUString OpenDocumentListBox::GetSelectedDocumentURL() const
+ {
+ OUString sURL;
+ sal_Int32 nSelected = m_xControl->get_active();
+ if (nSelected != -1)
+ sURL = impl_getDocumentAtIndex( nSelected ).first;
+ return sURL;
+ }
+
+ const OpenDocumentListBox::StringPair & OpenDocumentListBox::impl_getDocumentAtIndex( sal_uInt16 _nListIndex ) const
+ {
+ return m_aURLs[_nListIndex];
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/sqledit.cxx b/dbaccess/source/ui/control/sqledit.cxx
new file mode 100644
index 000000000..49758289e
--- /dev/null
+++ b/dbaccess/source/ui/control/sqledit.cxx
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <sqledit.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/specialchars.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace dbaui;
+
+class SQLEditView::ChangesListener:
+ public cppu::WeakImplHelper< css::beans::XPropertiesChangeListener >
+{
+public:
+ explicit ChangesListener(SQLEditView& editor): editor_(editor) {}
+
+private:
+ virtual ~ChangesListener() override {}
+
+ virtual void SAL_CALL disposing(css::lang::EventObject const &) override
+ {
+ osl::MutexGuard g(editor_.m_mutex);
+ editor_.m_notifier.clear();
+ }
+
+ virtual void SAL_CALL propertiesChange(
+ css::uno::Sequence< css::beans::PropertyChangeEvent > const &) override
+ {
+ SolarMutexGuard g;
+ editor_.ImplSetFont();
+ }
+
+ SQLEditView& editor_;
+};
+
+SQLEditView::SQLEditView(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
+ : m_xScrolledWindow(std::move(xScrolledWindow))
+ , m_aUpdateDataTimer("dbaccess SQLEditView m_aUpdateDataTimer")
+ , m_aHighlighter(HighlighterLanguage::SQL)
+ , m_bInUpdate(false)
+ , m_bDisableInternalUndo(false)
+{
+ m_xScrolledWindow->connect_vadjustment_changed(LINK(this, SQLEditView, ScrollHdl));
+}
+
+void SQLEditView::DisableInternalUndo()
+{
+ GetEditEngine()->EnableUndo(false);
+ m_bDisableInternalUndo = true;
+}
+
+void SQLEditView::SetItemPoolFont(SfxItemPool* pItemPool)
+{
+ OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString()));
+ if (sFontName.isEmpty())
+ {
+ vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED, Application::GetSettings().GetUILanguageTag().getLanguageType(), GetDefaultFontFlags::OnlyOne));
+ sFontName = aTmpFont.GetFamilyName();
+ }
+
+ Size aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get());
+ vcl::Font aAppFont(sFontName, aFontSize);
+
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO));
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO_CJK));
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO_CTL));
+
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT));
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CJK));
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CTL));
+}
+
+void SQLEditView::makeEditEngine()
+{
+ assert(!m_pItemPool);
+ m_pItemPool = EditEngine::CreatePool();
+ SetItemPoolFont(m_pItemPool.get());
+ m_xEditEngine.reset(new EditEngine(m_pItemPool.get()));
+}
+
+void SQLEditView::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ WeldEditView::SetDrawingArea(pDrawingArea);
+
+ EditEngine& rEditEngine = *GetEditEngine();
+
+ rEditEngine.SetDefaultHorizontalTextDirection(EEHorizontalTextDirection::L2R);
+ rEditEngine.SetModifyHdl(LINK(this, SQLEditView, ModifyHdl));
+ rEditEngine.SetStatusEventHdl(LINK(this, SQLEditView, EditStatusHdl));
+
+ m_aUpdateDataTimer.SetTimeout(150);
+ m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SQLEditView, ImplUpdateDataHdl));
+
+ ImplSetFont();
+
+ // Listen for change of Font and Color Settings:
+ // Using "this" in ctor is a little fishy, but should work here at least as
+ // long as there are no derivations:
+ m_listener = new ChangesListener(*this);
+ css::uno::Reference< css::beans::XMultiPropertySet > n(
+ officecfg::Office::Common::Font::SourceViewFont::get(),
+ css::uno::UNO_QUERY_THROW);
+ {
+ osl::MutexGuard g(m_mutex);
+ m_notifier = n;
+ }
+ css::uno::Sequence< OUString > s { "FontHeight", "FontName" };
+ n->addPropertiesChangeListener(s, m_listener);
+ m_ColorConfig.AddListener(this);
+}
+
+SQLEditView::~SQLEditView()
+{
+ css::uno::Reference< css::beans::XMultiPropertySet > n;
+ {
+ osl::MutexGuard g(m_mutex);
+ n = m_notifier;
+ }
+ if (n.is()) {
+ n->removePropertiesChangeListener(m_listener);
+ }
+ m_ColorConfig.RemoveListener(this);
+}
+
+void SQLEditView::SetTextAndUpdate(const OUString& rNewText)
+{
+ SetText(rNewText);
+ UpdateData();
+}
+
+IMPL_LINK_NOARG(SQLEditView, ModifyHdl, LinkParamNone*, void)
+{
+ if (m_bInUpdate)
+ return;
+ m_aUpdateDataTimer.Start();
+}
+
+IMPL_LINK_NOARG(SQLEditView, ImplUpdateDataHdl, Timer*, void)
+{
+ UpdateData();
+}
+
+Color SQLEditView::GetColorValue(TokenType aToken)
+{
+ return GetSyntaxHighlightColor(m_aColorConfig, m_aHighlighter.GetLanguage(), aToken);
+}
+
+void SQLEditView::UpdateData()
+{
+ m_bInUpdate = true;
+ EditEngine& rEditEngine = *GetEditEngine();
+
+ bool bModified = rEditEngine.IsModified();
+ bool bUndoEnabled = rEditEngine.IsUndoEnabled();
+ rEditEngine.EnableUndo(false);
+
+ // syntax highlighting
+ for (sal_Int32 nLine=0; nLine < rEditEngine.GetParagraphCount(); ++nLine)
+ {
+ OUString aLine( rEditEngine.GetText( nLine ) );
+
+ ESelection aAllLine(nLine, 0, nLine, EE_TEXTPOS_ALL);
+ rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_COLOR);
+ rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT);
+ rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CJK);
+ rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CTL);
+
+ std::vector<HighlightPortion> aPortions;
+ m_aHighlighter.getHighlightPortions( aLine, aPortions );
+ for (auto const& portion : aPortions)
+ {
+ SfxItemSet aSet(rEditEngine.GetEmptyItemSet());
+ aSet.Put(SvxColorItem(GetColorValue(portion.tokenType), EE_CHAR_COLOR));
+ rEditEngine.QuickSetAttribs(aSet, ESelection(nLine, portion.nBegin, nLine, portion.nEnd));
+ }
+ }
+
+ rEditEngine.ClearModifyFlag();
+
+ m_bInUpdate = false;
+
+ rEditEngine.EnableUndo(bUndoEnabled);
+
+ if (bModified)
+ m_aModifyLink.Call(nullptr);
+
+ Invalidate();
+}
+
+void SQLEditView::DoBracketHilight(sal_uInt16 nKey)
+{
+ ESelection aCurrentPos = m_xEditView->GetSelection();
+ sal_Int32 nStartPos = aCurrentPos.nStartPos;
+ const sal_uInt32 nStartPara = aCurrentPos.nStartPara;
+ sal_uInt16 nCount = 0;
+ int nChar = -1;
+
+ switch (nKey)
+ {
+ case '\'': // no break
+ case '"':
+ {
+ nChar = nKey;
+ break;
+ }
+ case '}' :
+ {
+ nChar = '{';
+ break;
+ }
+ case ')':
+ {
+ nChar = '(';
+ break;
+ }
+ case ']':
+ {
+ nChar = '[';
+ break;
+ }
+ }
+
+ if (nChar == -1)
+ return;
+
+ bool bUndoEnabled = m_xEditEngine->IsUndoEnabled();
+ m_xEditEngine->EnableUndo(false);
+
+ sal_uInt32 nPara = nStartPara;
+ do
+ {
+ if (nPara == nStartPara && nStartPos == 0)
+ continue;
+
+ OUString aLine( m_xEditEngine->GetText( nPara ) );
+
+ if (aLine.isEmpty())
+ continue;
+
+ for (sal_Int32 i = (nPara==nStartPara) ? nStartPos-1 : aLine.getLength()-1; i>0; --i)
+ {
+ if (aLine[i] == nChar)
+ {
+ if (!nCount)
+ {
+ SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
+ aSet.Put(SvxColorItem(Color(0,0,0), EE_CHAR_COLOR));
+ aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT));
+ aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CJK));
+ aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CTL));
+
+ m_xEditEngine->QuickSetAttribs(aSet, ESelection(nPara, i, nPara, i + 1));
+ m_xEditEngine->QuickSetAttribs(aSet, ESelection(nStartPara, nStartPos, nStartPara, nStartPos));
+ return;
+ }
+ else
+ --nCount;
+ }
+ if (aLine[i] == nKey)
+ ++nCount;
+ }
+ } while (nPara--);
+
+ m_xEditEngine->EnableUndo(bUndoEnabled);
+}
+
+Color SQLEditView::GetSyntaxHighlightColor(const svtools::ColorConfig& rColorConfig, HighlighterLanguage eLanguage, TokenType aToken)
+{
+ Color aColor;
+ switch (eLanguage)
+ {
+ case HighlighterLanguage::SQL:
+ {
+ switch (aToken)
+ {
+ case TokenType::Identifier: aColor = rColorConfig.GetColorValue(svtools::SQLIDENTIFIER).nColor; break;
+ case TokenType::Number: aColor = rColorConfig.GetColorValue(svtools::SQLNUMBER).nColor; break;
+ case TokenType::String: aColor = rColorConfig.GetColorValue(svtools::SQLSTRING).nColor; break;
+ case TokenType::Operator: aColor = rColorConfig.GetColorValue(svtools::SQLOPERATOR).nColor; break;
+ case TokenType::Keywords: aColor = rColorConfig.GetColorValue(svtools::SQLKEYWORD).nColor; break;
+ case TokenType::Parameter: aColor = rColorConfig.GetColorValue(svtools::SQLPARAMETER).nColor; break;
+ case TokenType::Comment: aColor = rColorConfig.GetColorValue(svtools::SQLCOMMENT).nColor; break;
+ default: aColor = Color(0,0,0);
+ }
+ break;
+ }
+ case HighlighterLanguage::Basic:
+ {
+ switch (aToken)
+ {
+ case TokenType::Identifier: aColor = Color(255,0,0); break;
+ case TokenType::Comment: aColor = Color(0,0,45); break;
+ case TokenType::Number: aColor = Color(204,102,204); break;
+ case TokenType::String: aColor = Color(0,255,45); break;
+ case TokenType::Operator: aColor = Color(0,0,100); break;
+ case TokenType::Keywords: aColor = Color(0,0,255); break;
+ case TokenType::Error : aColor = Color(0,255,255); break;
+ default: aColor = Color(0,0,0);
+ }
+ break;
+ }
+ default: aColor = Color(0,0,0);
+
+ }
+ return aColor;
+}
+
+bool SQLEditView::KeyInput(const KeyEvent& rKEvt)
+{
+ DoBracketHilight(rKEvt.GetCharCode());
+
+ if (m_bDisableInternalUndo)
+ {
+ KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
+ if (eFunc == KeyFuncType::UNDO || eFunc == KeyFuncType::REDO)
+ return false;
+ }
+
+ return WeldEditView::KeyInput(rKEvt);
+}
+
+bool SQLEditView::Command(const CommandEvent& rCEvt)
+{
+ if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
+ {
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Widget* pPopupParent = GetDrawingArea();
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "vcl/ui/editmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+
+ bool bEnableCut = true;
+ bool bEnableCopy = true;
+ bool bEnableDelete = true;
+ bool bEnablePaste = true;
+ bool bEnableSpecialChar = true;
+
+ EditView* pEditView = GetEditView();
+
+ if (!pEditView->HasSelection())
+ {
+ bEnableCut = false;
+ bEnableCopy = false;
+ bEnableDelete = false;
+ }
+
+ if (pEditView->IsReadOnly())
+ {
+ bEnableCut = false;
+ bEnablePaste = false;
+ bEnableDelete = false;
+ bEnableSpecialChar = false;
+ }
+
+ xContextMenu->set_sensitive("cut", bEnableCut);
+ xContextMenu->set_sensitive("copy", bEnableCopy);
+ xContextMenu->set_sensitive("delete", bEnableDelete);
+ xContextMenu->set_sensitive("paste", bEnablePaste);
+ xContextMenu->set_sensitive("specialchar", bEnableSpecialChar);
+ xContextMenu->set_visible("undo", false);
+ xContextMenu->set_visible("specialchar", vcl::GetGetSpecialCharsFunction() != nullptr);
+
+ OString sCommand = xContextMenu->popup_at_rect(pPopupParent, aRect);
+
+ if (sCommand == "cut")
+ pEditView->Cut();
+ else if (sCommand == "copy")
+ pEditView->Copy();
+ else if (sCommand == "paste")
+ pEditView->Paste();
+ else if (sCommand == "delete")
+ pEditView->DeleteSelected();
+ else if (sCommand == "selectall")
+ {
+ sal_Int32 nPar = m_xEditEngine->GetParagraphCount();
+ if (nPar)
+ {
+ sal_Int32 nLen = m_xEditEngine->GetTextLen(nPar - 1);
+ pEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen));
+ }
+ }
+ else if (sCommand == "specialchar")
+ {
+ OUString aChars = vcl::GetGetSpecialCharsFunction()(pPopupParent, m_xEditEngine->GetStandardFont(0));
+ if (!aChars.isEmpty())
+ {
+ pEditView->InsertText(aChars);
+ }
+ }
+
+ return true;
+ }
+ return WeldEditView::Command(rCEvt);
+}
+
+void SQLEditView::EditViewScrollStateChange()
+{
+ // editengine height has changed or editview scroll pos has changed
+ SetScrollBarRange();
+}
+
+void SQLEditView::SetScrollBarRange()
+{
+ EditEngine *pEditEngine = GetEditEngine();
+ if (!pEditEngine)
+ return;
+ if (!m_xScrolledWindow)
+ return;
+ EditView* pEditView = GetEditView();
+ if (!pEditView)
+ return;
+
+ int nVUpper = pEditEngine->GetTextHeight();
+ int nVCurrentDocPos = pEditView->GetVisArea().Top();
+ const Size aOut(pEditView->GetOutputArea().GetSize());
+ int nVStepIncrement = aOut.Height() * 2 / 10;
+ int nVPageIncrement = aOut.Height() * 8 / 10;
+ int nVPageSize = aOut.Height();
+
+ /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
+ effectively...
+
+ lower = gtk_adjustment_get_lower
+ upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
+
+ and requires that upper > lower or the deceleration animation never ends
+ */
+ nVPageSize = std::min(nVPageSize, nVUpper);
+
+ m_xScrolledWindow->vadjustment_configure(nVCurrentDocPos, 0, nVUpper,
+ nVStepIncrement, nVPageIncrement, nVPageSize);
+}
+
+IMPL_LINK_NOARG(SQLEditView, ScrollHdl, weld::ScrolledWindow&, void)
+{
+ DoScroll();
+}
+
+IMPL_LINK_NOARG(SQLEditView, EditStatusHdl, EditStatus&, void)
+{
+ Resize();
+}
+
+void SQLEditView::DoScroll()
+{
+ if (m_xEditView)
+ {
+ auto currentDocPos = m_xEditView->GetVisArea().Top();
+ auto nDiff = currentDocPos - m_xScrolledWindow->vadjustment_get_value();
+ // we expect SetScrollBarRange callback to be triggered by Scroll
+ // to set where we ended up
+ m_xEditView->Scroll(0, nDiff);
+ }
+}
+
+void SQLEditView::ConfigurationChanged(utl::ConfigurationBroadcaster*, ConfigurationHints)
+{
+ UpdateData();
+}
+
+void SQLEditView::ImplSetFont()
+{
+ // see SmEditWindow::DataChanged for a similar case
+ SetItemPoolFont(m_pItemPool.get()); // change default font
+ // re-create with the new font
+ EditEngine& rEditEngine = *GetEditEngine();
+ OUString aTxt(rEditEngine.GetText());
+ rEditEngine.Clear();
+ SetTextAndUpdate(aTxt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/tabletree.cxx b/dbaccess/source/ui/control/tabletree.cxx
new file mode 100644
index 000000000..2c3f0976f
--- /dev/null
+++ b/dbaccess/source/ui/control/tabletree.cxx
@@ -0,0 +1,707 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <tabletree.hxx>
+#include <imageprovider.hxx>
+#include <strings.hrc>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <connectivity/dbmetadata.hxx>
+
+#include <algorithm>
+
+namespace dbaui
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb::application;
+
+using namespace ::dbtools;
+using namespace ::comphelper;
+
+namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject;
+namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer;
+
+// OTableTreeListBox
+OTableTreeListBox::OTableTreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bShowToggles)
+ : TreeListBox(std::move(xTreeView), true)
+ , m_xImageProvider(new ImageProvider)
+ , m_bVirtualRoot(false)
+ , m_bNoEmptyFolders(false)
+ , m_bShowToggles(bShowToggles)
+{
+ if (m_bShowToggles)
+ m_xTreeView->enable_toggle_buttons(weld::ColumnToggleType::Check);
+}
+
+bool OTableTreeListBox::isFolderEntry(const weld::TreeIter& rEntry) const
+{
+ sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32();
+ return ( nEntryType == DatabaseObjectContainer::TABLES )
+ || ( nEntryType == DatabaseObjectContainer::CATALOG )
+ || ( nEntryType == DatabaseObjectContainer::SCHEMA );
+}
+
+void OTableTreeListBox::implOnNewConnection( const Reference< XConnection >& _rxConnection )
+{
+ m_xConnection = _rxConnection;
+ m_xImageProvider.reset( new ImageProvider( m_xConnection ) );
+}
+
+void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection )
+{
+ Sequence< OUString > sTables, sViews;
+
+ OUString sCurrentActionError;
+ try
+ {
+ Reference< XTablesSupplier > xTableSupp( _rxConnection, UNO_QUERY_THROW );
+ sCurrentActionError = DBA_RES(STR_NOTABLEINFO);
+
+ Reference< XNameAccess > xTables,xViews;
+
+ Reference< XViewsSupplier > xViewSupp( _rxConnection, UNO_QUERY );
+ if ( xViewSupp.is() )
+ {
+ xViews = xViewSupp->getViews();
+ if (xViews.is())
+ sViews = xViews->getElementNames();
+ }
+
+ xTables = xTableSupp->getTables();
+ if (xTables.is())
+ sTables = xTables->getElementNames();
+ }
+ catch(RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "OTableTreeListBox::UpdateTableList");
+ }
+ catch ( const SQLException& )
+ {
+ throw;
+ }
+ catch(Exception&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ // a non-SQLException exception occurred ... simply throw an SQLException
+ throw SQLException(sCurrentActionError, nullptr, "", 0, anyEx);
+ }
+
+ UpdateTableList( _rxConnection, sTables, sViews );
+}
+
+namespace
+{
+ struct OViewSetter
+ {
+ const Sequence< OUString> m_aViews;
+ ::comphelper::UStringMixEqual m_aEqualFunctor;
+
+ OViewSetter(const Sequence< OUString>& _rViews,bool _bCase) : m_aViews(_rViews),m_aEqualFunctor(_bCase){}
+ OTableTreeListBox::TNames::value_type operator() (const OUString& name)
+ {
+ OTableTreeListBox::TNames::value_type aRet;
+ aRet.first = name;
+ aRet.second = std::any_of(m_aViews.begin(), m_aViews.end(),
+ [this, &name](const OUString& lhs)
+ { return m_aEqualFunctor(lhs, name); } );
+
+ return aRet;
+ }
+ };
+
+}
+
+void OTableTreeListBox::UpdateTableList(
+ const Reference< XConnection >& _rxConnection,
+ const Sequence< OUString>& _rTables,
+ const Sequence< OUString>& _rViews
+ )
+{
+ TNames aTables;
+ aTables.resize(_rTables.getLength());
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW );
+ std::transform( _rTables.begin(), _rTables.end(),
+ aTables.begin(), OViewSetter( _rViews, xMeta->supportsMixedCaseQuotedIdentifiers() ) );
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ UpdateTableList( _rxConnection, aTables );
+}
+
+namespace
+{
+ std::vector< OUString > lcl_getMetaDataStrings_throw( const Reference< XResultSet >& _rxMetaDataResult, sal_Int32 _nColumnIndex )
+ {
+ std::vector< OUString > aStrings;
+ Reference< XRow > xRow( _rxMetaDataResult, UNO_QUERY_THROW );
+ while ( _rxMetaDataResult->next() )
+ aStrings.push_back( xRow->getString( _nColumnIndex ) );
+ return aStrings;
+ }
+
+ bool lcl_shouldDisplayEmptySchemasAndCatalogs( const Reference< XConnection >& _rxConnection )
+ {
+ ::dbtools::DatabaseMetaData aMetaData( _rxConnection );
+ return aMetaData.displayEmptyTableFolders();
+ }
+}
+
+void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection, const TNames& _rTables )
+{
+ implOnNewConnection( _rxConnection );
+
+ // throw away all the old stuff
+ m_xTreeView->clear();
+ m_xTreeView->make_unsorted();
+
+ try
+ {
+ if (haveVirtualRoot())
+ {
+ OUString sRootEntryText;
+ if ( std::none_of(_rTables.begin(),_rTables.end(),
+ [] (const TNames::value_type& name) { return !name.second; }) )
+ sRootEntryText = DBA_RES(STR_ALL_TABLES);
+ else if ( std::none_of(_rTables.begin(),_rTables.end(),
+ [] (const TNames::value_type& name) { return name.second; }) )
+ sRootEntryText = DBA_RES(STR_ALL_VIEWS);
+ else
+ sRootEntryText = DBA_RES(STR_ALL_TABLES_AND_VIEWS);
+ OUString sId(OUString::number(DatabaseObjectContainer::TABLES));
+ OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
+ std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator());
+ m_xTreeView->insert(nullptr, -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
+ m_xTreeView->set_image(*xRet, sImageId, -1);
+ if (m_bShowToggles)
+ m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE);
+ m_xTreeView->set_text(*xRet, sRootEntryText, 0);
+ m_xTreeView->set_text_emphasis(*xRet, false, 0);
+ }
+
+ if ( _rTables.empty() )
+ // nothing to do (besides inserting the root entry)
+ return;
+
+ // get the table/view names
+ Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW );
+ for (auto const& table : _rTables)
+ {
+ // add the entry
+ implAddEntry(xMeta, table.first, false);
+ }
+
+ if ( !m_bNoEmptyFolders && lcl_shouldDisplayEmptySchemasAndCatalogs( _rxConnection ) )
+ {
+ bool bSupportsCatalogs = xMeta->supportsCatalogsInDataManipulation();
+ bool bSupportsSchemas = xMeta->supportsSchemasInDataManipulation();
+
+ if ( bSupportsCatalogs || bSupportsSchemas )
+ {
+ // we display empty catalogs if the DB supports catalogs, and they're noted at the beginning of a
+ // composed name. Otherwise, we display empty schematas. (also see the tree structure explained in
+ // implAddEntry)
+ bool bCatalogs = bSupportsCatalogs && xMeta->isCatalogAtStart();
+
+ std::vector< OUString > aFolderNames( lcl_getMetaDataStrings_throw(
+ bCatalogs ? xMeta->getCatalogs() : xMeta->getSchemas(), 1 ) );
+ sal_Int32 nFolderType = bCatalogs ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA;
+
+ OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
+
+ std::unique_ptr<weld::TreeIter> xRootEntry(getAllObjectsEntry());
+ std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator());
+ for (auto const& folderName : aFolderNames)
+ {
+ std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(folderName, xRootEntry.get()));
+ if (!xFolder)
+ {
+ OUString sId(OUString::number(nFolderType));
+ m_xTreeView->insert(xRootEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
+ m_xTreeView->set_image(*xRet, sImageId, -1);
+ if (m_bShowToggles)
+ m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE);
+ m_xTreeView->set_text(*xRet, folderName, 0);
+ m_xTreeView->set_text_emphasis(*xRet, false, 0);
+ }
+ }
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xTreeView->make_sorted();
+}
+
+bool OTableTreeListBox::isWildcardChecked(const weld::TreeIter& rEntry)
+{
+ return m_xTreeView->get_text_emphasis(rEntry, 0);
+}
+
+void OTableTreeListBox::checkWildcard(const weld::TreeIter& rEntry)
+{
+ if (!m_bShowToggles)
+ return;
+ m_xTreeView->set_toggle(rEntry, TRISTATE_TRUE);
+ checkedButton_noBroadcast(rEntry);
+}
+
+std::unique_ptr<weld::TreeIter> OTableTreeListBox::getAllObjectsEntry() const
+{
+ if (!haveVirtualRoot())
+ return nullptr;
+ auto xRet = m_xTreeView->make_iterator();
+ if (!m_xTreeView->get_iter_first(*xRet))
+ return nullptr;
+ return xRet;
+}
+
+void OTableTreeListBox::checkedButton_noBroadcast(const weld::TreeIter& rEntry)
+{
+ if (!m_bShowToggles)
+ return;
+ TriState eState = m_xTreeView->get_toggle(rEntry);
+ OSL_ENSURE(TRISTATE_INDET != eState, "OTableTreeListBox::CheckButtonHdl: user action which lead to TRISTATE?");
+
+ if (m_xTreeView->iter_has_child(rEntry)) // if it has children, check those too
+ {
+ std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rEntry));
+ std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rEntry));
+ bool bChildEntry = m_xTreeView->iter_next(*xChildEntry);
+ bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry);
+ while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry)))
+ {
+ m_xTreeView->set_toggle(*xChildEntry, eState);
+ bChildEntry = m_xTreeView->iter_next(*xChildEntry);
+ }
+ }
+
+ if (m_xTreeView->is_selected(rEntry))
+ {
+ m_xTreeView->selected_foreach([this, eState](weld::TreeIter& rSelected){
+ m_xTreeView->set_toggle(rSelected, eState);
+ if (m_xTreeView->iter_has_child(rSelected)) // if it has children, check those too
+ {
+ std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rSelected));
+ std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rSelected));
+ bool bChildEntry = m_xTreeView->iter_next(*xChildEntry);
+ bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry);
+ while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry)))
+ {
+ m_xTreeView->set_toggle(*xChildEntry, eState);
+ bChildEntry = m_xTreeView->iter_next(*xChildEntry);
+ }
+ }
+ return false;
+ });
+ }
+
+ CheckButtons();
+
+ // if an entry has children, it makes a difference if the entry is checked
+ // because all children are checked or if the user checked it explicitly.
+ // So we track explicit (un)checking
+ implEmphasize(rEntry, eState == TRISTATE_TRUE);
+}
+
+void OTableTreeListBox::implEmphasize(const weld::TreeIter& rEntry, bool _bChecked, bool _bUpdateDescendants, bool _bUpdateAncestors)
+{
+ // special emphasizing handling for the "all objects" entry
+ bool bAllObjectsEntryAffected = haveVirtualRoot() && (getAllObjectsEntry()->equal(rEntry));
+ if ( m_xTreeView->iter_has_child(rEntry) // the entry has children
+ || bAllObjectsEntryAffected // or it is the "all objects" entry
+ )
+ {
+ m_xTreeView->set_text_emphasis(rEntry, _bChecked, 0);
+ }
+
+ if (_bUpdateDescendants)
+ {
+ std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry));
+ // remove the mark for all children of the checked entry
+ bool bChildLoop = m_xTreeView->iter_children(*xChild);
+ while (bChildLoop)
+ {
+ if (m_xTreeView->iter_has_child(*xChild))
+ implEmphasize(*xChild, false, true, false);
+ bChildLoop = m_xTreeView->iter_next_sibling(*xChild);
+ }
+ }
+
+ if (_bUpdateAncestors)
+ {
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
+ // remove the mark for all ancestors of the entry
+ if (m_xTreeView->iter_parent(*xParent))
+ implEmphasize(*xParent, false, false);
+ }
+}
+
+std::unique_ptr<weld::TreeIter> OTableTreeListBox::implAddEntry(
+ const Reference< XDatabaseMetaData >& _rxMeta,
+ const OUString& _rTableName,
+ bool _bCheckName
+ )
+{
+ OSL_PRECOND( _rxMeta.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" );
+ if ( !_rxMeta.is() )
+ return nullptr;
+
+ // split the complete name into its components
+ OUString sCatalog, sSchema, sName;
+ qualifiedNameComponents( _rxMeta, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
+
+ std::unique_ptr<weld::TreeIter> xParentEntry(getAllObjectsEntry());
+
+ // if the DB uses catalog at the start of identifiers, then our hierarchy is
+ // catalog
+ // +- schema
+ // +- table
+ // else it is
+ // schema
+ // +- catalog
+ // +- table
+ bool bCatalogAtStart = _rxMeta->isCatalogAtStart();
+ const OUString& rFirstName = bCatalogAtStart ? sCatalog : sSchema;
+ const sal_Int32 nFirstFolderType = bCatalogAtStart ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA;
+ const OUString& rSecondName = bCatalogAtStart ? sSchema : sCatalog;
+ const sal_Int32 nSecondFolderType = bCatalogAtStart ? DatabaseObjectContainer::SCHEMA : DatabaseObjectContainer::CATALOG;
+
+ if ( !rFirstName.isEmpty() )
+ {
+ std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rFirstName, xParentEntry.get()));
+ if (!xFolder)
+ {
+ xFolder = m_xTreeView->make_iterator();
+ OUString sId(OUString::number(nFirstFolderType));
+ OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
+ m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xFolder.get());
+ m_xTreeView->set_image(*xFolder, sImageId, -1);
+ if (m_bShowToggles)
+ m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE);
+ m_xTreeView->set_text(*xFolder, rFirstName, 0);
+ m_xTreeView->set_text_emphasis(*xFolder, false, 0);
+ }
+ xParentEntry = std::move(xFolder);
+ }
+
+ if ( !rSecondName.isEmpty() )
+ {
+ std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rSecondName, xParentEntry.get()));
+ if (!xFolder)
+ {
+ xFolder = m_xTreeView->make_iterator();
+ OUString sId(OUString::number(nSecondFolderType));
+ OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
+ m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xFolder.get());
+ m_xTreeView->set_image(*xFolder, sImageId, -1);
+ if (m_bShowToggles)
+ m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE);
+ m_xTreeView->set_text(*xFolder, rSecondName, 0);
+ m_xTreeView->set_text_emphasis(*xFolder, false, 0);
+ }
+ xParentEntry = std::move(xFolder);
+ }
+
+ if (!_bCheckName || !GetEntryPosByName(sName, xParentEntry.get()))
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ m_xTreeView->insert(xParentEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xEntry.get());
+
+ auto xGraphic = m_xImageProvider->getXGraphic(_rTableName, DatabaseObject::TABLE);
+ if (xGraphic.is())
+ m_xTreeView->set_image(*xEntry, xGraphic, -1);
+ else
+ {
+ OUString sImageId(m_xImageProvider->getImageId(_rTableName, DatabaseObject::TABLE));
+ m_xTreeView->set_image(*xEntry, sImageId, -1);
+ }
+ if (m_bShowToggles)
+ m_xTreeView->set_toggle(*xEntry, TRISTATE_FALSE);
+ m_xTreeView->set_text(*xEntry, sName, 0);
+ m_xTreeView->set_text_emphasis(*xEntry, false, 0);
+
+ return xEntry;
+ }
+
+ return nullptr;
+}
+
+NamedDatabaseObject OTableTreeListBox::describeObject(const weld::TreeIter& rEntry)
+{
+ NamedDatabaseObject aObject;
+
+ sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32();
+
+ if ( nEntryType == DatabaseObjectContainer::TABLES )
+ {
+ aObject.Type = DatabaseObjectContainer::TABLES;
+ }
+ else if ( ( nEntryType == DatabaseObjectContainer::CATALOG )
+ || ( nEntryType == DatabaseObjectContainer::SCHEMA )
+ )
+ {
+ // nothing useful to be done
+ }
+ else
+ {
+ aObject.Type = DatabaseObject::TABLE;
+ aObject.Name = getQualifiedTableName(rEntry);
+ }
+
+ return aObject;
+}
+
+std::unique_ptr<weld::TreeIter> OTableTreeListBox::addedTable(const OUString& rName)
+{
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta;
+ if ( impl_getAndAssertMetaData( xMeta ) )
+ return implAddEntry( xMeta, rName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return nullptr;
+}
+
+bool OTableTreeListBox::impl_getAndAssertMetaData( Reference< XDatabaseMetaData >& _out_rMetaData ) const
+{
+ if ( m_xConnection.is() )
+ _out_rMetaData = m_xConnection->getMetaData();
+ OSL_PRECOND( _out_rMetaData.is(), "OTableTreeListBox::impl_getAndAssertMetaData: invalid current connection!" );
+ return _out_rMetaData.is();
+}
+
+OUString OTableTreeListBox::getQualifiedTableName(const weld::TreeIter& rEntry) const
+{
+ OSL_PRECOND( !isFolderEntry(rEntry), "OTableTreeListBox::getQualifiedTableName: folder entries not allowed here!" );
+
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta;
+ if ( !impl_getAndAssertMetaData( xMeta ) )
+ return OUString();
+
+ OUString sCatalog;
+ OUString sSchema;
+ OUString sTable;
+
+ std::unique_ptr<weld::TreeIter> xSchema(m_xTreeView->make_iterator(&rEntry));
+ bool bSchema = m_xTreeView->iter_parent(*xSchema);
+ if (bSchema)
+ {
+ std::unique_ptr<weld::TreeIter> xCatalog(m_xTreeView->make_iterator(xSchema.get()));
+ bool bCatalog = m_xTreeView->iter_parent(*xCatalog);
+ if ( bCatalog
+ || ( xMeta->supportsCatalogsInDataManipulation()
+ && !xMeta->supportsSchemasInDataManipulation()
+ ) // here we support catalog but no schema
+ )
+ {
+ if (!bCatalog)
+ {
+ xCatalog = std::move(xSchema);
+ bSchema = false;
+ }
+ sCatalog = m_xTreeView->get_text(*xCatalog);
+ }
+ if (bSchema)
+ sSchema = m_xTreeView->get_text(*xSchema);
+ }
+ sTable = m_xTreeView->get_text(rEntry);
+
+ return ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return OUString();
+}
+
+std::unique_ptr<weld::TreeIter> OTableTreeListBox::getEntryByQualifiedName(const OUString& rName)
+{
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta;
+ if ( !impl_getAndAssertMetaData( xMeta ) )
+ return nullptr;
+
+ // split the complete name into its components
+ OUString sCatalog, sSchema, sName;
+ qualifiedNameComponents(xMeta, rName, sCatalog, sSchema, sName,::dbtools::EComposeRule::InDataManipulation);
+
+ std::unique_ptr<weld::TreeIter> xParent(getAllObjectsEntry());
+ std::unique_ptr<weld::TreeIter> xCat;
+ std::unique_ptr<weld::TreeIter> xSchema;
+ if (!sCatalog.isEmpty())
+ {
+ xCat = GetEntryPosByName(sCatalog);
+ if (xCat)
+ xParent = std::move(xCat);
+ }
+
+ if (!sSchema.isEmpty())
+ {
+ xSchema = GetEntryPosByName(sSchema, xParent.get());
+ if (xSchema)
+ xParent = std::move(xSchema);
+ }
+
+ return GetEntryPosByName(sName, xParent.get());
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return nullptr;
+}
+
+void OTableTreeListBox::removedTable(const OUString& rName)
+{
+ try
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = getEntryByQualifiedName(rName);
+ if (xEntry)
+ m_xTreeView->remove(*xEntry);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OTableTreeListBox::CheckButtons()
+{
+ if (!m_bShowToggles)
+ return;
+
+ auto xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_iter_first(*xEntry))
+ return;
+
+ do
+ {
+ implDetermineState(*xEntry);
+ } while (m_xTreeView->iter_next_sibling(*xEntry));
+}
+
+TriState OTableTreeListBox::implDetermineState(const weld::TreeIter& rEntry)
+{
+ if (!m_bShowToggles)
+ return TRISTATE_FALSE;
+
+ TriState eState = m_xTreeView->get_toggle(rEntry);
+ if (!m_xTreeView->iter_has_child(rEntry))
+ // nothing to do in this bottom-up routine if there are no children ...
+ return eState;
+
+ // loop through the children and check their states
+ sal_uInt16 nCheckedChildren = 0;
+ sal_uInt16 nChildrenOverall = 0;
+
+ std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry));
+ bool bChildLoop = m_xTreeView->iter_children(*xChild);
+ while (bChildLoop)
+ {
+ TriState eChildState = implDetermineState(*xChild);
+ if (eChildState == TRISTATE_INDET)
+ break;
+ if (eChildState == TRISTATE_TRUE)
+ ++nCheckedChildren;
+ ++nChildrenOverall;
+ bChildLoop = m_xTreeView->iter_next_sibling(*xChild);
+ }
+
+ if (bChildLoop)
+ {
+ // we did not finish the loop because at least one of the children is in tristate
+ eState = TRISTATE_INDET;
+
+ // but this means that we did not finish all the siblings of pChildLoop,
+ // so their checking may be incorrect at the moment
+ // -> correct this
+ while (bChildLoop)
+ {
+ implDetermineState(*xChild);
+ bChildLoop = m_xTreeView->iter_next_sibling(*xChild);
+ }
+ }
+ else
+ {
+ // none if the children are in tristate
+ if (nCheckedChildren)
+ {
+ // we have at least one child checked
+ if (nCheckedChildren != nChildrenOverall)
+ {
+ // not all children are checked
+ eState = TRISTATE_INDET;
+ }
+ else
+ {
+ // all children are checked
+ eState = TRISTATE_TRUE;
+ }
+ }
+ else
+ {
+ // no children are checked
+ eState = TRISTATE_FALSE;
+ }
+ }
+
+ // finally set the entry to the state we just determined
+ m_xTreeView->set_toggle(rEntry, eState);
+
+ return eState;
+}
+
+DBTableTreeView::DBTableTreeView(weld::Container* pContainer)
+ : DBTreeViewBase(pContainer)
+{
+ m_xTreeListBox.reset(new OTableTreeListBox(m_xBuilder->weld_tree_view("treeview"), /*bShowToggles*/false));
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/control/undosqledit.cxx b/dbaccess/source/ui/control/undosqledit.cxx
new file mode 100644
index 000000000..00a5fd407
--- /dev/null
+++ b/dbaccess/source/ui/control/undosqledit.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undosqledit.hxx>
+#include <QueryTextView.hxx>
+
+namespace dbaui
+{
+void OSqlEditUndoAct::ToggleText()
+{
+ OUString strNext = m_rOwner.GetSQLText();
+ m_rOwner.SetSQLText(m_strNextText);
+ m_strNextText = strNext;
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/CollectionView.cxx b/dbaccess/source/ui/dlg/CollectionView.cxx
new file mode 100644
index 000000000..2e02fda50
--- /dev/null
+++ b/dbaccess/source/ui/dlg/CollectionView.cxx
@@ -0,0 +1,316 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <CollectionView.hxx>
+#include <tools/diagnose_ex.h>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <comphelper/interaction.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <UITools.hxx>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+#include <com/sun/star/ucb/XDynamicResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/task/InteractionClassification.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <comphelper/processfactory.hxx>
+#include <ucbhelper/commandenvironment.hxx>
+#include <ucbhelper/content.hxx>
+#include <connectivity/dbexception.hxx>
+
+namespace dbaui
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::sdbc;
+using namespace comphelper;
+
+OCollectionView::OCollectionView(weld::Window* pParent,
+ const Reference< XContent>& _xContent,
+ const OUString& _sDefaultName,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext)
+ : GenericDialogController(pParent, "dbaccess/ui/collectionviewdialog.ui", "CollectionView")
+ , m_xContent(_xContent)
+ , m_xContext(_rxContext)
+ , m_bCreateForm(true)
+ , m_xFTCurrentPath(m_xBuilder->weld_label("currentPathLabel"))
+ , m_xNewFolder(m_xBuilder->weld_button("newFolderButton"))
+ , m_xUp(m_xBuilder->weld_button("upButton"))
+ , m_xView(m_xBuilder->weld_tree_view("viewTreeview"))
+ , m_xName(m_xBuilder->weld_entry("fileNameEntry"))
+ , m_xPB_OK(m_xBuilder->weld_button("ok"))
+{
+ Reference<XInteractionHandler2> xHandler(
+ InteractionHandler::createWithParent(m_xContext, m_xDialog->GetXWindow()));
+ m_xCmdEnv = new ::ucbhelper::CommandEnvironment(xHandler, nullptr);
+
+ OSL_ENSURE(m_xContent.is(),"No valid content!");
+ m_xView->set_size_request(m_xView->get_approximate_digit_width() * 60, m_xView->get_height_rows(8));
+ m_xView->make_sorted();
+ Initialize();
+ initCurrentPath();
+
+ m_xName->set_text(_sDefaultName);
+ m_xName->grab_focus();
+
+ m_xView->connect_row_activated( LINK( this, OCollectionView, Dbl_Click_FileView ) );
+ m_xUp->connect_clicked( LINK( this, OCollectionView, Up_Click ) );
+ m_xNewFolder->connect_clicked( LINK( this, OCollectionView, NewFolder_Click ) );
+ m_xPB_OK->connect_clicked( LINK( this, OCollectionView, Save_Click ) );
+}
+
+OCollectionView::~OCollectionView()
+{
+}
+
+IMPL_LINK_NOARG(OCollectionView, Save_Click, weld::Button&, void)
+{
+ OUString sName = m_xName->get_text();
+ if (sName.isEmpty())
+ return;
+ try
+ {
+ sal_Int32 nIndex = sName.lastIndexOf('/') + 1;
+ if ( nIndex )
+ {
+ if ( nIndex == 1 ) // special handling for root
+ {
+ Reference<XChild> xChild(m_xContent,UNO_QUERY);
+ Reference<XNameAccess> xNameAccess(xChild,UNO_QUERY);
+ while( xNameAccess.is() )
+ {
+ xNameAccess.set(xChild->getParent(),UNO_QUERY);
+ if ( xNameAccess.is() )
+ {
+ m_xContent.set(xNameAccess,UNO_QUERY);
+ xChild.set(m_xContent,UNO_QUERY);
+ }
+ }
+ Initialize();
+ initCurrentPath();
+ }
+ OUString sSubFolder = sName.copy(0,nIndex-1);
+ sName = sName.copy(nIndex);
+ Reference<XHierarchicalNameContainer> xHier(m_xContent,UNO_QUERY);
+ OSL_ENSURE(xHier.is(),"XHierarchicalNameContainer not supported!");
+ if ( !sSubFolder.isEmpty() && xHier.is() )
+ {
+ if ( xHier->hasByHierarchicalName(sSubFolder) )
+ {
+ m_xContent.set(xHier->getByHierarchicalName(sSubFolder),UNO_QUERY);
+ }
+ else // sub folder doesn't exist
+ {
+ Sequence<Any> aValues(comphelper::InitAnyPropertySequence(
+ {
+ {"ResourceName", Any(sSubFolder)},
+ {"ResourceType", Any(OUString("folder"))}
+ }));
+ InteractiveAugmentedIOException aException(OUString(),Reference<XInterface>(),
+ InteractionClassification_ERROR,
+ IOErrorCode_NOT_EXISTING_PATH,aValues);
+
+ Reference<XInteractionHandler2> xHandler(
+ InteractionHandler::createWithParent(m_xContext, m_xDialog->GetXWindow()));
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aException));
+
+ rtl::Reference<OInteractionApprove> pApprove = new OInteractionApprove;
+ pRequest->addContinuation(pApprove);
+ xHandler->handle(pRequest);
+
+ return;
+ }
+ }
+ }
+ Reference<XNameContainer> xNameContainer(m_xContent,UNO_QUERY);
+ if ( xNameContainer.is() )
+ {
+ if ( xNameContainer->hasByName(sName) )
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ DBA_RES(STR_ALREADYEXISTOVERWRITE)));
+ if (xQueryBox->run() != RET_YES)
+ return;
+ }
+ m_xName->set_text(sName);
+ m_xDialog->response(RET_OK);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+IMPL_LINK_NOARG(OCollectionView, NewFolder_Click, weld::Button&, void)
+{
+ try
+ {
+ Reference<XHierarchicalNameContainer> xNameContainer(m_xContent,UNO_QUERY);
+ if ( dbaui::insertHierarchyElement(m_xDialog.get(),m_xContext,xNameContainer,OUString(),m_bCreateForm) )
+ Initialize();
+ }
+ catch( const SQLException& )
+ {
+ showError(::dbtools::SQLExceptionInfo(::cppu::getCaughtException()), m_xDialog->GetXWindow(), m_xContext);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+IMPL_LINK_NOARG(OCollectionView, Up_Click, weld::Button&, void)
+{
+ try
+ {
+ Reference<XChild> xChild(m_xContent,UNO_QUERY);
+ if ( xChild.is() )
+ {
+ Reference<XNameAccess> xNameAccess(xChild->getParent(),UNO_QUERY);
+ if ( xNameAccess.is() )
+ {
+ m_xContent.set(xNameAccess,UNO_QUERY);
+ Initialize();
+ initCurrentPath();
+ }
+ else
+ m_xUp->set_sensitive(false);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+IMPL_LINK_NOARG(OCollectionView, Dbl_Click_FileView, weld::TreeView&, bool)
+{
+ try
+ {
+ Reference<XNameAccess> xNameAccess(m_xContent,UNO_QUERY);
+ if ( xNameAccess.is() )
+ {
+ OUString sSubFolder = m_xView->get_selected_text();
+ if (!sSubFolder.isEmpty())
+ {
+ Reference< XContent> xContent;
+ if ( xNameAccess->hasByName(sSubFolder) )
+ xContent.set(xNameAccess->getByName(sSubFolder),UNO_QUERY);
+ if ( xContent.is() )
+ {
+ m_xContent = xContent;
+ Initialize();
+ initCurrentPath();
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return true;
+}
+
+void OCollectionView::initCurrentPath()
+{
+ bool bEnable = false;
+ try
+ {
+ if ( m_xContent.is() )
+ {
+ const OUString sCID = m_xContent->getIdentifier()->getContentIdentifier();
+ static const char s_sFormsCID[] = "private:forms";
+ static const char s_sReportsCID[] = "private:reports";
+ m_bCreateForm = s_sFormsCID == sCID;
+ OUString sPath("/");
+ if ( m_bCreateForm && o3tl::make_unsigned(sCID.getLength()) != strlen(s_sFormsCID))
+ sPath = sCID.copy(strlen(s_sFormsCID));
+ else if ( !m_bCreateForm && o3tl::make_unsigned(sCID.getLength()) != strlen(s_sReportsCID) )
+ sPath = sCID.copy(strlen(s_sReportsCID) - 2);
+
+ m_xFTCurrentPath->set_label(sPath);
+ Reference<XChild> xChild(m_xContent,UNO_QUERY);
+ bEnable = xChild.is() && Reference<XNameAccess>(xChild->getParent(),UNO_QUERY).is();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xUp->set_sensitive(bEnable);
+}
+
+OUString OCollectionView::getName() const
+{
+ return m_xName->get_text();
+}
+
+#define ROW_TITLE 1
+#define ROW_IS_FOLDER 2
+
+void OCollectionView::Initialize()
+{
+ weld::WaitObject aWaitCursor(m_xDialog.get());
+
+ m_xView->clear();
+
+ try
+ {
+ ::ucbhelper::Content aContent(m_xContent, m_xCmdEnv, comphelper::getProcessComponentContext());
+ Sequence<OUString> aProps { "Title", "IsFolder" };
+ auto xDynResultSet = aContent.createDynamicCursor(aProps, ucbhelper::INCLUDE_FOLDERS_ONLY);
+ if (!xDynResultSet.is())
+ return;
+
+ Reference<XResultSet> xResultSet = xDynResultSet->getStaticResultSet();
+ Reference<XRow> xRow(xResultSet, UNO_QUERY);
+ while (xResultSet->next())
+ {
+ if (!xRow->getBoolean(ROW_IS_FOLDER))
+ continue;
+ m_xView->append_text(xRow->getString(ROW_TITLE));
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/ConnectionHelper.cxx b/dbaccess/source/ui/dlg/ConnectionHelper.cxx
new file mode 100644
index 000000000..6642d2895
--- /dev/null
+++ b/dbaccess/source/ui/dlg/ConnectionHelper.cxx
@@ -0,0 +1,720 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include "dsnItem.hxx"
+#include "ConnectionHelper.hxx"
+#include <IItemSetHelper.hxx>
+#include <strings.hrc>
+#include <svl/itemset.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svl/stritem.hxx>
+#include <dsitems.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <vcl/stdtext.hxx>
+#include <sqlmessage.hxx>
+#include "dsselect.hxx"
+#include <svl/filenotation.hxx>
+#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp>
+#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/lang/SystemDependent.hpp>
+#include <com/sun/star/mozilla/MozillaBootstrap.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ucb/XProgressHandler.hpp>
+#include <ucbhelper/commandenvironment.hxx>
+#include <ucbhelper/content.hxx>
+#include "finteraction.hxx"
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+
+#if defined _WIN32
+#include <rtl/process.h>
+#include <vcl/sysdata.hxx>
+#include "adodatalinks.hxx"
+#endif
+
+#include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::ucb;
+ using namespace ::com::sun::star::ui::dialogs;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::mozilla;
+ using namespace ::dbtools;
+ using namespace ::svt;
+
+ OConnectionHelper::OConnectionHelper(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs)
+ : OGenericAdministrationPage(pPage, pController, _rUIXMLDescription, _rId, _rCoreAttrs)
+ , m_bUserGrabFocus(false)
+ , m_pCollection(nullptr)
+ , m_xFT_Connection(m_xBuilder->weld_label("browseurllabel"))
+ , m_xPB_Connection(m_xBuilder->weld_button("browse"))
+ , m_xPB_CreateDB(m_xBuilder->weld_button("create"))
+ , m_xConnectionURL(new OConnectionURLEdit(m_xBuilder->weld_entry("browseurl"), m_xBuilder->weld_label("browselabel")))
+ {
+ // extract the datasource type collection from the item set
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rCoreAttrs.GetItem(DSID_TYPECOLLECTION) );
+ if (pCollectionItem)
+ m_pCollection = pCollectionItem->getCollection();
+ m_xPB_Connection->connect_clicked(LINK(this, OConnectionHelper, OnBrowseConnections));
+ m_xPB_CreateDB->connect_clicked(LINK(this, OConnectionHelper, OnCreateDatabase));
+ OSL_ENSURE(m_pCollection, "OConnectionHelper::OConnectionHelper : really need a DSN type collection !");
+ m_xConnectionURL->SetTypeCollection(m_pCollection);
+
+ m_xConnectionURL->connect_focus_in(LINK(this, OConnectionHelper, GetFocusHdl));
+ m_xConnectionURL->connect_focus_out(LINK(this, OConnectionHelper, LoseFocusHdl));
+ }
+
+ OConnectionHelper::~OConnectionHelper()
+ {
+ m_xConnectionURL.reset();
+ }
+
+ void OConnectionHelper::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ m_xFT_Connection->show();
+ m_xConnectionURL->show();
+ m_xConnectionURL->ShowPrefix( ::dbaccess::DST_JDBC == m_pCollection->determineType(m_eType) );
+
+ bool bEnableBrowseButton = m_pCollection->supportsBrowsing( m_eType );
+ m_xPB_Connection->set_visible( bEnableBrowseButton );
+
+ bool bEnableCreateButton = m_pCollection->supportsDBCreation( m_eType );
+ m_xPB_CreateDB->set_visible( bEnableCreateButton );
+
+ const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL);
+
+ // forward the values to the controls
+ if ( bValid )
+ {
+ OUString sUrl = pUrlItem->GetValue();
+ setURL( sUrl );
+
+ checkTestConnection();
+ m_xConnectionURL->save_value();
+ }
+
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ void OConnectionHelper::implUpdateURLDependentStates() const
+ {
+ OSL_PRECOND( m_pAdminDialog && m_pCollection, "OConnectionHelper::implUpdateURLDependentStates: no admin dialog!" );
+ if ( !m_pAdminDialog || !m_pCollection )
+ return;
+
+ if ( m_pCollection->isFileSystemBased(m_eType) )
+ m_pAdminDialog->enableConfirmSettings( !getURLNoPrefix().isEmpty() );
+ }
+
+ IMPL_LINK_NOARG(OConnectionHelper, OnBrowseConnections, weld::Button&, void)
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ const ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType);
+ switch ( eType )
+ {
+ case ::dbaccess::DST_DBASE:
+ case ::dbaccess::DST_FLAT:
+ {
+ try
+ {
+ Reference< XFolderPicker2 > xFolderPicker = sfx2::createFolderPicker(m_xORB, GetFrameWeld());
+
+ bool bDoBrowse = false;
+ OUString sOldPath = getURLNoPrefix();
+ do
+ {
+ if (!sOldPath.isEmpty())
+ xFolderPicker->setDisplayDirectory(sOldPath);
+ if (0 == xFolderPicker->execute())
+ // cancelled by the user
+ return;
+
+ sOldPath = xFolderPicker->getDirectory();
+ switch (checkPathExistence(sOldPath))
+ {
+ case RET_RETRY:
+ bDoBrowse = true;
+ break;
+ case RET_CANCEL:
+ return;
+ default:
+ break;
+ }
+ }
+ while (bDoBrowse);
+
+ OUString sSelectedDirectory = xFolderPicker->getDirectory();
+ INetURLObject aSelectedDirectory( sSelectedDirectory, INetURLObject::EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8 );
+
+ // for UI purpose, we don't want to have the path encoded
+ sSelectedDirectory = aSelectedDirectory.GetMainURL( INetURLObject::DecodeMechanism::WithCharset );
+
+ setURLNoPrefix( sSelectedDirectory );
+ SetRoadmapStateValue(true);
+ callModifiedHdl();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ break;
+ case ::dbaccess::DST_CALC:
+ {
+ SvtModuleOptions aModule;
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::NONE,
+ aModule.GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::CALC)
+ ,SfxFilterFlags::IMPORT, SfxFilterFlags::NONE, GetFrameWeld());
+ askForFileName(aFileDlg);
+ }
+ break;
+ case ::dbaccess::DST_WRITER:
+ {
+ SvtModuleOptions aModule;
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::NONE,
+ aModule.GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::WRITER),
+ SfxFilterFlags::IMPORT, SfxFilterFlags::NONE, GetFrameWeld());
+ askForFileName(aFileDlg);
+ }
+ break;
+ case ::dbaccess::DST_MSACCESS:
+ {
+ OUString sFilterName(DBA_RES (STR_MSACCESS_FILTERNAME));
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::NONE, GetFrameWeld());
+ aFileDlg.AddFilter(sFilterName,"*.mdb;*.mde");
+ aFileDlg.SetCurrentFilter(sFilterName);
+ askForFileName(aFileDlg);
+ }
+ break;
+ case ::dbaccess::DST_MSACCESS_2007:
+ {
+ OUString sFilterName2(DBA_RES (STR_MSACCESS_2007_FILTERNAME));
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::NONE, GetFrameWeld());
+ aFileDlg.AddFilter(sFilterName2,"*.accdb;*.accde");
+ aFileDlg.SetCurrentFilter(sFilterName2);
+ askForFileName(aFileDlg);
+ }
+ break;
+ case ::dbaccess::DST_MYSQL_ODBC:
+ case ::dbaccess::DST_ODBC:
+ {
+ // collect all ODBC data source names
+ OUString sCurrDatasource = getURLNoPrefix();
+ OUString sDataSource;
+ if ( getSelectedDataSource(sDataSource,sCurrDatasource) && !sDataSource.isEmpty() )
+ {
+ setURLNoPrefix(sDataSource);
+ SetRoadmapStateValue(true);
+ callModifiedHdl();
+ }
+ else
+ return;
+ }
+ break;
+#if defined _WIN32
+ case ::dbaccess::DST_ADO:
+ {
+ OUString sOldDataSource=getURLNoPrefix();
+ OUString sNewDataSource;
+ HWND hWnd = nullptr;
+
+ weld::Window* pDialog = GetFrameWeld();
+ css::uno::Reference<css::awt::XSystemDependentWindowPeer> xSysDepWin(pDialog->GetXWindow(), css::uno::UNO_QUERY);
+ if (xSysDepWin.is())
+ {
+ css::uno::Sequence<sal_Int8> aProcessIdent(16);
+ rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8*>(aProcessIdent.getArray()));
+ css::uno::Any aAny = xSysDepWin->getWindowHandle(aProcessIdent, css::lang::SystemDependent::SYSTEM_WIN32);
+ sal_Int64 tmp(0);
+ aAny >>= tmp;
+ hWnd = reinterpret_cast<HWND>(tmp);
+ }
+
+ sNewDataSource = getAdoDatalink(reinterpret_cast<sal_IntPtr>(hWnd),sOldDataSource);
+ if ( !sNewDataSource.isEmpty() )
+ {
+ setURLNoPrefix(sNewDataSource);
+ SetRoadmapStateValue(true);
+ callModifiedHdl();
+ }
+ }
+ break;
+#endif
+ case ::dbaccess::DST_MOZILLA:
+ case ::dbaccess::DST_THUNDERBIRD:
+ {
+ MozillaProductType profileType = MozillaProductType_Mozilla;
+ if (eType == ::dbaccess::DST_THUNDERBIRD)
+ profileType = MozillaProductType_Thunderbird;
+
+ Reference<XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ Reference<XMozillaBootstrap> xMozillaBootstrap = MozillaBootstrap::create(xContext);
+
+ // collect all Mozilla Profiles
+ css::uno::Sequence< OUString > list;
+
+ xMozillaBootstrap->getProfileList( profileType, list );
+ const OUString * pArray = list.getConstArray();
+
+ sal_Int32 count = list.getLength();
+
+ std::set<OUString> aProfiles;
+ for (sal_Int32 index=0; index < count; index++)
+ aProfiles.insert(pArray[index]);
+
+ // execute the select dialog
+ ODatasourceSelectDialog aSelector(GetFrameWeld(), aProfiles);
+ OUString sOldProfile=getURLNoPrefix();
+
+ if (!sOldProfile.isEmpty())
+ aSelector.Select(sOldProfile);
+ else
+ aSelector.Select(xMozillaBootstrap->getDefaultProfile(profileType));
+
+ if (RET_OK == aSelector.run())
+ setURLNoPrefix(aSelector.GetSelected());
+ break;
+ }
+ case ::dbaccess::DST_FIREBIRD:
+ {
+ OUString sFilterName(DBA_RES (STR_FIREBIRD_FILTERNAME));
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, GetFrameWeld());
+ aFileDlg.AddFilter(sFilterName,"*.fdb");
+ aFileDlg.SetCurrentFilter(sFilterName);
+ askForFileName(aFileDlg);
+ break;
+ }
+ default:
+ break;
+ }
+
+ checkTestConnection();
+ }
+
+ IMPL_LINK_NOARG(OConnectionHelper, OnCreateDatabase, weld::Button&, void)
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ const ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType);
+ switch ( eType )
+ {
+ case ::dbaccess::DST_FIREBIRD:
+ {
+ OUString sFilterName(DBA_RES (STR_FIREBIRD_FILTERNAME));
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE, GetFrameWeld());
+ aFileDlg.AddFilter(sFilterName,"*.fdb");
+ aFileDlg.SetCurrentFilter(sFilterName);
+ askForFileName(aFileDlg);
+ break;
+ }
+ default:
+ break;
+ }
+
+ checkTestConnection();
+ }
+
+ bool OConnectionHelper::checkTestConnection()
+ {
+ return true;
+ }
+
+ void OConnectionHelper::impl_setURL( std::u16string_view _rURL, bool _bPrefix )
+ {
+ OUString sURL( comphelper::string::stripEnd(_rURL, '*') );
+ OSL_ENSURE( m_pCollection, "OConnectionHelper::impl_setURL: have no interpreter for the URLs!" );
+
+ if ( m_pCollection && !sURL.isEmpty() )
+ {
+ if ( m_pCollection->isFileSystemBased( m_eType ) )
+ {
+ // get the two parts: prefix and file URL
+ OUString sTypePrefix, sFileURLEncoded;
+ if ( _bPrefix )
+ {
+ sTypePrefix = m_pCollection->getPrefix( m_eType );
+ sFileURLEncoded = m_pCollection->cutPrefix( sURL );
+ }
+ else
+ {
+ sFileURLEncoded = sURL;
+ }
+
+ // substitute any variables
+ sFileURLEncoded = SvtPathOptions().SubstituteVariable( sFileURLEncoded );
+
+ // decode the URL
+ sURL = sTypePrefix;
+ if ( !sFileURLEncoded.isEmpty() )
+ {
+ OFileNotation aFileNotation(sFileURLEncoded);
+ // set this decoded URL as text
+ sURL += aFileNotation.get(OFileNotation::N_SYSTEM);
+ }
+ }
+ }
+
+ if ( _bPrefix )
+ m_xConnectionURL->SetText( sURL );
+ else
+ m_xConnectionURL->SetTextNoPrefix( sURL );
+
+ implUpdateURLDependentStates();
+ }
+
+ OUString OConnectionHelper::impl_getURL() const
+ {
+ // get the pure text
+ OUString sURL = m_xConnectionURL->GetTextNoPrefix();
+
+ OSL_ENSURE( m_pCollection, "OConnectionHelper::impl_getURL: have no interpreter for the URLs!" );
+
+ if ( m_pCollection && !sURL.isEmpty() )
+ {
+ if ( m_pCollection->isFileSystemBased( m_eType ) )
+ {
+ // get the two parts: prefix and file URL
+ OUString sFileURLDecoded = sURL;
+
+ sURL = OUString();
+ if ( !sFileURLDecoded.isEmpty() )
+ {
+ OFileNotation aFileNotation( sFileURLDecoded, OFileNotation::N_SYSTEM );
+ sURL += aFileNotation.get( OFileNotation::N_URL );
+ }
+
+ // encode the URL
+ INetURLObject aFileURL( sFileURLDecoded, INetURLObject::EncodeMechanism::All, RTL_TEXTENCODING_UTF8 );
+ sFileURLDecoded = aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ }
+ return sURL;
+ }
+
+ void OConnectionHelper::setURL( std::u16string_view _rURL )
+ {
+ impl_setURL( _rURL, true );
+ }
+
+ OUString OConnectionHelper::getURLNoPrefix( ) const
+ {
+ return impl_getURL();
+ }
+
+ void OConnectionHelper::setURLNoPrefix( std::u16string_view _rURL )
+ {
+ impl_setURL( _rURL, false );
+ }
+
+ sal_Int32 OConnectionHelper::checkPathExistence(const OUString& _rURL)
+ {
+ IS_PATH_EXIST e_exists = pathExists(_rURL, false);
+ if (!m_pCollection->supportsDBCreation(m_eType) &&
+ (( e_exists == PATH_NOT_EXIST) || ( e_exists == PATH_NOT_KNOWN)))
+ {
+ OUString sQuery(DBA_RES(STR_ASK_FOR_DIRECTORY_CREATION));
+ OFileNotation aTransformer(_rURL);
+ sQuery = sQuery.replaceFirst("$path$", aTransformer.get(OFileNotation::N_SYSTEM));
+
+ m_bUserGrabFocus = false;
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ sQuery));
+ xQueryBox->set_default_response(RET_YES);
+ sal_Int32 nQueryResult = xQueryBox->run();
+ m_bUserGrabFocus = true;
+
+ switch (nQueryResult)
+ {
+ case RET_YES:
+ {
+ bool bTryCreate = false;
+ do
+ {
+ if ( !createDirectoryDeep(_rURL) )
+ { // could not create the directory
+ sQuery = DBA_RES(STR_COULD_NOT_CREATE_DIRECTORY);
+ sQuery = sQuery.replaceFirst("$name$", aTransformer.get(OFileNotation::N_SYSTEM));
+
+ m_bUserGrabFocus = false;
+
+ std::unique_ptr<weld::MessageDialog> xWhatToDo(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::NONE,
+ sQuery));
+ xWhatToDo->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
+ xWhatToDo->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ xWhatToDo->set_default_response(RET_RETRY);
+ nQueryResult = xWhatToDo->run();
+ m_bUserGrabFocus = true;
+
+ if (RET_RETRY == nQueryResult)
+ bTryCreate = true;
+ else
+ {
+ SetRoadmapStateValue(false);
+ callModifiedHdl();
+ return RET_RETRY;
+ }
+ }
+ }
+ while (bTryCreate);
+ }
+ break;
+
+ case RET_NO:
+ callModifiedHdl();
+ return RET_OK;
+
+ default:
+ // cancelled
+ SetRoadmapStateValue(false);
+ callModifiedHdl();
+ return RET_CANCEL;
+ }
+ }
+/* else
+ {
+ // TODO: error msg
+ return RET_CANCEL;
+ } */
+ SetRoadmapStateValue(true);
+ callModifiedHdl();
+ return RET_OK;
+ }
+
+ IS_PATH_EXIST OConnectionHelper::pathExists(const OUString& _rURL, bool bIsFile) const
+ {
+ ::ucbhelper::Content aCheckExistence;
+ IS_PATH_EXIST eExists = PATH_NOT_EXIST;
+ Reference< css::task::XInteractionHandler > xInteractionHandler =
+ task::InteractionHandler::createWithParent(m_xORB, nullptr);
+ rtl::Reference<OFilePickerInteractionHandler> pHandler = new OFilePickerInteractionHandler(xInteractionHandler);
+ xInteractionHandler = pHandler;
+
+ Reference< XCommandEnvironment > xCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() );
+ try
+ {
+ aCheckExistence = ::ucbhelper::Content(_rURL, xCmdEnv, comphelper::getProcessComponentContext());
+ const bool bExists = bIsFile? aCheckExistence.isDocument(): aCheckExistence.isFolder();
+ eExists = bExists? PATH_EXIST: PATH_NOT_EXIST;
+ }
+ catch (const Exception&)
+ {
+ eExists = pHandler->isDoesNotExist() ? PATH_NOT_EXIST : (bIsFile ? PATH_NOT_EXIST : PATH_NOT_KNOWN);
+ }
+ return eExists;
+ }
+
+ IMPL_LINK_NOARG(OConnectionHelper, GetFocusHdl, weld::Widget&, void)
+ {
+ if (!m_pCollection->isFileSystemBased(m_eType))
+ return;
+ if (!m_bUserGrabFocus)
+ return;
+ // URL edit field got the focus
+ m_xConnectionURL->SaveValueNoPrefix();
+ }
+
+ IMPL_LINK_NOARG(OConnectionHelper, LoseFocusHdl, weld::Widget&, void)
+ {
+ if (!m_pCollection->isFileSystemBased(m_eType))
+ return;
+ if (!m_bUserGrabFocus)
+ return;
+ // URL edit field lost the focus
+ commitURL();
+ }
+
+ bool OConnectionHelper::createDirectoryDeep(std::u16string_view _rPathURL)
+ {
+ // get a URL object analyzing the URL for us ...
+ INetURLObject aParser;
+ aParser.SetURL(_rPathURL);
+
+ INetProtocol eProtocol = aParser.GetProtocol();
+
+ std::vector< OUString > aToBeCreated; // the to-be-created levels
+
+ // search a level which exists
+ IS_PATH_EXIST eParentExists = PATH_NOT_EXIST;
+ while ( eParentExists == PATH_NOT_EXIST && aParser.getSegmentCount())
+ {
+ aToBeCreated.push_back(aParser.getName()); // remember the local name for creation
+ aParser.removeSegment(); // cut the local name
+ eParentExists = pathExists(aParser.GetMainURL(INetURLObject::DecodeMechanism::NONE), false);
+ }
+
+ if (!aParser.getSegmentCount())
+ return false;
+
+ // create all the missing levels
+ try
+ {
+ // the parent content
+ Reference< XCommandEnvironment > xEmptyEnv;
+ ::ucbhelper::Content aParent(aParser.GetMainURL(INetURLObject::DecodeMechanism::NONE), xEmptyEnv, comphelper::getProcessComponentContext());
+
+ OUString sContentType;
+ if ( INetProtocol::File == eProtocol )
+ {
+ sContentType = "application/vnd.sun.staroffice.fsys-folder";
+ // the file UCP currently does not support the ContentType property
+ }
+ else
+ {
+ Any aContentType = aParent.getPropertyValue("ContentType");
+ aContentType >>= sContentType;
+ }
+
+ // the properties which need to be set on the new content
+ Sequence< OUString > aNewDirectoryProperties { "Title" };
+
+ // loop
+ for ( std::vector< OUString >::const_reverse_iterator aLocalName = aToBeCreated.rbegin();
+ aLocalName != aToBeCreated.rend();
+ ++aLocalName
+ )
+ {
+ // the values to be set
+ Sequence< Any > aNewDirectoryAttributes{ Any(* aLocalName) };
+ if (!aParent.insertNewContent(sContentType, aNewDirectoryProperties, aNewDirectoryAttributes, aParent))
+ return false;
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ return false;
+ }
+
+ return true;
+ }
+
+ void OConnectionHelper::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFT_Connection.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Button>(m_xPB_Connection.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Button>(m_xPB_CreateDB.get()));
+ }
+
+ void OConnectionHelper::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back( new OSaveValueWidgetWrapper<OConnectionURLEdit>( m_xConnectionURL.get() ) );
+ }
+
+ bool OConnectionHelper::commitURL()
+ {
+ OUString sOldPath = m_xConnectionURL->GetSavedValueNoPrefix();
+ OUString sURL = m_xConnectionURL->GetTextNoPrefix();
+
+ if ( m_pCollection->isFileSystemBased(m_eType) )
+ {
+ if ( ( sURL != sOldPath ) && !sURL.isEmpty() )
+ { // the text changed since entering the control
+
+ // the path may be in system notation...
+ OFileNotation aTransformer(sURL);
+ sURL = aTransformer.get(OFileNotation::N_URL);
+
+ const ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType);
+
+ if ( ( ::dbaccess::DST_CALC == eType) || ( ::dbaccess::DST_WRITER == eType) || ( ::dbaccess::DST_MSACCESS == eType) || ( ::dbaccess::DST_MSACCESS_2007 == eType) )
+ {
+ if( pathExists(sURL, true) == PATH_NOT_EXIST )
+ {
+ OUString sFile = DBA_RES( STR_FILE_DOES_NOT_EXIST );
+ sFile = sFile.replaceFirst("$file$", aTransformer.get(OFileNotation::N_SYSTEM));
+ OSQLWarningBox aWarning(GetFrameWeld(), sFile);
+ aWarning.run();
+ setURLNoPrefix(sOldPath);
+ SetRoadmapStateValue(false);
+ callModifiedHdl();
+ return false;
+ }
+ }
+ else
+ {
+ switch (checkPathExistence(sURL))
+ {
+ case RET_RETRY:
+ m_bUserGrabFocus = false;
+ m_xConnectionURL->grab_focus();
+ m_bUserGrabFocus = true;
+ return false;
+
+ case RET_CANCEL:
+ setURLNoPrefix(sOldPath);
+ return false;
+ }
+ }
+ }
+ }
+
+ setURLNoPrefix(sURL);
+ m_xConnectionURL->SaveValueNoPrefix();
+ return true;
+ }
+
+ void OConnectionHelper::askForFileName(::sfx2::FileDialogHelper& _aFileOpen)
+ {
+ OUString sOldPath = getURLNoPrefix();
+ if ( !sOldPath.isEmpty() )
+ _aFileOpen.SetDisplayDirectory(sOldPath);
+ else
+ _aFileOpen.SetDisplayDirectory( SvtPathOptions().GetWorkPath() );
+ if (ERRCODE_NONE == _aFileOpen.Execute())
+ {
+ setURLNoPrefix(_aFileOpen.GetPath());
+ SetRoadmapStateValue(checkTestConnection());
+ callModifiedHdl();
+ }
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/ConnectionHelper.hxx b/dbaccess/source/ui/dlg/ConnectionHelper.hxx
new file mode 100644
index 000000000..b4c00548f
--- /dev/null
+++ b/dbaccess/source/ui/dlg/ConnectionHelper.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "adminpages.hxx"
+#include <curledit.hxx>
+#include <sfx2/filedlghelper.hxx>
+
+namespace dbaui
+{
+
+ enum IS_PATH_EXIST
+ {
+ PATH_NOT_EXIST = 0,
+ PATH_EXIST,
+ PATH_NOT_KNOWN
+ };
+
+ class OConnectionHelper : public OGenericAdministrationPage
+ {
+ bool m_bUserGrabFocus;
+
+ public:
+ OConnectionHelper(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs);
+ virtual ~OConnectionHelper() override;
+
+ OUString m_eType; // the type can't be changed in this class, so we hold it as member.
+ // setting/retrieving the current connection URL
+ // necessary because for some types, the URL must be decoded for display purposes
+ ::dbaccess::ODsnTypeCollection* m_pCollection; /// the DSN type collection instance
+
+ std::unique_ptr<weld::Label> m_xFT_Connection;
+ std::unique_ptr<weld::Button> m_xPB_Connection;
+ std::unique_ptr<weld::Button> m_xPB_CreateDB;
+ std::unique_ptr<OConnectionURLEdit> m_xConnectionURL;
+
+ public:
+
+ // <method>OGenericAdministrationPage::fillControls</method>
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ // <method>OGenericAdministrationPage::fillWindows</method>
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ // setting/retrieving the current connection URL
+ // necessary because for some types, the URL must be decoded for display purposes
+ //String getURL( OConnectionURLEdit* _m_pConnection ) const;
+ //void setURL( const OUString& _rURL, OConnectionURLEdit* _m_pConnection );
+
+ OUString getURLNoPrefix( ) const;
+ void setURLNoPrefix( std::u16string_view _rURL );
+
+ /** checks if the path is existence
+ @param _rURL
+ The URL to check.
+ */
+ sal_Int32 checkPathExistence(const OUString& _rURL);
+
+ IS_PATH_EXIST pathExists(const OUString& _rURL, bool bIsFile) const;
+ bool createDirectoryDeep(std::u16string_view _rPathNormalized);
+ bool commitURL();
+
+ /** opens the FileOpen dialog and asks for a FileName
+ @param _aFileOpen
+ Executes the file open dialog, which must be filled from caller.
+ */
+ void askForFileName(::sfx2::FileDialogHelper& _aFileOpen);
+
+ protected:
+ void setURL( std::u16string_view _rURL );
+ virtual bool checkTestConnection();
+
+ private:
+ DECL_LINK(OnBrowseConnections, weld::Button&, void);
+ DECL_LINK(OnCreateDatabase, weld::Button&, void);
+ DECL_LINK(GetFocusHdl, weld::Widget&, void);
+ DECL_LINK(LoseFocusHdl, weld::Widget&, void);
+ OUString impl_getURL() const;
+ void impl_setURL( std::u16string_view _rURL, bool _bPrefix );
+ void implUpdateURLDependentStates() const;
+ };
+
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/ConnectionPage.cxx b/dbaccess/source/ui/dlg/ConnectionPage.cxx
new file mode 100644
index 000000000..7ff32140e
--- /dev/null
+++ b/dbaccess/source/ui/dlg/ConnectionPage.cxx
@@ -0,0 +1,284 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_java.h>
+#include "ConnectionPage.hxx"
+#include <core_resource.hxx>
+#include <IItemSetHelper.hxx>
+#include <strings.hrc>
+#include <dsmeta.hxx>
+#if HAVE_FEATURE_JAVA
+#include <jvmaccess/virtualmachine.hxx>
+#endif
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <dsitems.hxx>
+#include <helpids.h>
+#include <sqlmessage.hxx>
+#include <svl/filenotation.hxx>
+#include <com/sun/star/ucb/XProgressHandler.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::ucb;
+ using namespace ::com::sun::star::ui::dialogs;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::dbtools;
+ using namespace ::svt;
+
+ std::unique_ptr<SfxTabPage> OConnectionTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet)
+ {
+ return std::make_unique<OConnectionTabPage>(pPage, pController, *_rAttrSet);
+ }
+
+ // OConnectionTabPage
+ OConnectionTabPage::OConnectionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs)
+ : OConnectionHelper(pPage, pController, "dbaccess/ui/connectionpage.ui", "ConnectionPage", _rCoreAttrs)
+ , m_xFL2(m_xBuilder->weld_label("userlabel"))
+ , m_xUserNameLabel(m_xBuilder->weld_label("userNameLabel"))
+ , m_xUserName(m_xBuilder->weld_entry("userNameEntry"))
+ , m_xPasswordRequired(m_xBuilder->weld_check_button("passCheckbutton"))
+ , m_xFL3(m_xBuilder->weld_label("JDBCLabel"))
+ , m_xJavaDriverLabel(m_xBuilder->weld_label("javaDriverLabel"))
+ , m_xJavaDriver(m_xBuilder->weld_entry("driverEntry"))
+ , m_xTestJavaDriver(m_xBuilder->weld_button("driverButton"))
+ , m_xTestConnection(m_xBuilder->weld_button("connectionButton"))
+ {
+ m_xConnectionURL->connect_changed(LINK(this, OConnectionTabPage, OnEditModified));
+ m_xJavaDriver->connect_changed(LINK(this, OConnectionTabPage, OnEditModified));
+ m_xUserName->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ m_xPasswordRequired->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick));
+
+ m_xTestConnection->connect_clicked(LINK(this,OGenericAdministrationPage,OnTestConnectionButtonClickHdl));
+ m_xTestJavaDriver->connect_clicked(LINK(this,OConnectionTabPage,OnTestJavaClickHdl));
+ }
+
+ OConnectionTabPage::~OConnectionTabPage()
+ {
+ }
+
+ void OConnectionTabPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ m_eType = m_pAdminDialog->getDatasourceType(_rSet);
+ OConnectionHelper::implInitControls( _rSet, _bSaveValue);
+
+ ::dbaccess::DATASOURCE_TYPE eType = m_pCollection->determineType(m_eType);
+ switch( eType )
+ {
+ case ::dbaccess::DST_DBASE:
+ m_xFT_Connection->set_label(DBA_RES(STR_DBASE_PATH_OR_FILE));
+ m_xConnectionURL->set_help_id(HID_DSADMIN_DBASE_PATH);
+ break;
+ case ::dbaccess::DST_FLAT:
+ m_xFT_Connection->set_label(DBA_RES(STR_FLAT_PATH_OR_FILE));
+ m_xConnectionURL->set_help_id(HID_DSADMIN_FLAT_PATH);
+ break;
+ case ::dbaccess::DST_CALC:
+ m_xFT_Connection->set_label(DBA_RES(STR_CALC_PATH_OR_FILE));
+ m_xConnectionURL->set_help_id(HID_DSADMIN_CALC_PATH);
+ break;
+ case ::dbaccess::DST_WRITER:
+ m_xFT_Connection->set_label(DBA_RES(STR_WRITER_PATH_OR_FILE));
+ m_xConnectionURL->set_help_id(HID_DSADMIN_WRITER_PATH);
+ break;
+ case ::dbaccess::DST_ADO:
+ m_xFT_Connection->set_label(DBA_RES(STR_COMMONURL));
+ break;
+ case ::dbaccess::DST_MSACCESS:
+ case ::dbaccess::DST_MSACCESS_2007:
+ m_xFT_Connection->set_label(DBA_RES(STR_MSACCESS_MDB_FILE));
+ m_xConnectionURL->set_help_id(HID_DSADMIN_MSACCESS_MDB_FILE);
+ break;
+ case ::dbaccess::DST_MYSQL_NATIVE:
+ case ::dbaccess::DST_MYSQL_JDBC:
+ m_xFT_Connection->set_label(DBA_RES(STR_MYSQL_DATABASE_NAME));
+ m_xConnectionURL->set_help_id( HID_DSADMIN_MYSQL_DATABASE );
+ break;
+ case ::dbaccess::DST_ORACLE_JDBC:
+ m_xFT_Connection->set_label(DBA_RES(STR_ORACLE_DATABASE_NAME));
+ m_xConnectionURL->set_help_id(HID_DSADMIN_ORACLE_DATABASE);
+ break;
+ case ::dbaccess::DST_MYSQL_ODBC:
+ case ::dbaccess::DST_ODBC:
+ m_xFT_Connection->set_label(DBA_RES(STR_NAME_OF_ODBC_DATASOURCE));
+ m_xConnectionURL->set_help_id( eType == ::dbaccess::DST_MYSQL_ODBC ? OString(HID_DSADMIN_MYSQL_ODBC_DATASOURCE) : OString(HID_DSADMIN_ODBC_DATASOURCE));
+ break;
+ case ::dbaccess::DST_LDAP:
+ m_xFT_Connection->set_label(DBA_RES(STR_HOSTNAME));
+ m_xConnectionURL->set_help_id( HID_DSADMIN_LDAP_HOSTNAME );
+ break;
+ case ::dbaccess::DST_MOZILLA:
+ m_xFT_Connection->set_label(DBA_RES(STR_MOZILLA_PROFILE_NAME));
+ m_xConnectionURL->set_help_id( HID_DSADMIN_MOZILLA_PROFILE_NAME );
+ break;
+ case ::dbaccess::DST_THUNDERBIRD:
+ m_xFT_Connection->set_label(DBA_RES(STR_THUNDERBIRD_PROFILE_NAME));
+ m_xConnectionURL->set_help_id( HID_DSADMIN_THUNDERBIRD_PROFILE_NAME );
+ break;
+ case ::dbaccess::DST_OUTLOOK:
+ case ::dbaccess::DST_OUTLOOKEXP:
+ case ::dbaccess::DST_EVOLUTION:
+ case ::dbaccess::DST_EVOLUTION_GROUPWISE:
+ case ::dbaccess::DST_EVOLUTION_LDAP:
+ case ::dbaccess::DST_KAB:
+ case ::dbaccess::DST_MACAB:
+ m_xFT_Connection->set_label(DBA_RES(STR_NO_ADDITIONAL_SETTINGS));
+ {
+ OUString sText = m_xFT_Connection->get_label();
+ sText = sText.replaceAll("%test",m_xTestConnection->get_label());
+ sText = sText.replaceAll("~","");
+ m_xFT_Connection->set_label(sText);
+ }
+ m_xConnectionURL->hide();
+ break;
+ case ::dbaccess::DST_JDBC:
+ default:
+ m_xFT_Connection->set_label(DBA_RES(STR_COMMONURL));
+ break;
+ }
+
+ AuthenticationMode eAuthMode( DataSourceMetaData::getAuthentication( m_eType ) );
+ bool bShowUserAuthenfication = ( eAuthMode != AuthNone );
+ bool bShowUser = ( eAuthMode == AuthUserPwd );
+
+ m_xPB_Connection->set_help_id(HID_DSADMIN_BROWSECONN);
+ m_xFL2->set_visible( bShowUserAuthenfication );
+ m_xUserNameLabel->set_visible( bShowUser && bShowUserAuthenfication );
+ m_xUserName->set_visible( bShowUser && bShowUserAuthenfication );
+ m_xPasswordRequired->set_visible( bShowUserAuthenfication );
+
+ // collect the items
+ const SfxStringItem* pUidItem = _rSet.GetItem<SfxStringItem>(DSID_USER);
+
+ const SfxStringItem* pJdbcDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS);
+ const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL);
+ const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED);
+
+ // forward the values to the controls
+ if ( !bValid )
+ return;
+
+ m_xUserName->set_text(pUidItem->GetValue());
+ m_xPasswordRequired->set_active(pAllowEmptyPwd->GetValue());
+
+ const OUString& sUrl = pUrlItem->GetValue();
+ setURL( sUrl );
+
+ const bool bEnableJDBC = m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC;
+ if ( !pJdbcDrvItem->GetValue().getLength() )
+ {
+ OUString sDefaultJdbcDriverName = m_pCollection->getJavaDriverClass(m_eType);
+ if ( !sDefaultJdbcDriverName.isEmpty() )
+ m_xJavaDriver->set_text(sDefaultJdbcDriverName);
+ }
+ else
+ m_xJavaDriver->set_text(pJdbcDrvItem->GetValue());
+
+ m_xJavaDriverLabel->set_visible(bEnableJDBC);
+ m_xJavaDriver->set_visible(bEnableJDBC);
+ m_xTestJavaDriver->set_visible(bEnableJDBC);
+ m_xTestJavaDriver->set_sensitive( !m_xJavaDriver->get_text().trim().isEmpty() );
+ m_xFL3->set_visible(bEnableJDBC);
+
+ checkTestConnection();
+
+ m_xUserName->save_value();
+ m_xConnectionURL->save_value();
+ m_xJavaDriver->save_value();
+ m_xPasswordRequired->save_state();
+ }
+
+ bool OConnectionTabPage::FillItemSet(SfxItemSet* _rSet)
+ {
+ bool bChangedSomething = false;
+
+ if (m_xUserName->get_value_changed_from_saved())
+ {
+ _rSet->Put(SfxStringItem(DSID_USER, m_xUserName->get_text()));
+ _rSet->Put(SfxStringItem(DSID_PASSWORD, OUString()));
+ bChangedSomething = true;
+ }
+
+ fillBool(*_rSet,m_xPasswordRequired.get(),DSID_PASSWORDREQUIRED,false, bChangedSomething);
+
+ if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC )
+ {
+ fillString(*_rSet,m_xJavaDriver.get(), DSID_JDBCDRIVERCLASS, bChangedSomething);
+ }
+
+ fillString(*_rSet,m_xConnectionURL.get(), DSID_CONNECTURL, bChangedSomething);
+
+ return bChangedSomething;
+ }
+ IMPL_LINK_NOARG(OConnectionTabPage, OnTestJavaClickHdl, weld::Button&, void)
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ bool bSuccess = false;
+#if HAVE_FEATURE_JAVA
+ try
+ {
+ if ( !m_xJavaDriver->get_text().trim().isEmpty() )
+ {
+ ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() );
+ m_xJavaDriver->set_text(m_xJavaDriver->get_text().trim()); // fdo#68341
+ bSuccess = ::connectivity::existsJavaClassByName(xJVM, o3tl::trim(m_xJavaDriver->get_text()));
+ }
+ }
+ catch(Exception&)
+ {
+ }
+#endif
+
+ TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS;
+ const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error;
+ OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt);
+ aMsg.run();
+ }
+ bool OConnectionTabPage::checkTestConnection()
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ bool bEnableTestConnection = !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty();
+ if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC )
+ bEnableTestConnection = bEnableTestConnection && (!m_xJavaDriver->get_text().trim().isEmpty());
+ m_xTestConnection->set_sensitive(bEnableTestConnection);
+ return true;
+ }
+ IMPL_LINK(OConnectionTabPage, OnEditModified, weld::Entry&, rEdit, void)
+ {
+ if (&rEdit == m_xJavaDriver.get())
+ m_xTestJavaDriver->set_sensitive( !m_xJavaDriver->get_text().trim().isEmpty() );
+
+ checkTestConnection();
+ // tell the listener we were modified
+ callModifiedHdl();
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/ConnectionPage.hxx b/dbaccess/source/ui/dlg/ConnectionPage.hxx
new file mode 100644
index 000000000..19e769462
--- /dev/null
+++ b/dbaccess/source/ui/dlg/ConnectionPage.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ConnectionHelper.hxx"
+
+namespace dbaui
+{
+
+ // OConnectionTabPage
+
+ /** implements the connection page of the data source properties dialog.
+ */
+ class OConnectionTabPage final : public OConnectionHelper
+ {
+ private:
+ // user authentication
+ std::unique_ptr<weld::Label> m_xFL2;
+ std::unique_ptr<weld::Label> m_xUserNameLabel;
+ std::unique_ptr<weld::Entry> m_xUserName;
+ std::unique_ptr<weld::CheckButton> m_xPasswordRequired;
+
+ // jdbc driver
+ std::unique_ptr<weld::Label> m_xFL3;
+ std::unique_ptr<weld::Label> m_xJavaDriverLabel;
+ std::unique_ptr<weld::Entry> m_xJavaDriver;
+ std::unique_ptr<weld::Button> m_xTestJavaDriver;
+
+ // connection test
+ std::unique_ptr<weld::Button> m_xTestConnection;
+
+ // called when the test connection button was clicked
+ DECL_LINK(OnTestJavaClickHdl, weld::Button&, void);
+ DECL_LINK(OnEditModified, weld::Entry&, void);
+
+ public:
+ OConnectionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet);
+ virtual ~OConnectionTabPage() override;
+ virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override;
+
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ /** changes the connection URL.
+ <p>The new URL must be of the type which is currently selected, only the parts which do not
+ affect the type may be changed (compared to the previous URL).</p>
+ */
+ private:
+ /** enables the test connection button, if allowed
+ */
+ virtual bool checkTestConnection() override;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx b/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx
new file mode 100644
index 000000000..8f57c24f9
--- /dev/null
+++ b/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ConnectionPageSetup.hxx"
+#include <strings.hrc>
+#include <core_resource.hxx>
+#include <IItemSetHelper.hxx>
+#include <svl/itemset.hxx>
+#include <dsitems.hxx>
+#include <svl/filenotation.hxx>
+#include <com/sun/star/ucb/XProgressHandler.hpp>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::ucb;
+ using namespace ::com::sun::star::ui::dialogs;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::svt;
+
+ std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateDbaseTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_DBASE_HELPTEXT, STR_DBASE_HEADERTEXT, STR_DBASE_PATH_OR_FILE );
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateMSAccessTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_MSACCESS_HELPTEXT, STR_MSACCESS_HEADERTEXT, STR_MSACCESS_MDB_FILE );
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateADOTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_ADO_HELPTEXT, STR_ADO_HEADERTEXT, STR_COMMONURL );
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateODBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OConnectionTabPageSetup>( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_ODBC_HELPTEXT, STR_ODBC_HEADERTEXT, STR_NAME_OF_ODBC_DATASOURCE );
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OConnectionTabPageSetup::CreateUserDefinedTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OConnectionTabPageSetup>(pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, TranslateId(), TranslateId(), STR_COMMONURL);
+ }
+
+ OConnectionTabPageSetup::OConnectionTabPageSetup(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs, TranslateId pHelpTextResId, TranslateId pHeaderResId, TranslateId pUrlResId)
+ : OConnectionHelper(pPage, pController, _rUIXMLDescription, _rId, _rCoreAttrs)
+ , m_xHelpText(m_xBuilder->weld_label("helptext"))
+ , m_xHeaderText(m_xBuilder->weld_label("header"))
+ {
+
+ if (pHelpTextResId)
+ {
+ OUString sHelpText = DBA_RES(pHelpTextResId);
+ m_xHelpText->set_label(sHelpText);
+ }
+ else
+ m_xHelpText->hide();
+
+ if (pHeaderResId)
+ m_xHeaderText->set_label(DBA_RES(pHeaderResId));
+
+ if (pUrlResId)
+ {
+ OUString sLabelText = DBA_RES(pUrlResId);
+ m_xFT_Connection->set_label(sLabelText);
+ }
+ else
+ m_xFT_Connection->hide();
+
+ m_xConnectionURL->connect_changed(LINK(this, OConnectionTabPageSetup, OnEditModified));
+
+ SetRoadmapStateValue(false);
+ }
+
+ OConnectionTabPageSetup::~OConnectionTabPageSetup()
+ {
+ }
+
+ void OConnectionTabPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ m_eType = m_pAdminDialog->getDatasourceType(_rSet);
+ // special handling for oracle, this can only happen
+ // if the user enters the same url as used for Oracle and we are on the JDBC path
+ //! TODO
+ //if ( ::dbaccess::DST_ORACLE_JDBC == m_eType )
+ // m_eType = ::dbaccess::DST_JDBC;
+ if(m_pCollection->determineType(m_eType) == ::dbaccess::DST_POSTGRES){
+ SetRoadmapStateValue(true);
+ }
+
+ OConnectionHelper::implInitControls(_rSet, _bSaveValue);
+
+ //! TODO
+ //if ( m_eType >= ::dbaccess::DST_USERDEFINE1 )
+ //{
+ // OUString sDisplayName = m_pCollection->getTypeDisplayName(m_eType);
+ // FixedText* ppTextControls[] ={&m_aFT_Connection};
+ // for (size_t i = 0; i < sizeof(ppTextControls)/sizeof(ppTextControls[0]); ++i)
+ // {
+ // ppTextControls[i]->SetText(sDisplayName);
+ // }
+ //}
+
+ callModifiedHdl();
+ }
+
+ bool OConnectionTabPageSetup::commitPage( ::vcl::WizardTypes::CommitPageReason /*_eReason*/ )
+ {
+ return commitURL();
+ }
+
+ bool OConnectionTabPageSetup::FillItemSet(SfxItemSet* _rSet)
+ {
+ bool bChangedSomething = false;
+ fillString(*_rSet,m_xConnectionURL.get(), DSID_CONNECTURL, bChangedSomething);
+ return bChangedSomething;
+ }
+
+ bool OConnectionTabPageSetup::checkTestConnection()
+ {
+ if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_POSTGRES )
+ return true;
+ return !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty();
+ }
+
+ IMPL_LINK_NOARG(OConnectionTabPageSetup, OnEditModified, weld::Entry&, void)
+ {
+ SetRoadmapStateValue(checkTestConnection());
+ callModifiedHdl();
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx b/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx
new file mode 100644
index 000000000..0039a7160
--- /dev/null
+++ b/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ConnectionHelper.hxx"
+#include "adminpages.hxx"
+#include <unotools/resmgr.hxx>
+
+namespace dbaui
+{
+
+ // OConnectionTabPageSetup
+
+ /** implements the connection page of the data source properties dialog.
+ */
+ class OConnectionTabPageSetup : public OConnectionHelper
+ {
+ std::unique_ptr<weld::Label> m_xHelpText;
+ std::unique_ptr<weld::Label> m_xHeaderText;
+
+ // called when the test connection button was clicked
+ DECL_LINK(OnEditModified, weld::Entry&, void);
+
+ public:
+ OConnectionTabPageSetup(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs, TranslateId pHelpTextResId, TranslateId pHeaderResId, TranslateId pUrlResId);
+ virtual ~OConnectionTabPageSetup() override;
+
+ static std::unique_ptr<OGenericAdministrationPage> CreateDbaseTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet);
+ static std::unique_ptr<OGenericAdministrationPage> CreateMSAccessTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet);
+ static std::unique_ptr<OGenericAdministrationPage> CreateADOTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet);
+ static std::unique_ptr<OGenericAdministrationPage> CreateODBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet);
+ static std::unique_ptr<OGenericAdministrationPage> CreateUserDefinedTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet);
+
+ virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override;
+
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override;
+
+ protected:
+ virtual bool checkTestConnection() override;
+ };
+
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx b/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx
new file mode 100644
index 000000000..ffbde972f
--- /dev/null
+++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx
@@ -0,0 +1,786 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_java.h>
+
+#include "DBSetupConnectionPages.hxx"
+#include <core_resource.hxx>
+#include <sqlmessage.hxx>
+#include <strings.hrc>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <dsitems.hxx>
+#include "dsnItem.hxx"
+
+#if HAVE_FEATURE_JAVA
+ #include <jvmaccess/virtualmachine.hxx>
+#endif
+
+#include <connectivity/CommonTools.hxx>
+#include <dbwizsetup.hxx>
+#include "TextConnectionHelper.hxx"
+#include <osl/diagnose.h>
+
+namespace dbaui
+{
+using namespace ::com::sun::star;
+
+ std::unique_ptr<OGenericAdministrationPage> OTextConnectionPageSetup::CreateTextTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OTextConnectionPageSetup>(pPage, pController, _rAttrSet);
+ }
+
+ // OTextConnectionPageSetup
+ OTextConnectionPageSetup::OTextConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OConnectionTabPageSetup(pPage, pController, "dbaccess/ui/dbwiztextpage.ui", "DBWizTextPage",
+ rCoreAttrs, STR_TEXT_HELPTEXT, STR_TEXT_HEADERTEXT, STR_TEXT_PATH_OR_FILE)
+ , m_xSubContainer(m_xBuilder->weld_widget("TextPageContainer"))
+ , m_xTextConnectionHelper(new OTextConnectionHelper(m_xSubContainer.get(), TC_EXTENSION | TC_SEPARATORS))
+ {
+ m_xTextConnectionHelper->SetClickHandler(LINK( this, OTextConnectionPageSetup, ImplGetExtensionHdl ) );
+ }
+
+ OTextConnectionPageSetup::~OTextConnectionPageSetup()
+ {
+ m_xTextConnectionHelper.reset();
+ }
+
+ IMPL_LINK_NOARG(OTextConnectionPageSetup, ImplGetExtensionHdl, OTextConnectionHelper*, void)
+ {
+ SetRoadmapStateValue(!m_xTextConnectionHelper->GetExtension().isEmpty() && OConnectionTabPageSetup::checkTestConnection());
+ callModifiedHdl();
+ }
+
+ bool OTextConnectionPageSetup::checkTestConnection()
+ {
+ bool bDoEnable = OConnectionTabPageSetup::checkTestConnection();
+ bDoEnable = !m_xTextConnectionHelper->GetExtension().isEmpty() && bDoEnable;
+ return bDoEnable;
+ }
+
+ void OTextConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OConnectionTabPageSetup::fillControls(_rControlList);
+ m_xTextConnectionHelper->fillControls(_rControlList);
+ }
+
+ void OTextConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OConnectionTabPageSetup::fillWindows(_rControlList);
+ m_xTextConnectionHelper->fillWindows(_rControlList);
+ }
+
+ void OTextConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+ OConnectionTabPageSetup::implInitControls( _rSet, _bSaveValue);
+ m_xTextConnectionHelper->implInitControls(_rSet, bValid);
+ }
+
+ bool OTextConnectionPageSetup::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OConnectionTabPageSetup::FillItemSet(_rSet);
+ bChangedSomething = m_xTextConnectionHelper->FillItemSet(*_rSet, bChangedSomething);
+ return bChangedSomething;
+ }
+
+ bool OTextConnectionPageSetup::prepareLeave()
+ {
+ return m_xTextConnectionHelper->prepareLeave();
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OLDAPConnectionPageSetup::CreateLDAPTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet )
+ {
+ return std::make_unique<OLDAPConnectionPageSetup>(pPage, pController, _rAttrSet);
+ }
+
+ // OLDAPPageSetup
+ OLDAPConnectionPageSetup::OLDAPConnectionPageSetup( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs )
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/ldapconnectionpage.ui", "LDAPConnectionPage", _rCoreAttrs)
+ , m_xFTHelpText(m_xBuilder->weld_label("helpLabel"))
+ , m_xFTHostServer(m_xBuilder->weld_label("hostNameLabel"))
+ , m_xETHostServer(m_xBuilder->weld_entry("hostNameEntry"))
+ , m_xFTBaseDN(m_xBuilder->weld_label("baseDNLabel"))
+ , m_xETBaseDN(m_xBuilder->weld_entry("baseDNEntry"))
+ , m_xFTPortNumber(m_xBuilder->weld_label("portNumLabel"))
+ , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumEntry"))
+ , m_xFTDefaultPortNumber(m_xBuilder->weld_label("portNumDefLabel"))
+ , m_xCBUseSSL(m_xBuilder->weld_check_button("useSSLCheckbutton"))
+ {
+ m_xETHostServer->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ m_xETBaseDN->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ m_xNFPortNumber->connect_value_changed(LINK(this, OGenericAdministrationPage, OnControlSpinButtonModifyHdl));
+ m_xCBUseSSL->connect_toggled( LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick) );
+ SetRoadmapStateValue(false);
+ }
+
+ OLDAPConnectionPageSetup::~OLDAPConnectionPageSetup()
+ {
+ }
+
+ bool OLDAPConnectionPageSetup::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = false;
+ fillString(*_rSet,m_xETBaseDN.get(),DSID_CONN_LDAP_BASEDN, bChangedSomething);
+ fillInt32(*_rSet,m_xNFPortNumber.get(),DSID_CONN_LDAP_PORTNUMBER,bChangedSomething);
+
+ if ( m_xETHostServer->get_value_changed_from_saved() )
+ {
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rSet->GetItem(DSID_TYPECOLLECTION) );
+ ::dbaccess::ODsnTypeCollection* pCollection = nullptr;
+ if (pCollectionItem)
+ pCollection = pCollectionItem->getCollection();
+ OSL_ENSURE(pCollection, "OLDAPConnectionPageSetup::FillItemSet : really need a DSN type collection !");
+ if (pCollection)
+ {
+ OUString sUrl = pCollection->getPrefix( "sdbc:address:ldap:") + m_xETHostServer->get_text();
+ _rSet->Put(SfxStringItem(DSID_CONNECTURL, sUrl));
+ bChangedSomething = true;
+ }
+ }
+
+ fillBool(*_rSet,m_xCBUseSSL.get(),DSID_CONN_LDAP_USESSL,false,bChangedSomething);
+ return bChangedSomething;
+ }
+ void OLDAPConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETHostServer.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETBaseDN.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xNFPortNumber.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBUseSSL.get()));
+ }
+ void OLDAPConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHelpText.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHostServer.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTBaseDN.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTPortNumber.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDefaultPortNumber.get()));
+ }
+ void OLDAPConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ const SfxStringItem* pBaseDN = _rSet.GetItem<SfxStringItem>(DSID_CONN_LDAP_BASEDN);
+ const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER);
+
+ if ( bValid )
+ {
+ m_xETBaseDN->set_text(pBaseDN->GetValue());
+ m_xNFPortNumber->set_value(pPortNumber->GetValue());
+ }
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+ callModifiedHdl();
+ }
+
+ void OLDAPConnectionPageSetup::callModifiedHdl(weld::Widget*)
+ {
+ bool bRoadmapState = ((!m_xETHostServer->get_text().isEmpty() ) && ( !m_xETBaseDN->get_text().isEmpty() ) && (!m_xFTPortNumber->get_label().isEmpty() ));
+ SetRoadmapStateValue(bRoadmapState);
+ OGenericAdministrationPage::callModifiedHdl();
+ }
+
+ std::unique_ptr<OMySQLIntroPageSetup> OMySQLIntroPageSetup::CreateMySQLIntroTabPage(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rAttrSet)
+ {
+ return std::make_unique<OMySQLIntroPageSetup>(pPage, pController, rAttrSet);
+ }
+
+ OMySQLIntroPageSetup::OMySQLIntroPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rCoreAttrs)
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/dbwizmysqlintropage.ui", "DBWizMysqlIntroPage", _rCoreAttrs)
+ , m_xODBCDatabase(m_xBuilder->weld_radio_button("odbc"))
+ , m_xJDBCDatabase(m_xBuilder->weld_radio_button("jdbc"))
+ , m_xNATIVEDatabase(m_xBuilder->weld_radio_button("directly"))
+ {
+ m_xODBCDatabase->connect_toggled(LINK(this, OMySQLIntroPageSetup, OnSetupModeSelected));
+ m_xJDBCDatabase->connect_toggled(LINK(this, OMySQLIntroPageSetup, OnSetupModeSelected));
+ m_xNATIVEDatabase->connect_toggled(LINK(this, OMySQLIntroPageSetup, OnSetupModeSelected));
+ pController->SetIntroPage(this);
+ }
+
+ OMySQLIntroPageSetup::~OMySQLIntroPageSetup()
+ {
+ }
+
+ IMPL_LINK_NOARG(OMySQLIntroPageSetup, OnSetupModeSelected, weld::Toggleable&, void)
+ {
+ maClickHdl.Call( this );
+ }
+
+ void OMySQLIntroPageSetup::implInitControls(const SfxItemSet& _rSet, bool /*_bSaveValue*/)
+ {
+ // show the "Connect directly" option only if the driver is installed
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rSet.GetItem(DSID_TYPECOLLECTION) );
+ bool bHasMySQLNative = ( pCollectionItem != nullptr ) && pCollectionItem->getCollection()->hasDriver( "sdbc:mysql:mysqlc:" );
+ if ( bHasMySQLNative )
+ m_xNATIVEDatabase->show();
+
+ // if any of the options is checked, then there's nothing to do
+ if ( m_xODBCDatabase->get_active() || m_xJDBCDatabase->get_active() || m_xNATIVEDatabase->get_active() )
+ return;
+
+ // prefer "native" or "JDBC"
+ if ( bHasMySQLNative )
+ m_xNATIVEDatabase->set_active(true);
+ else
+ m_xJDBCDatabase->set_active(true);
+ }
+
+ void OMySQLIntroPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/)
+ {
+ }
+
+ void OMySQLIntroPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/)
+ {
+ }
+
+ bool OMySQLIntroPageSetup::FillItemSet(SfxItemSet* /*_rSet*/)
+ {
+ OSL_FAIL("Who called me?! Please ask oj for more information.");
+ return true;
+ }
+
+ OMySQLIntroPageSetup::ConnectionType OMySQLIntroPageSetup::getMySQLMode() const
+ {
+ if (m_xJDBCDatabase->get_active())
+ return VIA_JDBC;
+ else if (m_xNATIVEDatabase->get_active())
+ return VIA_NATIVE;
+ else
+ return VIA_ODBC;
+ }
+
+ // MySQLNativeSetupPage
+ MySQLNativeSetupPage::MySQLNativeSetupPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs )
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/dbwizmysqlnativepage.ui", "DBWizMysqlNativePage", rCoreAttrs)
+ , m_xHelpText(m_xBuilder->weld_label("helptext"))
+ , m_xSettingsContainer(m_xBuilder->weld_container("MySQLSettingsContainer"))
+ , m_xMySQLSettings(new MySQLNativeSettings(m_xSettingsContainer.get(), LINK(this, OGenericAdministrationPage, OnControlModified)))
+ {
+ SetRoadmapStateValue(false);
+ }
+
+ MySQLNativeSetupPage::~MySQLNativeSetupPage()
+ {
+ m_xMySQLSettings.reset();
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> MySQLNativeSetupPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet)
+ {
+ return std::make_unique<MySQLNativeSetupPage>(pPage, pController, rAttrSet);
+ }
+
+ void MySQLNativeSetupPage::fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList )
+ {
+ m_xMySQLSettings->fillControls( _rControlList );
+ }
+
+ void MySQLNativeSetupPage::fillWindows(std::vector<std::unique_ptr<ISaveValueWrapper>>& rControlList)
+ {
+ rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xHelpText.get()));
+ m_xMySQLSettings->fillWindows(rControlList);
+ }
+
+ bool MySQLNativeSetupPage::FillItemSet( SfxItemSet* _rSet )
+ {
+ return m_xMySQLSettings->FillItemSet( _rSet );
+ }
+
+ void MySQLNativeSetupPage::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue )
+ {
+ m_xMySQLSettings->implInitControls( _rSet );
+
+ OGenericAdministrationPage::implInitControls( _rSet, _bSaveValue );
+
+ callModifiedHdl();
+ }
+
+ void MySQLNativeSetupPage::callModifiedHdl(weld::Widget*)
+ {
+ SetRoadmapStateValue( m_xMySQLSettings->canAdvance() );
+
+ OGenericAdministrationPage::callModifiedHdl();
+ }
+
+ // OMySQLJDBCConnectionPageSetup
+ OGeneralSpecialJDBCConnectionPageSetup::OGeneralSpecialJDBCConnectionPageSetup( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs ,sal_uInt16 _nPortId, TranslateId pDefaultPortResId, TranslateId pHelpTextResId, TranslateId pHeaderTextResId, TranslateId pDriverClassId)
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/specialjdbcconnectionpage.ui", "SpecialJDBCConnectionPage", _rCoreAttrs)
+ , m_nPortId(_nPortId)
+ , m_xHeaderText(m_xBuilder->weld_label("header"))
+ , m_xFTHelpText(m_xBuilder->weld_label("helpLabel"))
+ , m_xFTDatabasename(m_xBuilder->weld_label("dbNameLabel"))
+ , m_xETDatabasename(m_xBuilder->weld_entry("dbNameEntry"))
+ , m_xFTHostname(m_xBuilder->weld_label("hostNameLabel"))
+ , m_xETHostname(m_xBuilder->weld_entry("hostNameEntry"))
+ , m_xFTPortNumber(m_xBuilder->weld_label("portNumLabel"))
+ , m_xFTDefaultPortNumber(m_xBuilder->weld_label("portNumDefLabel"))
+ , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumEntry"))
+ , m_xFTDriverClass(m_xBuilder->weld_label("jdbcDriverLabel"))
+ , m_xETDriverClass(m_xBuilder->weld_entry("jdbcDriverEntry"))
+ , m_xPBTestJavaDriver(m_xBuilder->weld_button("testDriverButton"))
+ {
+ m_xFTDriverClass->set_label(DBA_RES(pDriverClassId));
+
+ m_xFTDefaultPortNumber->set_label(DBA_RES(pDefaultPortResId));
+ OUString sHelpText = DBA_RES(pHelpTextResId);
+ m_xFTHelpText->set_label(sHelpText);
+ //TODO this code snippet is redundant
+ m_xHeaderText->set_label(DBA_RES(pHeaderTextResId));
+
+ m_xETDatabasename->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ m_xETHostname->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ m_xNFPortNumber->connect_value_changed(LINK(this, OGenericAdministrationPage, OnControlSpinButtonModifyHdl));
+
+ m_xETDriverClass->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ m_xPBTestJavaDriver->connect_clicked(LINK(this,OGeneralSpecialJDBCConnectionPageSetup,OnTestJavaClickHdl));
+
+ const SfxStringItem* pUrlItem = _rCoreAttrs.GetItem<SfxStringItem>(DSID_CONNECTURL);
+ const DbuTypeCollectionItem* pTypesItem = _rCoreAttrs.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
+ ::dbaccess::ODsnTypeCollection* pTypeCollection = pTypesItem ? pTypesItem->getCollection() : nullptr;
+ if (pTypeCollection && pUrlItem && pUrlItem->GetValue().getLength() )
+ {
+ m_sDefaultJdbcDriverName = pTypeCollection->getJavaDriverClass(pUrlItem->GetValue());
+ }
+
+ SetRoadmapStateValue(false);
+ }
+
+ OGeneralSpecialJDBCConnectionPageSetup::~OGeneralSpecialJDBCConnectionPageSetup()
+ {
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet )
+ {
+ return std::make_unique<OGeneralSpecialJDBCConnectionPageSetup>(pPage, pController,
+ _rAttrSet,
+ DSID_MYSQL_PORTNUMBER ,
+ STR_MYSQL_DEFAULT,
+ STR_MYSQLJDBC_HELPTEXT,
+ STR_MYSQLJDBC_HEADERTEXT,
+ STR_MYSQL_DRIVERCLASSTEXT);
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet )
+ {
+ return std::make_unique<OGeneralSpecialJDBCConnectionPageSetup>(pPage, pController,
+ _rAttrSet,
+ DSID_ORACLE_PORTNUMBER,
+ STR_ORACLE_DEFAULT,
+ STR_ORACLE_HELPTEXT,
+ STR_ORACLE_HEADERTEXT,
+ STR_ORACLE_DRIVERCLASSTEXT);
+ }
+
+ void OGeneralSpecialJDBCConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETDatabasename.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETDriverClass.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETHostname.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xNFPortNumber.get()));
+ }
+
+ void OGeneralSpecialJDBCConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHelpText.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDatabasename.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHostname.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTPortNumber.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDefaultPortNumber.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDriverClass.get()));
+ }
+
+ bool OGeneralSpecialJDBCConnectionPageSetup::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = false;
+ fillString(*_rSet,m_xETDriverClass.get(),DSID_JDBCDRIVERCLASS,bChangedSomething);
+ fillString(*_rSet,m_xETHostname.get(),DSID_CONN_HOSTNAME,bChangedSomething);
+ fillString(*_rSet,m_xETDatabasename.get(),DSID_DATABASENAME,bChangedSomething);
+ fillInt32(*_rSet,m_xNFPortNumber.get(),m_nPortId,bChangedSomething );
+ return bChangedSomething;
+ }
+
+ void OGeneralSpecialJDBCConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ const SfxStringItem* pDatabaseName = _rSet.GetItem<SfxStringItem>(DSID_DATABASENAME);
+ const SfxStringItem* pDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS);
+ const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
+ const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(m_nPortId);
+
+ if ( bValid )
+ {
+ m_xETDatabasename->set_text(pDatabaseName->GetValue());
+ m_xETDatabasename->save_value();
+
+ m_xETDriverClass->set_text(pDrvItem->GetValue());
+ m_xETDriverClass->save_value();
+
+ m_xETHostname->set_text(pHostName->GetValue());
+ m_xETHostname->save_value();
+
+ m_xNFPortNumber->set_value(pPortNumber->GetValue());
+ m_xNFPortNumber->save_value();
+ }
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+
+ // to get the correct value when saveValue was called by base class
+ if ( m_xETDriverClass->get_text().trim().isEmpty() )
+ {
+ m_xETDriverClass->set_text(m_sDefaultJdbcDriverName);
+ m_xETDriverClass->save_value();
+ }
+ callModifiedHdl();
+
+ bool bRoadmapState = ((!m_xETDatabasename->get_text().isEmpty() ) && (!m_xETHostname->get_text().isEmpty()) && (!m_xNFPortNumber->get_text().isEmpty() ) && ( !m_xETDriverClass->get_text().isEmpty() ));
+ SetRoadmapStateValue(bRoadmapState);
+ }
+
+ IMPL_LINK_NOARG(OGeneralSpecialJDBCConnectionPageSetup, OnTestJavaClickHdl, weld::Button&, void)
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+
+ bool bSuccess = false;
+#if HAVE_FEATURE_JAVA
+ try
+ {
+ if ( !m_xETDriverClass->get_text().trim().isEmpty() )
+ {
+// TODO change jvmaccess
+ ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() );
+ m_xETDriverClass->set_text(m_xETDriverClass->get_text().trim()); // fdo#68341
+ bSuccess = ::connectivity::existsJavaClassByName(xJVM,m_xETDriverClass->get_text());
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ }
+#endif
+ TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS;
+ const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error;
+ OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt);
+ aMsg.run();
+ }
+
+ void OGeneralSpecialJDBCConnectionPageSetup::callModifiedHdl(weld::Widget* pControl)
+ {
+ if (pControl == m_xETDriverClass.get())
+ m_xPBTestJavaDriver->set_sensitive( !m_xETDriverClass->get_text().trim().isEmpty() );
+ bool bRoadmapState = ((!m_xETDatabasename->get_text().isEmpty() ) && ( !m_xETHostname->get_text().isEmpty() ) && (!m_xNFPortNumber->get_text().isEmpty() ) && ( !m_xETDriverClass->get_text().trim().isEmpty() ));
+ SetRoadmapStateValue(bRoadmapState);
+ OGenericAdministrationPage::callModifiedHdl();
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OJDBCConnectionPageSetup::CreateJDBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OJDBCConnectionPageSetup>(pPage, pController, _rAttrSet);
+ }
+
+ // OMySQLJDBCConnectionPageSetup
+ OJDBCConnectionPageSetup::OJDBCConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OConnectionTabPageSetup(pPage, pController, "dbaccess/ui/jdbcconnectionpage.ui", "JDBCConnectionPage", rCoreAttrs,
+ STR_JDBC_HELPTEXT, STR_JDBC_HEADERTEXT, STR_COMMONURL)
+ , m_xFTDriverClass(m_xBuilder->weld_label("jdbcLabel"))
+ , m_xETDriverClass(m_xBuilder->weld_entry("jdbcEntry"))
+ , m_xPBTestJavaDriver(m_xBuilder->weld_button("jdbcButton"))
+ {
+ m_xETDriverClass->connect_changed(LINK(this, OJDBCConnectionPageSetup, OnEditModified));
+ m_xPBTestJavaDriver->connect_clicked(LINK(this,OJDBCConnectionPageSetup,OnTestJavaClickHdl));
+ }
+
+ OJDBCConnectionPageSetup::~OJDBCConnectionPageSetup()
+ {
+ }
+
+ void OJDBCConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETDriverClass.get()));
+ }
+
+ void OJDBCConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTDriverClass.get()));
+ }
+
+ bool OJDBCConnectionPageSetup::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OConnectionTabPageSetup::FillItemSet(_rSet);
+ fillString(*_rSet,m_xETDriverClass.get(),DSID_JDBCDRIVERCLASS,bChangedSomething);
+ return bChangedSomething;
+ }
+
+ void OJDBCConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ const SfxStringItem* pDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS);
+
+ if ( bValid )
+ {
+ if ( !pDrvItem->GetValue().getLength() )
+ {
+ OUString sDefaultJdbcDriverName = m_pCollection->getJavaDriverClass(m_eType);
+ if ( !sDefaultJdbcDriverName.isEmpty() )
+ {
+ m_xETDriverClass->set_text(sDefaultJdbcDriverName);
+ m_xETDriverClass->save_value();
+ }
+ }
+ else
+ {
+ m_xETDriverClass->set_text(pDrvItem->GetValue());
+ m_xETDriverClass->save_value();
+ }
+ }
+ bool bEnable = pDrvItem->GetValue().getLength() != 0;
+ m_xPBTestJavaDriver->set_sensitive(bEnable);
+ OConnectionTabPageSetup::implInitControls(_rSet, _bSaveValue);
+
+ SetRoadmapStateValue(checkTestConnection());
+ }
+
+ bool OJDBCConnectionPageSetup::checkTestConnection()
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ bool bEnableTestConnection = !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty();
+ bEnableTestConnection = bEnableTestConnection && (!m_xETDriverClass->get_text().isEmpty());
+ return bEnableTestConnection;
+ }
+
+ IMPL_LINK_NOARG(OJDBCConnectionPageSetup, OnTestJavaClickHdl, weld::Button&, void)
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ bool bSuccess = false;
+#if HAVE_FEATURE_JAVA
+ try
+ {
+ if ( !m_xETDriverClass->get_text().isEmpty() )
+ {
+// TODO change jvmaccess
+ ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() );
+ m_xETDriverClass->set_text(m_xETDriverClass->get_text().trim()); // fdo#68341
+ bSuccess = xJVM.is() && ::connectivity::existsJavaClassByName(xJVM,m_xETDriverClass->get_text());
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ }
+#endif
+ TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS;
+ const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error;
+ OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt);
+ aMsg.run();
+ }
+
+ IMPL_LINK(OJDBCConnectionPageSetup, OnEditModified, weld::Entry&, rEdit, void)
+ {
+ if (&rEdit == m_xETDriverClass.get())
+ m_xPBTestJavaDriver->set_sensitive(!m_xETDriverClass->get_text().isEmpty());
+ SetRoadmapStateValue(checkTestConnection());
+ // tell the listener we were modified
+ callModifiedHdl();
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OSpreadSheetConnectionPageSetup>(pPage, pController, _rAttrSet);
+ }
+
+ OSpreadSheetConnectionPageSetup::OSpreadSheetConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OConnectionTabPageSetup(pPage, pController, "dbaccess/ui/dbwizspreadsheetpage.ui", "DBWizSpreadsheetPage",
+ rCoreAttrs, STR_SPREADSHEET_HELPTEXT, STR_SPREADSHEET_HEADERTEXT, STR_SPREADSHEETPATH)
+ , m_xPasswordrequired(m_xBuilder->weld_check_button("passwordrequired"))
+ {
+ m_xPasswordrequired->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick));
+ }
+
+ OSpreadSheetConnectionPageSetup::~OSpreadSheetConnectionPageSetup()
+ {
+ }
+
+ void OSpreadSheetConnectionPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/)
+ {
+ }
+
+ void OSpreadSheetConnectionPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OConnectionTabPageSetup::fillControls(_rControlList);
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xPasswordrequired.get()));
+
+ }
+
+ bool OSpreadSheetConnectionPageSetup::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OConnectionTabPageSetup::FillItemSet(_rSet);
+ fillBool(*_rSet,m_xPasswordrequired.get(),DSID_PASSWORDREQUIRED,false,bChangedSomething);
+ return bChangedSomething;
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OAuthentificationPageSetup::CreateAuthentificationTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OAuthentificationPageSetup>(pPage, pController, _rAttrSet);
+ }
+
+ OAuthentificationPageSetup::OAuthentificationPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs)
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/authentificationpage.ui", "AuthentificationPage", _rCoreAttrs)
+ , m_xFTHelpText(m_xBuilder->weld_label("helptext"))
+ , m_xFTUserName(m_xBuilder->weld_label("generalUserNameLabel"))
+ , m_xETUserName(m_xBuilder->weld_entry("generalUserNameEntry"))
+ , m_xCBPasswordRequired(m_xBuilder->weld_check_button("passRequiredCheckbutton"))
+ , m_xPBTestConnection(m_xBuilder->weld_button("testConnectionButton"))
+ {
+ m_xETUserName->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl));
+ m_xCBPasswordRequired->connect_toggled(LINK(this,OGenericAdministrationPage,OnControlModifiedButtonClick));
+ m_xPBTestConnection->connect_clicked(LINK(this,OGenericAdministrationPage,OnTestConnectionButtonClickHdl));
+ }
+
+ OAuthentificationPageSetup::~OAuthentificationPageSetup()
+ {
+ }
+
+ void OAuthentificationPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHelpText.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTUserName.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Button>(m_xPBTestConnection.get()));
+ }
+
+ void OAuthentificationPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xETUserName.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBPasswordRequired.get()));
+ }
+
+ void OAuthentificationPageSetup::implInitControls(const SfxItemSet& _rSet, bool /*_bSaveValue*/)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+ const SfxStringItem* pUidItem = _rSet.GetItem<SfxStringItem>(DSID_USER);
+ const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED);
+
+ m_xETUserName->set_text(pUidItem->GetValue());
+ m_xCBPasswordRequired->set_active(pAllowEmptyPwd->GetValue());
+
+ m_xETUserName->save_value();
+ }
+
+ bool OAuthentificationPageSetup::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = false;
+
+ if (m_xETUserName->get_value_changed_from_saved())
+ {
+ _rSet->Put(SfxStringItem(DSID_USER, m_xETUserName->get_text()));
+ _rSet->Put(SfxStringItem(DSID_PASSWORD, OUString()));
+ bChangedSomething = true;
+ }
+ fillBool(*_rSet, m_xCBPasswordRequired.get(), DSID_PASSWORDREQUIRED, false, bChangedSomething);
+ return bChangedSomething;
+ }
+
+ std::unique_ptr<OGenericAdministrationPage> OFinalDBPageSetup::CreateFinalDBTabPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rAttrSet)
+ {
+ return std::make_unique<OFinalDBPageSetup>(pPage, pController, _rAttrSet);
+ }
+
+ OFinalDBPageSetup::OFinalDBPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rCoreAttrs)
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/finalpagewizard.ui", "PageFinal", _rCoreAttrs)
+ , m_xFTFinalHeader(m_xBuilder->weld_label("headerText"))
+ , m_xFTFinalHelpText(m_xBuilder->weld_label("helpText"))
+ , m_xRBRegisterDataSource(m_xBuilder->weld_radio_button("yesregister"))
+ , m_xRBDontregisterDataSource(m_xBuilder->weld_radio_button("noregister"))
+ , m_xFTAdditionalSettings(m_xBuilder->weld_label("additionalText"))
+ , m_xCBOpenAfterwards(m_xBuilder->weld_check_button("openediting"))
+ , m_xCBStartTableWizard(m_xBuilder->weld_check_button("usewizard"))
+ , m_xFTFinalText(m_xBuilder->weld_label("finishText"))
+ {
+ m_xCBOpenAfterwards->connect_toggled(LINK(this, OFinalDBPageSetup, OnOpenSelected));
+ m_xRBRegisterDataSource->set_active(true);
+ pController->SetFinalPage(this);
+ }
+
+ OFinalDBPageSetup::~OFinalDBPageSetup()
+ {
+ }
+
+ bool OFinalDBPageSetup::IsDatabaseDocumentToBeRegistered() const
+ {
+ return m_xRBRegisterDataSource->get_active() && m_xRBRegisterDataSource->get_sensitive();
+ }
+
+ bool OFinalDBPageSetup::IsDatabaseDocumentToBeOpened() const
+ {
+ return m_xCBOpenAfterwards->get_active() && m_xCBOpenAfterwards->get_sensitive();
+ }
+
+ bool OFinalDBPageSetup::IsTableWizardToBeStarted() const
+ {
+ return m_xCBStartTableWizard->get_active() && m_xCBStartTableWizard->get_sensitive();
+ }
+
+ void OFinalDBPageSetup::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTFinalHeader.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTFinalHelpText.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTAdditionalSettings.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTFinalText.get()));
+ }
+
+ void OFinalDBPageSetup::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBOpenAfterwards.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xCBStartTableWizard.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xRBRegisterDataSource.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xRBDontregisterDataSource.get()));
+ }
+
+ void OFinalDBPageSetup::implInitControls(const SfxItemSet& /*_rSet*/, bool /*_bSaveValue*/)
+ {
+ m_xCBOpenAfterwards->set_active(true);
+ }
+
+ void OFinalDBPageSetup::enableTableWizardCheckBox( bool _bSupportsTableCreation)
+ {
+ m_xCBStartTableWizard->set_sensitive(_bSupportsTableCreation);
+ }
+
+ bool OFinalDBPageSetup::FillItemSet( SfxItemSet* /*_rSet*/ )
+ {
+ return true;
+ }
+
+ IMPL_LINK(OFinalDBPageSetup, OnOpenSelected, weld::Toggleable&, rBox, void)
+ {
+ m_xCBStartTableWizard->set_sensitive(rBox.get_sensitive() && rBox.get_active());
+ }
+}
+
+// namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx b/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx
new file mode 100644
index 000000000..8bc367602
--- /dev/null
+++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx
@@ -0,0 +1,270 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ConnectionPageSetup.hxx"
+
+#include "adminpages.hxx"
+#include "admincontrols.hxx"
+#include "TextConnectionHelper.hxx"
+
+namespace dbaui
+{
+ class ODbTypeWizDialogSetup;
+
+ // OSpreadSheetConnectionPageSetup
+ class OSpreadSheetConnectionPageSetup final : public OConnectionTabPageSetup
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+ static std::unique_ptr<OGenericAdministrationPage> CreateDocumentOrSpreadSheetTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet);
+ OSpreadSheetConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~OSpreadSheetConnectionPageSetup() override;
+
+ private:
+ std::unique_ptr<weld::CheckButton> m_xPasswordrequired;
+
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ };
+
+ // OTextConnectionPage
+ class OTextConnectionPageSetup : public OConnectionTabPageSetup
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+ static std::unique_ptr<OGenericAdministrationPage> CreateTextTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet );
+ OTextConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~OTextConnectionPageSetup() override;
+ protected:
+ virtual bool prepareLeave() override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ bool checkTestConnection() override;
+ private:
+ DECL_LINK(ImplGetExtensionHdl, OTextConnectionHelper*, void);
+ std::unique_ptr<weld::Widget> m_xSubContainer;
+ std::unique_ptr<OTextConnectionHelper> m_xTextConnectionHelper;
+ };
+
+ // OLDAPConnectionPageSetup
+ class OLDAPConnectionPageSetup : public OGenericAdministrationPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+ static std::unique_ptr<OGenericAdministrationPage> CreateLDAPTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet );
+ OLDAPConnectionPageSetup( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs );
+ virtual ~OLDAPConnectionPageSetup() override;
+ virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override;
+
+ protected:
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ private:
+ std::unique_ptr<weld::Label> m_xFTHelpText;
+ std::unique_ptr<weld::Label> m_xFTHostServer;
+ std::unique_ptr<weld::Entry> m_xETHostServer;
+ std::unique_ptr<weld::Label> m_xFTBaseDN;
+ std::unique_ptr<weld::Entry> m_xETBaseDN;
+ std::unique_ptr<weld::Label> m_xFTPortNumber;
+ std::unique_ptr<weld::SpinButton> m_xNFPortNumber;
+ std::unique_ptr<weld::Label> m_xFTDefaultPortNumber;
+ std::unique_ptr<weld::CheckButton> m_xCBUseSSL;
+ };
+
+ // MySQLNativeSetupPage
+ class MySQLNativeSetupPage : public OGenericAdministrationPage
+ {
+ private:
+ std::unique_ptr<weld::Label> m_xHelpText;
+ std::unique_ptr<weld::Container> m_xSettingsContainer;
+ std::unique_ptr<MySQLNativeSettings> m_xMySQLSettings;
+
+ public:
+ MySQLNativeSetupPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ virtual ~MySQLNativeSetupPage() override;
+
+ static std::unique_ptr<OGenericAdministrationPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet);
+
+ protected:
+ virtual void fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) override;
+ virtual void fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList ) override;
+
+ virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override;
+ };
+
+ // OGeneralSpecialJDBCConnectionPageSetup
+ class OGeneralSpecialJDBCConnectionPageSetup final : public OGenericAdministrationPage
+ {
+ public:
+ OGeneralSpecialJDBCConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController
+ , const SfxItemSet& _rCoreAttrs
+ , sal_uInt16 _nPortId
+ , TranslateId pDefaultPortResId
+ , TranslateId pHelpTextResId
+ , TranslateId pHeaderTextResId
+ , TranslateId pDriverClassId );
+ virtual ~OGeneralSpecialJDBCConnectionPageSetup() override;
+ static std::unique_ptr<OGenericAdministrationPage> CreateMySQLJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet );
+ static std::unique_ptr<OGenericAdministrationPage> CreateOracleJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet );
+
+ private:
+ virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override;
+
+ DECL_LINK(OnTestJavaClickHdl, weld::Button&, void);
+
+ OUString m_sDefaultJdbcDriverName;
+ sal_uInt16 m_nPortId;
+
+ std::unique_ptr<weld::Label> m_xHeaderText;
+ std::unique_ptr<weld::Label> m_xFTHelpText;
+ std::unique_ptr<weld::Label> m_xFTDatabasename;
+ std::unique_ptr<weld::Entry> m_xETDatabasename;
+ std::unique_ptr<weld::Label> m_xFTHostname;
+ std::unique_ptr<weld::Entry> m_xETHostname;
+ std::unique_ptr<weld::Label> m_xFTPortNumber;
+ std::unique_ptr<weld::Label> m_xFTDefaultPortNumber;
+ std::unique_ptr<weld::SpinButton> m_xNFPortNumber;
+
+ std::unique_ptr<weld::Label> m_xFTDriverClass;
+ std::unique_ptr<weld::Entry> m_xETDriverClass;
+ std::unique_ptr<weld::Button> m_xPBTestJavaDriver;
+ };
+
+ // OJDBCConnectionPageSetup
+ class OJDBCConnectionPageSetup final : public OConnectionTabPageSetup
+ {
+ public:
+ OJDBCConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~OJDBCConnectionPageSetup() override;
+ static std::unique_ptr<OGenericAdministrationPage> CreateJDBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet);
+
+ private:
+ virtual bool checkTestConnection() override;
+
+ virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ DECL_LINK(OnTestJavaClickHdl, weld::Button&, void);
+ DECL_LINK(OnEditModified, weld::Entry&, void);
+ std::unique_ptr<weld::Label> m_xFTDriverClass;
+ std::unique_ptr<weld::Entry> m_xETDriverClass;
+ std::unique_ptr<weld::Button> m_xPBTestJavaDriver;
+ };
+
+ // OMySQLIntroPageSetup
+ class OMySQLIntroPageSetup : public OGenericAdministrationPage
+ {
+ public:
+ enum ConnectionType
+ {
+ VIA_ODBC,
+ VIA_JDBC,
+ VIA_NATIVE
+ };
+
+ OMySQLIntroPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rCoreAttrs);
+ virtual ~OMySQLIntroPageSetup() override;
+
+ static std::unique_ptr<OMySQLIntroPageSetup> CreateMySQLIntroTabPage(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rAttrSet);
+ ConnectionType getMySQLMode() const;
+ void SetClickHdl( const Link<OMySQLIntroPageSetup *, void>& rLink ) { maClickHdl = rLink; }
+
+ protected:
+ virtual bool FillItemSet(SfxItemSet* _rSet) override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ private:
+ std::unique_ptr<weld::RadioButton> m_xODBCDatabase;
+ std::unique_ptr<weld::RadioButton> m_xJDBCDatabase;
+ std::unique_ptr<weld::RadioButton> m_xNATIVEDatabase;
+ Link<OMySQLIntroPageSetup *, void> maClickHdl;
+
+ DECL_LINK(OnSetupModeSelected, weld::Toggleable&, void);
+ };
+
+ // OAuthentificationPageSetup
+ class OAuthentificationPageSetup final : public OGenericAdministrationPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+ static std::unique_ptr<OGenericAdministrationPage> CreateAuthentificationTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet);
+ OAuthentificationPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~OAuthentificationPageSetup() override;
+
+ private:
+ std::unique_ptr<weld::Label> m_xFTHelpText;
+ std::unique_ptr<weld::Label> m_xFTUserName;
+ std::unique_ptr<weld::Entry> m_xETUserName;
+ std::unique_ptr<weld::CheckButton> m_xCBPasswordRequired;
+ std::unique_ptr<weld::Button> m_xPBTestConnection;
+
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ };
+
+ // OFinalDBPageSetup
+ class OFinalDBPageSetup : public OGenericAdministrationPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+ static std::unique_ptr<OGenericAdministrationPage> CreateFinalDBTabPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rAttrSet);
+
+ OFinalDBPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~OFinalDBPageSetup() override;
+ bool IsDatabaseDocumentToBeRegistered() const;
+ bool IsDatabaseDocumentToBeOpened() const;
+ bool IsTableWizardToBeStarted() const;
+ void enableTableWizardCheckBox( bool _bSupportsTableCreation);
+
+ DECL_LINK(OnOpenSelected, weld::Toggleable&, void);
+ protected:
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ private:
+ std::unique_ptr<weld::Label> m_xFTFinalHeader;
+ std::unique_ptr<weld::Label> m_xFTFinalHelpText;
+ std::unique_ptr<weld::RadioButton> m_xRBRegisterDataSource;
+ std::unique_ptr<weld::RadioButton> m_xRBDontregisterDataSource;
+ std::unique_ptr<weld::Label> m_xFTAdditionalSettings;
+ std::unique_ptr<weld::CheckButton> m_xCBOpenAfterwards;
+ std::unique_ptr<weld::CheckButton> m_xCBStartTableWizard;
+ std::unique_ptr<weld::Label> m_xFTFinalText;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/DbAdminImpl.cxx b/dbaccess/source/ui/dlg/DbAdminImpl.cxx
new file mode 100644
index 000000000..ca20930ef
--- /dev/null
+++ b/dbaccess/source/ui/dlg/DbAdminImpl.cxx
@@ -0,0 +1,1074 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DbAdminImpl.hxx"
+#include <dsmeta.hxx>
+
+#include <svl/poolitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <IItemSetHelper.hxx>
+#include <UITools.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <dsitems.hxx>
+#include "dsnItem.hxx"
+#include "optionalboolitem.hxx"
+#include <stringlistitem.hxx>
+#include <OAuthenticationContinuation.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/ConnectionPool.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ucb/AuthenticationRequest.hpp>
+
+#include <comphelper/interaction.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/DriversConfig.hxx>
+#include <connectivity/dbexception.hxx>
+#include <osl/file.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <typelib/typedescription.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/weld.hxx>
+
+#include <algorithm>
+#include <iterator>
+#include <functional>
+#include <o3tl/functional.hxx>
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace com::sun::star::uno;
+using namespace com::sun::star;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::task;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdb;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::util;
+using namespace com::sun::star::container;
+using namespace com::sun::star::frame;
+
+namespace
+{
+ bool implCheckItemType( SfxItemSet const & _rSet, const sal_uInt16 _nId, const std::function<bool ( const SfxPoolItem* )>& isItemType )
+ {
+ bool bCorrectType = false;
+
+ SfxItemPool* pPool = _rSet.GetPool();
+ OSL_ENSURE( pPool, "implCheckItemType: invalid item pool!" );
+ if ( pPool )
+ {
+ const SfxPoolItem& rDefItem = pPool->GetDefaultItem( _nId );
+ bCorrectType = isItemType(&rDefItem);
+ }
+ return bCorrectType;
+ }
+
+ void lcl_putProperty(const Reference< XPropertySet >& _rxSet, const OUString& _rName, const Any& _rValue)
+ {
+ try
+ {
+ if ( _rxSet.is() )
+ _rxSet->setPropertyValue(_rName, _rValue);
+ }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess", "ODbAdminDialog::implTranslateProperty: could not set the property "
+ << _rName);
+ }
+
+ }
+
+ OUString lcl_createHostWithPort(const SfxStringItem* _pHostName,const SfxInt32Item* _pPortNumber)
+ {
+ OUString sNewUrl;
+
+ if ( _pHostName && _pHostName->GetValue().getLength() )
+ sNewUrl = _pHostName->GetValue();
+
+ if ( _pPortNumber )
+ {
+ sNewUrl += ":" + OUString::number(_pPortNumber->GetValue());
+ }
+
+ return sNewUrl;
+ }
+}
+
+ // ODbDataSourceAdministrationHelper
+ODbDataSourceAdministrationHelper::ODbDataSourceAdministrationHelper(const Reference< XComponentContext >& _xORB, weld::Window* pParent, weld::Window* pTopParent, IItemSetHelper* _pItemSetHelper)
+ : m_xContext(_xORB)
+ , m_pParent(pParent)
+ , m_pItemSetHelper(_pItemSetHelper)
+{
+ /// initialize the property translation map
+ // direct properties of a data source
+ m_aDirectPropTranslator.emplace( DSID_CONNECTURL, PROPERTY_URL );
+ m_aDirectPropTranslator.emplace( DSID_NAME, PROPERTY_NAME );
+ m_aDirectPropTranslator.emplace( DSID_USER, PROPERTY_USER );
+ m_aDirectPropTranslator.emplace( DSID_PASSWORD, PROPERTY_PASSWORD );
+ m_aDirectPropTranslator.emplace( DSID_PASSWORDREQUIRED, PROPERTY_ISPASSWORDREQUIRED );
+ m_aDirectPropTranslator.emplace( DSID_TABLEFILTER, PROPERTY_TABLEFILTER );
+ m_aDirectPropTranslator.emplace( DSID_READONLY, PROPERTY_ISREADONLY );
+ m_aDirectPropTranslator.emplace( DSID_SUPPRESSVERSIONCL, PROPERTY_SUPPRESSVERSIONCL );
+
+ // implicit properties, to be found in the direct property "Info"
+ m_aIndirectPropTranslator.emplace( DSID_JDBCDRIVERCLASS, INFO_JDBCDRIVERCLASS );
+ m_aIndirectPropTranslator.emplace( DSID_TEXTFILEEXTENSION, INFO_TEXTFILEEXTENSION );
+ m_aIndirectPropTranslator.emplace( DSID_CHARSET, INFO_CHARSET );
+ m_aIndirectPropTranslator.emplace( DSID_TEXTFILEHEADER, INFO_TEXTFILEHEADER );
+ m_aIndirectPropTranslator.emplace( DSID_FIELDDELIMITER, INFO_FIELDDELIMITER );
+ m_aIndirectPropTranslator.emplace( DSID_TEXTDELIMITER, INFO_TEXTDELIMITER );
+ m_aIndirectPropTranslator.emplace( DSID_DECIMALDELIMITER, INFO_DECIMALDELIMITER );
+ m_aIndirectPropTranslator.emplace( DSID_THOUSANDSDELIMITER, INFO_THOUSANDSDELIMITER );
+ m_aIndirectPropTranslator.emplace( DSID_SHOWDELETEDROWS, INFO_SHOWDELETEDROWS );
+ m_aIndirectPropTranslator.emplace( DSID_ALLOWLONGTABLENAMES, INFO_ALLOWLONGTABLENAMES );
+ m_aIndirectPropTranslator.emplace( DSID_ADDITIONALOPTIONS, INFO_ADDITIONALOPTIONS );
+ m_aIndirectPropTranslator.emplace( DSID_SQL92CHECK, PROPERTY_ENABLESQL92CHECK );
+ m_aIndirectPropTranslator.emplace( DSID_AUTOINCREMENTVALUE, PROPERTY_AUTOINCREMENTCREATION );
+ m_aIndirectPropTranslator.emplace( DSID_AUTORETRIEVEVALUE, INFO_AUTORETRIEVEVALUE );
+ m_aIndirectPropTranslator.emplace( DSID_AUTORETRIEVEENABLED, INFO_AUTORETRIEVEENABLED );
+ m_aIndirectPropTranslator.emplace( DSID_APPEND_TABLE_ALIAS, INFO_APPEND_TABLE_ALIAS );
+ m_aIndirectPropTranslator.emplace( DSID_AS_BEFORE_CORRNAME, INFO_AS_BEFORE_CORRELATION_NAME );
+ m_aIndirectPropTranslator.emplace( DSID_CHECK_REQUIRED_FIELDS, INFO_FORMS_CHECK_REQUIRED_FIELDS );
+ m_aIndirectPropTranslator.emplace( DSID_ESCAPE_DATETIME, INFO_ESCAPE_DATETIME );
+ m_aIndirectPropTranslator.emplace( DSID_PRIMARY_KEY_SUPPORT, OUString("PrimaryKeySupport") );
+ m_aIndirectPropTranslator.emplace( DSID_PARAMETERNAMESUBST, INFO_PARAMETERNAMESUBST );
+ m_aIndirectPropTranslator.emplace( DSID_IGNOREDRIVER_PRIV, INFO_IGNOREDRIVER_PRIV );
+ m_aIndirectPropTranslator.emplace( DSID_BOOLEANCOMPARISON, PROPERTY_BOOLEANCOMPARISONMODE );
+ m_aIndirectPropTranslator.emplace( DSID_ENABLEOUTERJOIN, PROPERTY_ENABLEOUTERJOIN );
+ m_aIndirectPropTranslator.emplace( DSID_CATALOG, PROPERTY_USECATALOGINSELECT );
+ m_aIndirectPropTranslator.emplace( DSID_SCHEMA, PROPERTY_USESCHEMAINSELECT );
+ m_aIndirectPropTranslator.emplace( DSID_INDEXAPPENDIX, OUString("AddIndexAppendix") );
+ m_aIndirectPropTranslator.emplace( DSID_DOSLINEENDS, OUString("PreferDosLikeLineEnds") );
+ m_aIndirectPropTranslator.emplace( DSID_CONN_SOCKET, OUString("LocalSocket") );
+ m_aIndirectPropTranslator.emplace( DSID_NAMED_PIPE, OUString("NamedPipe") );
+ m_aIndirectPropTranslator.emplace( DSID_RESPECTRESULTSETTYPE, OUString("RespectDriverResultSetType") );
+ m_aIndirectPropTranslator.emplace( DSID_MAX_ROW_SCAN, OUString("MaxRowScan") );
+
+ // extra settings for ODBC
+ m_aIndirectPropTranslator.emplace( DSID_USECATALOG, INFO_USECATALOG );
+ // extra settings for an LDAP address book
+ m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_BASEDN, INFO_CONN_LDAP_BASEDN );
+ m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_ROWCOUNT, INFO_CONN_LDAP_ROWCOUNT );
+ m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_USESSL, OUString("UseSSL") );
+ m_aIndirectPropTranslator.emplace( DSID_DOCUMENT_URL, PROPERTY_URL );
+
+ // Oracle
+ m_aIndirectPropTranslator.emplace( DSID_IGNORECURRENCY, OUString("IgnoreCurrency") );
+
+ try
+ {
+ m_xDatabaseContext = DatabaseContext::create(m_xContext);
+ }
+ catch(const Exception&)
+ {
+ ShowServiceNotAvailableError(pTopParent, u"com.sun.star.sdb.DatabaseContext", true);
+ }
+}
+
+bool ODbDataSourceAdministrationHelper::getCurrentSettings(Sequence< PropertyValue >& _rDriverParam)
+{
+ OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::getCurrentSettings : not to be called without an example set!");
+ if (!m_pItemSetHelper->getOutputSet())
+ return false;
+
+ std::vector< PropertyValue > aReturn;
+ // collecting this in a vector because it has a push_back, in opposite to sequences
+
+ // user: DSID_USER -> "user"
+ const SfxStringItem* pUser = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_USER);
+ if (pUser && pUser->GetValue().getLength())
+ aReturn.emplace_back( "user", 0,
+ Any(pUser->GetValue()), PropertyState_DIRECT_VALUE);
+
+ // check if the connection type requires a password
+ if (hasAuthentication(*m_pItemSetHelper->getOutputSet()))
+ {
+ // password: DSID_PASSWORD -> password
+ const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD);
+ OUString sPassword = pPassword ? pPassword->GetValue() : OUString();
+ const SfxBoolItem* pPasswordRequired = m_pItemSetHelper->getOutputSet()->GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED);
+ // if the set does not contain a password, but the item set says it requires one, ask the user
+ if ((!pPassword || !pPassword->GetValue().getLength()) && (pPasswordRequired && pPasswordRequired->GetValue()))
+ {
+ const SfxStringItem* pName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_NAME);
+
+ Reference< XModel > xModel( getDataSourceOrModel( m_xDatasource ), UNO_QUERY_THROW );
+ ::comphelper::NamedValueCollection aArgs( xModel->getArgs() );
+ Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) );
+
+ if ( !xHandler.is() )
+ {
+ // instantiate the default SDB interaction handler
+ xHandler = task::InteractionHandler::createWithParent(m_xContext, m_pParent->GetXWindow());
+ }
+
+ OUString sName = pName ? pName->GetValue() : OUString();
+ OUString sLoginRequest(DBA_RES(STR_ENTER_CONNECTION_PASSWORD));
+ OUString sTemp = sName;
+ sName = ::dbaui::getStrippedDatabaseName(nullptr,sTemp);
+ if ( !sName.isEmpty() )
+ sLoginRequest = sLoginRequest.replaceAll("$name$", sName);
+ else
+ {
+ sLoginRequest = sLoginRequest.replaceAll("\"$name$\"", "");
+ // ensure that in other languages the string will be deleted
+ sLoginRequest = sLoginRequest.replaceAll("$name$", "");
+ }
+
+ // the request
+ AuthenticationRequest aRequest;
+ aRequest.ServerName = sName;
+ aRequest.Diagnostic = sLoginRequest;
+ aRequest.HasRealm = false;
+ // aRequest.Realm
+ aRequest.HasUserName = pUser != nullptr;
+ aRequest.UserName = pUser ? pUser->GetValue() : OUString();
+ aRequest.HasPassword = true;
+ //aRequest.Password
+ aRequest.HasAccount = false;
+ // aRequest.Account
+
+ rtl::Reference<comphelper::OInteractionRequest> pRequest = new comphelper::OInteractionRequest(Any(aRequest));
+
+ // build an interaction request
+ // two continuations (Ok and Cancel)
+ ::rtl::Reference< comphelper::OInteractionAbort > pAbort = new comphelper::OInteractionAbort;
+ ::rtl::Reference< dbaccess::OAuthenticationContinuation > pAuthenticate = new dbaccess::OAuthenticationContinuation;
+ pAuthenticate->setCanChangeUserName( false );
+ pAuthenticate->setRememberPassword( RememberAuthentication_SESSION );
+
+ // some knittings
+ pRequest->addContinuation(pAbort);
+ pRequest->addContinuation(pAuthenticate);
+
+ // handle the request
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ // release the mutex when calling the handler, it may need to lock the SolarMutex
+ xHandler->handle(pRequest);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ if (!pAuthenticate->wasSelected())
+ return false;
+
+ sPassword = pAuthenticate->getPassword();
+ if (pAuthenticate->getRememberPassword())
+ m_pItemSetHelper->getWriteOutputSet()->Put(SfxStringItem(DSID_PASSWORD, sPassword));
+ }
+
+ if (!sPassword.isEmpty())
+ aReturn.emplace_back( "password", 0,
+ Any(sPassword), PropertyState_DIRECT_VALUE);
+ }
+
+ if ( !aReturn.empty() )
+ _rDriverParam = comphelper::containerToSequence(aReturn);
+
+ // append all the other stuff (charset etc.)
+ fillDatasourceInfo(*m_pItemSetHelper->getOutputSet(), _rDriverParam);
+
+ return true;
+}
+
+void ODbDataSourceAdministrationHelper::successfullyConnected()
+{
+ OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::successfullyConnected: not to be called without an example set!");
+ if (!m_pItemSetHelper->getOutputSet())
+ return;
+
+ if (hasAuthentication(*m_pItemSetHelper->getOutputSet()))
+ {
+ const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD);
+ if (pPassword && (0 != pPassword->GetValue().getLength()))
+ {
+ OUString sPassword = pPassword->GetValue();
+
+ Reference< XPropertySet > xCurrentDatasource = getCurrentDataSource();
+ lcl_putProperty(xCurrentDatasource,m_aDirectPropTranslator[DSID_PASSWORD], Any(sPassword));
+ }
+ }
+}
+
+void ODbDataSourceAdministrationHelper::clearPassword()
+{
+ if (m_pItemSetHelper->getWriteOutputSet())
+ m_pItemSetHelper->getWriteOutputSet()->ClearItem(DSID_PASSWORD);
+}
+
+std::pair< Reference<XConnection>,bool> ODbDataSourceAdministrationHelper::createConnection()
+{
+ std::pair< Reference<XConnection>,bool> aRet;
+ aRet.second = false;
+ Sequence< PropertyValue > aConnectionParams;
+ if ( getCurrentSettings(aConnectionParams) )
+ {
+ // the current DSN
+ // fill the table list with this connection information
+ SQLExceptionInfo aErrorInfo;
+ try
+ {
+ weld::WaitObject aWaitCursor(m_pParent);
+ aRet.first = getDriver()->connect(getConnectionURL(), aConnectionParams);
+ aRet.second = true;
+ }
+ catch (const SQLContext& e) { aErrorInfo = SQLExceptionInfo(e); }
+ catch (const SQLWarning& e) { aErrorInfo = SQLExceptionInfo(e); }
+ catch (const SQLException& e) { aErrorInfo = SQLExceptionInfo(e); }
+
+ showError(aErrorInfo,m_pParent->GetXWindow(),getORB());
+ }
+ if ( aRet.first.is() )
+ successfullyConnected();// notify the admindlg to save the password
+
+ return aRet;
+}
+
+Reference< XDriver > ODbDataSourceAdministrationHelper::getDriver()
+{
+ return getDriver(getConnectionURL());
+}
+
+Reference< XDriver > ODbDataSourceAdministrationHelper::getDriver(const OUString& _sURL)
+{
+ // get the global DriverManager
+ Reference< XConnectionPool > xDriverManager;
+
+ OUString sCurrentActionError = DBA_RES(STR_COULDNOTCREATE_DRIVERMANAGER);
+ sCurrentActionError = sCurrentActionError.replaceFirst("#servicename#", "com.sun.star.sdbc.ConnectionPool");
+
+ try
+ {
+ xDriverManager.set( ConnectionPool::create( getORB() ) );
+ }
+ catch (const Exception&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ // wrap the exception into an SQLException
+ throw SQLException(sCurrentActionError, getORB(), "S1000", 0, anyEx);
+ }
+
+ Reference< XDriver > xDriver = xDriverManager->getDriverByURL(_sURL);
+ if (!xDriver.is())
+ {
+ sCurrentActionError = DBA_RES(STR_NOREGISTEREDDRIVER);
+ sCurrentActionError = sCurrentActionError.replaceFirst("#connurl#", _sURL);
+ // will be caught and translated into an SQLContext exception
+ throw SQLException(sCurrentActionError, getORB(), "S1000", 0, Any());
+ }
+ return xDriver;
+}
+
+Reference< XPropertySet > const & ODbDataSourceAdministrationHelper::getCurrentDataSource()
+{
+ if ( !m_xDatasource.is() )
+ {
+ Reference<XInterface> xIn(m_aDataSourceOrName,UNO_QUERY);
+ if ( !xIn.is() )
+ {
+ OUString sCurrentDatasource;
+ m_aDataSourceOrName >>= sCurrentDatasource;
+ OSL_ENSURE(!sCurrentDatasource.isEmpty(),"No datasource name given!");
+ try
+ {
+ if ( m_xDatabaseContext.is() )
+ m_xDatasource.set(m_xDatabaseContext->getByName(sCurrentDatasource),UNO_QUERY);
+ xIn = m_xDatasource;
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ m_xModel.set(getDataSourceOrModel(xIn),UNO_QUERY);
+ if ( m_xModel.is() )
+ m_xDatasource.set(xIn,UNO_QUERY);
+ else
+ {
+ m_xDatasource.set(getDataSourceOrModel(xIn),UNO_QUERY);
+ m_xModel.set(xIn,UNO_QUERY);
+ }
+ }
+
+ OSL_ENSURE(m_xDatasource.is(), "ODbDataSourceAdministrationHelper::getCurrentDataSource: no data source!");
+ return m_xDatasource;
+}
+
+OUString ODbDataSourceAdministrationHelper::getDatasourceType( const SfxItemSet& _rSet )
+{
+ const SfxStringItem* pConnectURL = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL);
+ OSL_ENSURE( pConnectURL , "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!" );
+ const DbuTypeCollectionItem* pTypeCollection = _rSet.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
+ OSL_ENSURE(pTypeCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
+ ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection();
+ return pCollection->getType(pConnectURL->GetValue());
+}
+
+bool ODbDataSourceAdministrationHelper::hasAuthentication(const SfxItemSet& _rSet)
+{
+ return DataSourceMetaData::getAuthentication( getDatasourceType( _rSet ) ) != AuthNone;
+}
+
+OUString ODbDataSourceAdministrationHelper::getConnectionURL() const
+{
+ OUString sNewUrl;
+
+ OUString eType = getDatasourceType(*m_pItemSetHelper->getOutputSet());
+
+ const SfxStringItem* pUrlItem = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONNECTURL);
+ const DbuTypeCollectionItem* pTypeCollection = m_pItemSetHelper->getOutputSet()->GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
+
+ OSL_ENSURE(pUrlItem,"Connection URL is NULL. -> GPF!");
+ OSL_ENSURE(pTypeCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
+ ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection();
+ OSL_ENSURE(pCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid type collection!");
+
+ switch( pCollection->determineType(eType) )
+ {
+ case ::dbaccess::DST_DBASE:
+ case ::dbaccess::DST_FLAT:
+ case ::dbaccess::DST_CALC:
+ case ::dbaccess::DST_WRITER:
+ break;
+ case ::dbaccess::DST_MSACCESS:
+ case ::dbaccess::DST_MSACCESS_2007:
+ {
+ OUString sFileName = pCollection->cutPrefix(pUrlItem->GetValue());
+ OUString sNewFileName;
+ if ( ::osl::FileBase::getSystemPathFromFileURL( sFileName, sNewFileName ) == ::osl::FileBase::E_None )
+ {
+ sNewUrl += sNewFileName;
+ }
+ }
+ break;
+ case ::dbaccess::DST_MYSQL_NATIVE:
+ case ::dbaccess::DST_MYSQL_JDBC:
+ {
+ const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
+ const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_MYSQL_PORTNUMBER);
+ const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME);
+ sNewUrl = lcl_createHostWithPort(pHostName,pPortNumber);
+ OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString();
+ if ( !sDatabaseName.getLength() && pUrlItem )
+ sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() );
+ // TODO: what's that? Why is the database name transported via the URL Item?
+ // Huh? Anybody there?
+ // OJ: It is needed when the connection properties are changed. There the URL is used for every type.
+
+ if ( !sDatabaseName.isEmpty() )
+ {
+ sNewUrl += "/" + sDatabaseName;
+ }
+ }
+ break;
+ case ::dbaccess::DST_ORACLE_JDBC:
+ {
+ const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
+ const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_ORACLE_PORTNUMBER);
+ const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME);
+ if ( pHostName && pHostName->GetValue().getLength() )
+ {
+ sNewUrl = "@" + lcl_createHostWithPort(pHostName,pPortNumber);
+ OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString();
+ if ( sDatabaseName.isEmpty() && pUrlItem )
+ sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() );
+ if ( !sDatabaseName.isEmpty() )
+ {
+ sNewUrl += ":" + sDatabaseName;
+ }
+ }
+ else
+ { // here someone entered a JDBC url which looks like oracle, so we have to use the url property
+
+ }
+ }
+ break;
+ case ::dbaccess::DST_LDAP:
+ {
+ const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER);
+ sNewUrl = pCollection->cutPrefix(pUrlItem->GetValue()) + lcl_createHostWithPort(nullptr,pPortNumber);
+ }
+ break;
+ case ::dbaccess::DST_JDBC:
+ // run through
+ default:
+ break;
+ }
+ if ( !sNewUrl.isEmpty() )
+ sNewUrl = pCollection->getPrefix(eType) + sNewUrl;
+ else
+ sNewUrl = pUrlItem->GetValue();
+
+ return sNewUrl;
+}
+
+namespace {
+
+struct PropertyValueLess
+{
+ bool operator() (const PropertyValue& x, const PropertyValue& y) const
+ { return x.Name < y.Name; } // construct prevents a MSVC6 warning
+};
+
+}
+
+typedef std::set<PropertyValue, PropertyValueLess> PropertyValueSet;
+
+void ODbDataSourceAdministrationHelper::translateProperties(const Reference< XPropertySet >& _rxSource, SfxItemSet& _rDest)
+{
+ if (_rxSource.is())
+ {
+ for (auto const& elem : m_aDirectPropTranslator)
+ {
+ // get the property value
+ Any aValue;
+ try
+ {
+ aValue = _rxSource->getPropertyValue(elem.second);
+ }
+ catch(Exception&)
+ {
+ SAL_WARN("dbaccess", "ODbDataSourceAdministrationHelper::translateProperties: could not extract the property "
+ << elem.second);
+ }
+ // transfer it into an item
+ implTranslateProperty(_rDest, elem.first, aValue);
+ }
+
+ // get the additional information
+ Sequence< PropertyValue > aAdditionalInfo;
+ try
+ {
+ _rxSource->getPropertyValue(PROPERTY_INFO) >>= aAdditionalInfo;
+ }
+ catch(Exception&) { }
+
+ // collect the names of the additional settings
+ PropertyValueSet aInfos;
+ for (const PropertyValue& rAdditionalInfo : std::as_const(aAdditionalInfo))
+ {
+ if( rAdditionalInfo.Name == "JDBCDRV" )
+ { // compatibility
+ PropertyValue aCompatibility(rAdditionalInfo);
+ aCompatibility.Name = "JavaDriverClass";
+ aInfos.insert(aCompatibility);
+ }
+ else
+ aInfos.insert(rAdditionalInfo);
+ }
+
+ // go through all known translations and check if we have such a setting
+ if ( !aInfos.empty() )
+ {
+ PropertyValue aSearchFor;
+ for (auto const& elem : m_aIndirectPropTranslator)
+ {
+ aSearchFor.Name = elem.second;
+ PropertyValueSet::const_iterator aInfoPos = aInfos.find(aSearchFor);
+ if (aInfos.end() != aInfoPos)
+ // the property is contained in the info sequence
+ // -> transfer it into an item
+ implTranslateProperty(_rDest, elem.first, aInfoPos->Value);
+ }
+ }
+
+ convertUrl(_rDest);
+ }
+
+ try
+ {
+ Reference<XStorable> xStore(getDataSourceOrModel(_rxSource),UNO_QUERY);
+ _rDest.Put(SfxBoolItem(DSID_READONLY, !xStore.is() || xStore->isReadonly() ));
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "IsReadOnly throws");
+ }
+}
+
+void ODbDataSourceAdministrationHelper::translateProperties(const SfxItemSet& _rSource, const Reference< XPropertySet >& _rxDest)
+{
+ OSL_ENSURE(_rxDest.is(), "ODbDataSourceAdministrationHelper::translateProperties: invalid property set!");
+ if (!_rxDest.is())
+ return;
+
+ // the property set info
+ Reference< XPropertySetInfo > xInfo;
+ try { xInfo = _rxDest->getPropertySetInfo(); }
+ catch(Exception&) { }
+
+ static const OUStringLiteral sUrlProp(u"URL");
+ // transfer the direct properties
+ for (auto const& elem : m_aDirectPropTranslator)
+ {
+ const SfxPoolItem* pCurrentItem = _rSource.GetItem(static_cast<sal_uInt16>(elem.first));
+ if (pCurrentItem)
+ {
+ sal_Int16 nAttributes = PropertyAttribute::READONLY;
+ if (xInfo.is())
+ {
+ try { nAttributes = xInfo->getPropertyByName(elem.second).Attributes; }
+ catch(Exception&) { }
+ }
+ if ((nAttributes & PropertyAttribute::READONLY) == 0)
+ {
+ if ( sUrlProp == elem.second )
+ {
+ Any aValue(getConnectionURL());
+ // aValue <<= OUString();
+ lcl_putProperty(_rxDest, elem.second,aValue);
+ }
+ else
+ implTranslateProperty(_rxDest, elem.second, pCurrentItem);
+ }
+ }
+ }
+
+ // now for the indirect properties
+
+ Sequence< PropertyValue > aInfo;
+ // the original properties
+ try
+ {
+ _rxDest->getPropertyValue(PROPERTY_INFO) >>= aInfo;
+ }
+ catch(Exception&) { }
+
+ // overwrite and extend them
+ fillDatasourceInfo(_rSource, aInfo);
+ // and propagate the (newly composed) sequence to the set
+ lcl_putProperty(_rxDest,PROPERTY_INFO, Any(aInfo));
+}
+
+void ODbDataSourceAdministrationHelper::fillDatasourceInfo(const SfxItemSet& _rSource, Sequence< css::beans::PropertyValue >& _rInfo)
+{
+ // within the current "Info" sequence, replace the ones we can examine from the item set
+ // (we don't just fill a completely new sequence with our own items, but we preserve any properties unknown to
+ // us)
+
+ // first determine which of all the items are relevant for the data source (depends on the connection url)
+ const OUString eType = getDatasourceType(_rSource);
+ const ::connectivity::DriversConfig aDriverConfig(getORB());
+ const ::comphelper::NamedValueCollection& aProperties = aDriverConfig.getProperties(eType);
+
+ // collect the translated property values for the relevant items
+ PropertyValueSet aRelevantSettings;
+ MapInt2String::const_iterator aTranslation;
+ for (ItemID detailId = DSID_FIRST_ITEM_ID ; detailId <= DSID_LAST_ITEM_ID; ++detailId)
+ {
+ const SfxPoolItem* pCurrent = _rSource.GetItem(static_cast<sal_uInt16>(detailId));
+ aTranslation = m_aIndirectPropTranslator.find(detailId);
+ if ( pCurrent && (m_aIndirectPropTranslator.end() != aTranslation) &&
+ aProperties.has(aTranslation->second) )
+ {
+ if ( aTranslation->second == INFO_CHARSET )
+ {
+ OUString sCharSet;
+ implTranslateProperty(pCurrent) >>= sCharSet;
+ if ( !sCharSet.isEmpty() )
+ aRelevantSettings.insert(PropertyValue(aTranslation->second, 0, Any(sCharSet), PropertyState_DIRECT_VALUE));
+ }
+ else
+ aRelevantSettings.insert(PropertyValue(aTranslation->second, 0, implTranslateProperty(pCurrent), PropertyState_DIRECT_VALUE));
+ }
+ }
+
+ // settings to preserve
+ MapInt2String aPreservedSettings;
+
+ // now aRelevantSettings contains all the property values relevant for the current data source type,
+ // check the original sequence if it already contains any of these values (which have to be overwritten, then)
+ PropertyValue* pInfo = _rInfo.getArray();
+ PropertyValue aSearchFor;
+ sal_Int32 nObsoleteSetting = -1;
+ sal_Int32 nCount = _rInfo.getLength();
+ for (sal_Int32 i = 0; i < nCount; ++i, ++pInfo)
+ {
+ aSearchFor.Name = pInfo->Name;
+ PropertyValueSet::const_iterator aOverwrittenSetting = aRelevantSettings.find(aSearchFor);
+ if (aRelevantSettings.end() != aOverwrittenSetting)
+ { // the setting was present in the original sequence, and it is to be overwritten -> replace it
+ if ( pInfo->Value != aOverwrittenSetting->Value )
+ *pInfo = *aOverwrittenSetting;
+ aRelevantSettings.erase(aOverwrittenSetting);
+ }
+ else if( pInfo->Name == "JDBCDRV" )
+ { // this is a compatibility setting, remove it from the sequence (it's replaced by JavaDriverClass)
+ nObsoleteSetting = i;
+ }
+ else
+ aPreservedSettings[i] = pInfo->Name;
+ }
+ if (-1 != nObsoleteSetting)
+ ::comphelper::removeElementAt(_rInfo, nObsoleteSetting);
+
+ if ( !aPreservedSettings.empty() )
+ { // check if there are settings which
+ // * are known as indirect properties
+ // * but not relevant for the current data source type
+ // These settings have to be removed: If they're not relevant, we have no UI for changing them.
+
+ // for this, we need a string-controlled quick access to m_aIndirectPropTranslator
+ std::set<OUString> aIndirectProps;
+ std::transform(m_aIndirectPropTranslator.begin(),
+ m_aIndirectPropTranslator.end(),
+ std::inserter(aIndirectProps,aIndirectProps.begin()),
+ ::o3tl::select2nd< MapInt2String::value_type >());
+
+ // now check the to-be-preserved props
+ std::vector< sal_Int32 > aRemoveIndexes;
+ sal_Int32 nPositionCorrector = 0;
+ for (auto const& preservedSetting : aPreservedSettings)
+ {
+ if (aIndirectProps.end() != aIndirectProps.find(preservedSetting.second))
+ {
+ aRemoveIndexes.push_back(preservedSetting.first - nPositionCorrector);
+ ++nPositionCorrector;
+ }
+ }
+ // now finally remove all such props
+ for (auto const& removeIndex : aRemoveIndexes)
+ ::comphelper::removeElementAt(_rInfo, removeIndex);
+ }
+
+ Sequence< Any> aTypeSettings;
+ aTypeSettings = aProperties.getOrDefault("TypeInfoSettings",aTypeSettings);
+ // here we have a special entry for types from oracle
+ if ( aTypeSettings.hasElements() )
+ {
+ aRelevantSettings.insert(PropertyValue("TypeInfoSettings", 0, Any(aTypeSettings), PropertyState_DIRECT_VALUE));
+ }
+
+ // check which values are still left ('cause they were not present in the original sequence, but are to be set)
+ if ( aRelevantSettings.empty() )
+ return;
+
+ sal_Int32 nOldLength = _rInfo.getLength();
+ _rInfo.realloc(nOldLength + aRelevantSettings.size());
+ PropertyValue* pAppendValues = _rInfo.getArray() + nOldLength;
+ for (auto const& relevantSetting : aRelevantSettings)
+ {
+ if ( relevantSetting.Name == INFO_CHARSET )
+ {
+ OUString sCharSet;
+ relevantSetting.Value >>= sCharSet;
+ if ( !sCharSet.isEmpty() )
+ *pAppendValues = relevantSetting;
+ }
+ else
+ *pAppendValues = relevantSetting;
+ ++pAppendValues;
+ }
+}
+
+Any ODbDataSourceAdministrationHelper::implTranslateProperty(const SfxPoolItem* _pItem)
+{
+ // translate the SfxPoolItem
+ Any aValue;
+
+ const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( _pItem );
+ const SfxBoolItem* pBoolItem = dynamic_cast<const SfxBoolItem*>( _pItem );
+ const OptionalBoolItem* pOptBoolItem = dynamic_cast<const OptionalBoolItem*>( _pItem );
+ const SfxInt32Item* pInt32Item = dynamic_cast< const SfxInt32Item* >( _pItem );
+ const OStringListItem* pStringListItem = dynamic_cast<const OStringListItem*>( _pItem );
+
+ if ( pStringItem )
+ {
+ aValue <<= pStringItem->GetValue();
+ }
+ else if ( pBoolItem )
+ {
+ aValue <<= pBoolItem->GetValue();
+ }
+ else if ( pOptBoolItem )
+ {
+ if ( !pOptBoolItem->HasValue() )
+ aValue.clear();
+ else
+ aValue <<= pOptBoolItem->GetValue();
+ }
+ else if ( pInt32Item )
+ {
+ aValue <<= pInt32Item->GetValue();
+ }
+ else if ( pStringListItem )
+ {
+ aValue <<= pStringListItem->getList();
+ }
+ else
+ {
+ OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported item type!");
+ return aValue;
+ }
+
+ return aValue;
+}
+
+void ODbDataSourceAdministrationHelper::implTranslateProperty(const Reference< XPropertySet >& _rxSet, const OUString& _rName, const SfxPoolItem* _pItem)
+{
+ Any aValue = implTranslateProperty(_pItem);
+ lcl_putProperty(_rxSet, _rName,aValue);
+}
+
+OString ODbDataSourceAdministrationHelper::translatePropertyId( sal_Int32 _nId )
+{
+ OUString aString;
+
+ MapInt2String::const_iterator aPos = m_aDirectPropTranslator.find( _nId );
+ if ( m_aDirectPropTranslator.end() != aPos )
+ {
+ aString = aPos->second;
+ }
+ else
+ {
+ MapInt2String::const_iterator indirectPos = m_aIndirectPropTranslator.find( _nId );
+ if ( m_aIndirectPropTranslator.end() != indirectPos )
+ aString = indirectPos->second;
+ }
+
+ OString aReturn( aString.getStr(), aString.getLength(), RTL_TEXTENCODING_ASCII_US );
+ return aReturn;
+}
+template<class T> static bool checkItemType(const SfxPoolItem* pItem){ return dynamic_cast<const T*>(pItem) != nullptr;}
+
+void ODbDataSourceAdministrationHelper::implTranslateProperty( SfxItemSet& _rSet, sal_Int32 _nId, const Any& _rValue )
+{
+ switch ( _rValue.getValueType().getTypeClass() )
+ {
+ case TypeClass_STRING:
+ if ( implCheckItemType( _rSet, _nId, checkItemType<SfxStringItem> ) )
+ {
+ OUString sValue;
+ _rValue >>= sValue;
+ _rSet.Put(SfxStringItem(_nId, sValue));
+ }
+ else {
+ SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
+ << translatePropertyId(_nId) << " should be no string)!");
+ }
+ break;
+
+ case TypeClass_BOOLEAN:
+ if ( implCheckItemType( _rSet, _nId, checkItemType<SfxBoolItem> ) )
+ {
+ bool bVal = false;
+ _rValue >>= bVal;
+ _rSet.Put(SfxBoolItem(_nId, bVal));
+ }
+ else if ( implCheckItemType( _rSet, _nId, checkItemType<OptionalBoolItem> ) )
+ {
+ OptionalBoolItem aItem( _nId );
+ if ( _rValue.hasValue() )
+ {
+ bool bValue = false;
+ _rValue >>= bValue;
+ aItem.SetValue( bValue );
+ }
+ else
+ aItem.ClearValue();
+ _rSet.Put( aItem );
+ }
+ else {
+ SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
+ << translatePropertyId(_nId)
+ << " should be no boolean)!");
+ }
+ break;
+
+ case TypeClass_LONG:
+ if ( implCheckItemType( _rSet, _nId, checkItemType<SfxInt32Item> ) )
+ {
+ sal_Int32 nValue = 0;
+ _rValue >>= nValue;
+ _rSet.Put( SfxInt32Item( _nId, nValue ) );
+ }
+ else {
+ SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
+ << translatePropertyId(_nId)
+ << " should be no int)!");
+ }
+ break;
+
+ case TypeClass_SEQUENCE:
+ if ( implCheckItemType( _rSet, _nId, checkItemType<OStringListItem> ) )
+ {
+ // determine the element type
+ TypeDescription aTD(_rValue.getValueType());
+ typelib_IndirectTypeDescription* pSequenceTD =
+ reinterpret_cast< typelib_IndirectTypeDescription* >(aTD.get());
+ OSL_ENSURE(pSequenceTD && pSequenceTD->pType, "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid sequence type!");
+
+ Type aElementType(pSequenceTD->pType);
+ switch (aElementType.getTypeClass())
+ {
+ case TypeClass_STRING:
+ {
+ Sequence< OUString > aStringList;
+ _rValue >>= aStringList;
+ _rSet.Put(OStringListItem(_nId, aStringList));
+ }
+ break;
+ default:
+ OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!");
+ }
+ }
+ else {
+ SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
+ << translatePropertyId(_nId)
+ << " should be no string sequence)!");
+ }
+ break;
+
+ case TypeClass_VOID:
+ _rSet.ClearItem(_nId);
+ break;
+
+ default:
+ OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!");
+ }
+}
+
+OUString ODbDataSourceAdministrationHelper::getDocumentUrl(SfxItemSet const & _rDest)
+{
+ const SfxStringItem* pUrlItem = _rDest.GetItem<SfxStringItem>(DSID_DOCUMENT_URL);
+ OSL_ENSURE(pUrlItem,"Document URL is NULL. -> GPF!");
+ return pUrlItem->GetValue();
+}
+
+void ODbDataSourceAdministrationHelper::convertUrl(SfxItemSet& _rDest)
+{
+ OUString eType = getDatasourceType(_rDest);
+
+ const SfxStringItem* pUrlItem = _rDest.GetItem<SfxStringItem>(DSID_CONNECTURL);
+ const DbuTypeCollectionItem* pTypeCollection = _rDest.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
+
+ OSL_ENSURE(pUrlItem,"Connection URL is NULL. -> GPF!");
+ OSL_ENSURE(pTypeCollection, "ODbAdminDialog::getDatasourceType: invalid items in the source set!");
+ ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection();
+ OSL_ENSURE(pCollection, "ODbAdminDialog::getDatasourceType: invalid type collection!");
+
+ sal_uInt16 nPortNumberId = 0;
+ sal_Int32 nPortNumber = -1;
+ OUString sNewHostName;
+ OUString sUrlPart;
+
+ pCollection->extractHostNamePort(pUrlItem->GetValue(),sUrlPart,sNewHostName,nPortNumber);
+ const ::dbaccess::DATASOURCE_TYPE eTy = pCollection->determineType(eType);
+
+ switch( eTy )
+ {
+ case ::dbaccess::DST_MYSQL_NATIVE:
+ case ::dbaccess::DST_MYSQL_JDBC:
+ nPortNumberId = DSID_MYSQL_PORTNUMBER;
+ break;
+ case ::dbaccess::DST_ORACLE_JDBC:
+ nPortNumberId = DSID_ORACLE_PORTNUMBER;
+ break;
+ case ::dbaccess::DST_LDAP:
+ nPortNumberId = DSID_CONN_LDAP_PORTNUMBER;
+ break;
+ default:
+ break;
+ }
+
+ if ( !sUrlPart.isEmpty() )
+ {
+ if ( eTy == ::dbaccess::DST_MYSQL_NATIVE )
+ {
+ _rDest.Put( SfxStringItem( DSID_DATABASENAME, sUrlPart ) );
+ }
+ else
+ {
+ OUString sNewUrl = pCollection->getPrefix(eType) + sUrlPart;
+ _rDest.Put( SfxStringItem( DSID_CONNECTURL, sNewUrl ) );
+ }
+ }
+
+ if ( !sNewHostName.isEmpty() )
+ _rDest.Put(SfxStringItem(DSID_CONN_HOSTNAME, sNewHostName));
+
+ if ( nPortNumber != -1 && nPortNumberId != 0 )
+ _rDest.Put(SfxInt32Item(nPortNumberId, nPortNumber));
+
+}
+
+bool ODbDataSourceAdministrationHelper::saveChanges(const SfxItemSet& _rSource)
+{
+ // put the remembered settings into the property set
+ Reference<XPropertySet> xDatasource = getCurrentDataSource();
+ if ( !xDatasource.is() )
+ return false;
+
+ translateProperties(_rSource,xDatasource );
+
+ return true;
+}
+
+void ODbDataSourceAdministrationHelper::setDataSourceOrName( const Any& _rDataSourceOrName )
+{
+ OSL_ENSURE( !m_aDataSourceOrName.hasValue(), "ODbDataSourceAdministrationHelper::setDataSourceOrName: already have one!" );
+ // hmm. We could reset m_xDatasource/m_xModel, probably, and continue working
+ m_aDataSourceOrName = _rDataSourceOrName;
+}
+
+// DbuTypeCollectionItem
+DbuTypeCollectionItem::DbuTypeCollectionItem(sal_Int16 _nWhich, ::dbaccess::ODsnTypeCollection* _pCollection)
+ :SfxPoolItem(_nWhich)
+ ,m_pCollection(_pCollection)
+{
+}
+
+DbuTypeCollectionItem::DbuTypeCollectionItem(const DbuTypeCollectionItem& _rSource)
+ :SfxPoolItem(_rSource)
+ ,m_pCollection(_rSource.getCollection())
+{
+}
+
+bool DbuTypeCollectionItem::operator==(const SfxPoolItem& _rItem) const
+{
+ return SfxPoolItem::operator==(_rItem) &&
+ static_cast<const DbuTypeCollectionItem&>( _rItem ).getCollection() == getCollection();
+}
+
+DbuTypeCollectionItem* DbuTypeCollectionItem::Clone(SfxItemPool* /*_pPool*/) const
+{
+ return new DbuTypeCollectionItem(*this);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/DbAdminImpl.hxx b/dbaccess/source/ui/dlg/DbAdminImpl.hxx
new file mode 100644
index 000000000..22a61ecee
--- /dev/null
+++ b/dbaccess/source/ui/dlg/DbAdminImpl.hxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdb/XDatabaseContext.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <dsntypes.hxx>
+#include <svl/itemset.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <svl/poolitem.hxx>
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+ namespace DataSourceInfoConverter
+ {
+ void convert(const css::uno::Reference< css::uno::XComponentContext> & xContext,
+ const ::dbaccess::ODsnTypeCollection* _pCollection,
+ const OUString& _sOldURLPrefix,
+ const OUString& _sNewURLPrefix,
+ const css::uno::Reference< css::beans::XPropertySet >& _xDatasource);
+ };
+ class IItemSetHelper;
+ // ODbDataSourceAdministrationHelper
+ class ODbDataSourceAdministrationHelper final
+ {
+ public:
+ typedef std::map<sal_Int32, OUString> MapInt2String;
+
+ private:
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext; /// service factory
+ css::uno::Reference< css::sdb::XDatabaseContext >
+ m_xDatabaseContext; /// database context we're working in
+ css::uno::Reference< css::beans::XPropertySet > m_xDatasource;
+ css::uno::Reference< css::frame::XModel > m_xModel;
+
+ css::uno::Any m_aDataSourceOrName;
+
+ MapInt2String m_aDirectPropTranslator; /// translating property id's into names (direct properties of a data source)
+ MapInt2String m_aIndirectPropTranslator; /// translating property id's into names (indirect properties of a data source)
+ weld::Window* m_pParent;
+ IItemSetHelper* m_pItemSetHelper;
+ public:
+
+ ODbDataSourceAdministrationHelper(const css::uno::Reference< css::uno::XComponentContext >& _xORB,
+ weld::Window* pParent, weld::Window* pTopParent,
+ IItemSetHelper* _pItemSetHelper);
+
+ /** translate the current dialog SfxItems into driver relevant PropertyValues
+ @see successfullyConnected
+ */
+ bool getCurrentSettings(css::uno::Sequence< css::beans::PropertyValue >& _rDriverParams);
+
+ /** to be called if the settings got from getCurrentSettings have been used for successfully connecting
+ @see getCurrentSettings
+ */
+ void successfullyConnected();
+
+ /// clear the password in the current data source's item set
+ void clearPassword();
+
+ const css::uno::Reference< css::uno::XComponentContext >& getORB() const { return m_xContext; }
+
+ /** creates a new connection. The caller is responsible to dispose it !!!!
+ */
+ std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection();
+
+ /** return the corresponding driver for the selected URL
+ */
+ css::uno::Reference< css::sdbc::XDriver > getDriver();
+ css::uno::Reference< css::sdbc::XDriver > getDriver(const OUString& _sURL);
+
+ /** returns the data source the dialog is currently working with
+ */
+ css::uno::Reference< css::beans::XPropertySet > const & getCurrentDataSource();
+ // returns the Url of a database document
+ static OUString getDocumentUrl(SfxItemSet const & _rDest);
+
+ void setDataSourceOrName( const css::uno::Any& _rDataSourceOrName );
+
+ /** extracts the connection type from the given set<p/>
+ The connection type is determined by the value of the DSN item, analyzed by the TypeCollection item.
+ */
+ static OUString getDatasourceType( const SfxItemSet& _rSet );
+
+ /** returns the connection URL
+ @return
+ The connection URL
+ */
+ OUString getConnectionURL() const;
+
+ /// fill the necessary information from the url line
+ static void convertUrl(SfxItemSet& _rDest);
+
+ const MapInt2String& getIndirectProperties() const { return m_aIndirectPropTranslator; }
+
+ /** translates properties of a UNO data source into SfxItems
+ @param _rxSource
+ The data source
+ @param _rDest
+ The item set to fill.
+ */
+ void translateProperties(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxSource,
+ SfxItemSet& _rDest);
+
+ /** translate SfxItems into properties of a UNO data source
+ @param _rSource
+ The item set to read from.
+ @param _rxDest
+ The data source to fill.
+ */
+ void translateProperties(
+ const SfxItemSet& _rSource,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxDest);
+
+ bool saveChanges(const SfxItemSet& _rSource);
+ private:
+ /** fill a data source info array with the settings from a given item set
+ */
+ void fillDatasourceInfo(const SfxItemSet& _rSource, css::uno::Sequence< css::beans::PropertyValue >& _rInfo);
+
+ /// translate the given value into an SfxPoolItem, put this into the given set under the given id
+ void implTranslateProperty(SfxItemSet& _rSet, sal_Int32 _nId, const css::uno::Any& _rValue);
+
+ /// translate the given SfxPoolItem into an <type scope="com.sun.star.Any">uno</type>
+ static css::uno::Any implTranslateProperty(const SfxPoolItem* _pItem);
+
+ /// translate the given SfxPoolItem into an <type scope="com.sun.star.Any">uno</type>, set it (under the given name) on the given property set
+ static void implTranslateProperty(const css::uno::Reference< css::beans::XPropertySet >& _rxSet, const OUString& _rName, const SfxPoolItem* _pItem);
+
+ /** check if the data source described by the given set needs authentication<p/>
+ The return value depends on the data source type only.
+ */
+ static bool hasAuthentication(const SfxItemSet& _rSet);
+
+ OString translatePropertyId( sal_Int32 _nId );
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/DriverSettings.hxx b/dbaccess/source/ui/dlg/DriverSettings.hxx
new file mode 100644
index 000000000..72ce3d459
--- /dev/null
+++ b/dbaccess/source/ui/dlg/DriverSettings.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+class SfxTabPage;
+namespace dbaui
+{
+ /// a collection class for all details a driver needs
+ class ODriversSettings
+ {
+ public:
+
+ /** Creates the detail page for ado
+ */
+ static std::unique_ptr<SfxTabPage> CreateDbase( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for ado
+ */
+ static std::unique_ptr<SfxTabPage> CreateAdo( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for ODBC
+ */
+ static std::unique_ptr<SfxTabPage> CreateODBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for user
+ */
+ static std::unique_ptr<SfxTabPage> CreateUser( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for MySQLODBC
+ */
+ static std::unique_ptr<SfxTabPage> CreateMySQLODBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for MySQLJDBC
+ */
+ static std::unique_ptr<SfxTabPage> CreateMySQLJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for MySQLNATIVE
+ */
+ static std::unique_ptr<SfxTabPage> CreateMySQLNATIVE( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for Oracle JDBC
+ */
+ static std::unique_ptr<SfxTabPage> CreateOracleJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /** Creates the detail page for LDAP
+ */
+ static std::unique_ptr<SfxTabPage> CreateLDAP( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /// Creates the detail page for Text
+ static std::unique_ptr<SfxTabPage> CreateText( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /// creates the GeneratedValues page
+ static std::unique_ptr<SfxTabPage> CreateGeneratedValuesPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+
+ /// creates the "Special Settings" page of the "Advanced Settings" dialog
+ static std::unique_ptr<SfxTabPage> CreateSpecialSettingsPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx b/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx
new file mode 100644
index 000000000..df0d38e4b
--- /dev/null
+++ b/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <QueryPropertiesDialog.hxx>
+#include <strings.hrc>
+#include <core_resource.hxx>
+
+namespace dbaui
+{
+
+QueryPropertiesDialog::QueryPropertiesDialog(
+ weld::Window* pParent, const bool bDistinct, const sal_Int64 nLimit )
+ : GenericDialogController(pParent, "dbaccess/ui/querypropertiesdialog.ui", "QueryPropertiesDialog")
+ , m_xRB_Distinct(m_xBuilder->weld_radio_button("distinct"))
+ , m_xRB_NonDistinct(m_xBuilder->weld_radio_button("nondistinct"))
+ , m_xLB_Limit(m_xBuilder->weld_combo_box("limitbox"))
+{
+ m_xRB_Distinct->set_active(bDistinct);
+ m_xRB_NonDistinct->set_active(!bDistinct);
+
+ m_xLB_Limit->append(OUString::number(-1), DBA_RES(STR_QUERY_LIMIT_ALL)); // ALL_INT and ALL_STRING
+ /// Default values
+ sal_Int64 const aDefLimitAry[] =
+ {
+ 5,
+ 10,
+ 20,
+ 50
+ };
+ for (auto a : aDefLimitAry)
+ m_xLB_Limit->append(OUString::number(a), OUString::number(a));
+ OUString sInitial = OUString::number(nLimit);
+ auto nPos = m_xLB_Limit->find_id(sInitial);
+ if (nPos != -1)
+ m_xLB_Limit->set_active(nPos);
+ else
+ m_xLB_Limit->set_entry_text(OUString::number(nLimit));
+}
+
+sal_Int64 QueryPropertiesDialog::getLimit() const
+{
+ OUString sSelectedId = m_xLB_Limit->get_active_id();
+ if (!sSelectedId.isEmpty())
+ return sSelectedId.toInt64();
+ return m_xLB_Limit->get_active_text().toInt64();
+}
+
+QueryPropertiesDialog::~QueryPropertiesDialog()
+{
+}
+
+} ///dbaui namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/RelationDlg.cxx b/dbaccess/source/ui/dlg/RelationDlg.cxx
new file mode 100644
index 000000000..cc449d9b7
--- /dev/null
+++ b/dbaccess/source/ui/dlg/RelationDlg.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <RelationDlg.hxx>
+
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <JoinDesignView.hxx>
+#include <JoinController.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <RTableConnectionData.hxx>
+#include <RelationControl.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::dbaui;
+using namespace ::dbtools;
+
+ORelationDialog::ORelationDialog( OJoinTableView* pParent,
+ const TTableConnectionData::value_type& pConnectionData,
+ bool bAllowTableSelect )
+ : GenericDialogController(pParent->GetFrameWeld(),
+ "dbaccess/ui/relationdialog.ui", "RelationDialog")
+ , m_pParent(pParent)
+ , m_pOrigConnData(pConnectionData)
+ , m_bTriedOneUpdate(false)
+ , m_xRB_NoCascUpd(m_xBuilder->weld_radio_button("addaction"))
+ , m_xRB_CascUpd(m_xBuilder->weld_radio_button("addcascade"))
+ , m_xRB_CascUpdNull(m_xBuilder->weld_radio_button("addnull"))
+ , m_xRB_CascUpdDefault(m_xBuilder->weld_radio_button("adddefault"))
+ , m_xRB_NoCascDel(m_xBuilder->weld_radio_button("delaction"))
+ , m_xRB_CascDel(m_xBuilder->weld_radio_button("delcascade"))
+ , m_xRB_CascDelNull(m_xBuilder->weld_radio_button("delnull"))
+ , m_xRB_CascDelDefault(m_xBuilder->weld_radio_button("deldefault"))
+ , m_xPB_OK(m_xBuilder->weld_button("ok"))
+{
+ // Copy connection
+ m_pConnData = pConnectionData->NewInstance();
+ m_pConnData->CopyFrom( *pConnectionData );
+
+ Init(m_pConnData);
+ m_xTableControl.reset(new OTableListBoxControl(m_xBuilder.get(), &pParent->GetTabWinMap(), this));
+
+ m_xPB_OK->connect_clicked(LINK(this, ORelationDialog, OKClickHdl));
+
+ m_xTableControl->Init( m_pConnData );
+ if ( bAllowTableSelect )
+ m_xTableControl->fillListBoxes();
+ else
+ m_xTableControl->fillAndDisable(pConnectionData);
+
+ m_xTableControl->lateInit();
+
+ m_xTableControl->NotifyCellChange();
+}
+
+ORelationDialog::~ORelationDialog()
+{
+}
+
+void ORelationDialog::Init(const TTableConnectionData::value_type& _pConnectionData)
+{
+ ORelationTableConnectionData* pConnData = static_cast<ORelationTableConnectionData*>(_pConnectionData.get());
+ // Update Rules
+ switch (pConnData->GetUpdateRules())
+ {
+ case KeyRule::NO_ACTION:
+ case KeyRule::RESTRICT:
+ m_xRB_NoCascUpd->set_active(true);
+ break;
+
+ case KeyRule::CASCADE:
+ m_xRB_CascUpd->set_active(true);
+ break;
+
+ case KeyRule::SET_NULL:
+ m_xRB_CascUpdNull->set_active(true);
+ break;
+ case KeyRule::SET_DEFAULT:
+ m_xRB_CascUpdDefault->set_active(true);
+ break;
+ }
+
+ // Delete Rules
+ switch (pConnData->GetDeleteRules())
+ {
+ case KeyRule::NO_ACTION:
+ case KeyRule::RESTRICT:
+ m_xRB_NoCascDel->set_active(true);
+ break;
+
+ case KeyRule::CASCADE:
+ m_xRB_CascDel->set_active(true);
+ break;
+
+ case KeyRule::SET_NULL:
+ m_xRB_CascDelNull->set_active(true);
+ break;
+ case KeyRule::SET_DEFAULT:
+ m_xRB_CascDelDefault->set_active(true);
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(ORelationDialog, OKClickHdl, weld::Button&, void)
+{
+ // Read out RadioButtons
+ sal_uInt16 nAttrib = 0;
+
+ // Delete Rules
+ if( m_xRB_NoCascDel->get_active() )
+ nAttrib |= KeyRule::NO_ACTION;
+ if( m_xRB_CascDel->get_active() )
+ nAttrib |= KeyRule::CASCADE;
+ if( m_xRB_CascDelNull->get_active() )
+ nAttrib |= KeyRule::SET_NULL;
+ if( m_xRB_CascDelDefault->get_active() )
+ nAttrib |= KeyRule::SET_DEFAULT;
+
+ ORelationTableConnectionData* pConnData = static_cast<ORelationTableConnectionData*>(m_pConnData.get());
+ pConnData->SetDeleteRules( nAttrib );
+
+ // Update Rules
+ nAttrib = 0;
+ if( m_xRB_NoCascUpd->get_active() )
+ nAttrib |= KeyRule::NO_ACTION;
+ if( m_xRB_CascUpd->get_active() )
+ nAttrib |= KeyRule::CASCADE;
+ if( m_xRB_CascUpdNull->get_active() )
+ nAttrib |= KeyRule::SET_NULL;
+ if( m_xRB_CascUpdDefault->get_active() )
+ nAttrib |= KeyRule::SET_DEFAULT;
+ pConnData->SetUpdateRules( nAttrib );
+
+ m_xTableControl->SaveModified();
+
+ //// if the ComboBoxes for the table selection are enabled (constructor with bAllowTableSelect==sal_True),
+ //// then I must also put the table names into the connection
+ //m_pConnData->SetSourceWinName(m_xTableControl->getSourceWinName());
+ //m_pConnData->SetDestWinName(m_xTableControl->getDestWinName());
+
+ // try to create the relation
+ try
+ {
+ ORelationTableConnectionData* pOrigConnData = static_cast<ORelationTableConnectionData*>(m_pOrigConnData.get());
+ if ( *pConnData == *pOrigConnData || pConnData->Update())
+ {
+ m_pOrigConnData->CopyFrom( *m_pConnData );
+ m_xDialog->response(RET_OK);
+ return;
+ }
+ }
+ catch( const SQLException& )
+ {
+ ::dbtools::showError(SQLExceptionInfo(::cppu::getCaughtException()),
+ m_xDialog->GetXWindow(),
+ m_pParent->getDesignView()->getController().getORB());
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_bTriedOneUpdate = true;
+ // this means that the original connection may be lost (if m_pConnData was not a newly created but an
+ // existent conn to be modified), which we reflect by returning RET_NO (see ::Execute)
+
+ // try again
+ Init(m_pConnData);
+ m_xTableControl->Init( m_pConnData );
+ m_xTableControl->lateInit();
+}
+
+short ORelationDialog::run()
+{
+ short nResult = GenericDialogController::run();
+ if ((nResult != RET_OK) && m_bTriedOneUpdate)
+ return RET_NO;
+
+ return nResult;
+}
+
+void ORelationDialog::setValid(bool _bValid)
+{
+ m_xPB_OK->set_sensitive(_bValid);
+}
+
+void ORelationDialog::notifyConnectionChange()
+{
+ Init(m_pConnData);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/TablesSingleDlg.cxx b/dbaccess/source/ui/dlg/TablesSingleDlg.cxx
new file mode 100644
index 000000000..bcf039c5e
--- /dev/null
+++ b/dbaccess/source/ui/dlg/TablesSingleDlg.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TablesSingleDlg.hxx>
+#include "DbAdminImpl.hxx"
+#include "tablespage.hxx"
+
+namespace dbaui
+{
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+ // OTableSubscriptionDialog
+OTableSubscriptionDialog::OTableSubscriptionDialog(weld::Window* pParent
+ ,const SfxItemSet* _pItems
+ ,const Reference< XComponentContext >& _rxORB
+ ,const css::uno::Any& _aDataSourceName)
+ : SfxSingleTabDialogController(pParent, _pItems,
+ "dbaccess/ui/tablesfilterdialog.ui", "TablesFilterDialog")
+ , m_pImpl(new ODbDataSourceAdministrationHelper(_rxORB, m_xDialog.get(), pParent, this))
+ , m_bStopExecution(false)
+{
+ m_pImpl->setDataSourceOrName(_aDataSourceName);
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ m_pOutSet.reset(new SfxItemSet( *_pItems ));
+
+ m_pImpl->translateProperties(xDatasource, *m_pOutSet);
+ SetInputSet(m_pOutSet.get());
+
+ auto xTabPage = std::make_unique<OTableSubscriptionPage>(get_content_area(), this, *m_pOutSet);
+ xTabPage->SetServiceFactory(_rxORB);
+ SetTabPage(std::move(xTabPage));
+}
+
+OTableSubscriptionDialog::~OTableSubscriptionDialog()
+{
+}
+
+short OTableSubscriptionDialog::run()
+{
+ short nRet = RET_CANCEL;
+ if ( !m_bStopExecution )
+ {
+ nRet = SfxSingleTabDialogController::run();
+ if ( nRet == RET_OK )
+ {
+ m_pOutSet->Put(*GetOutputItemSet());
+ m_pImpl->saveChanges(*m_pOutSet);
+ }
+ }
+ return nRet;
+}
+
+bool OTableSubscriptionDialog::getCurrentSettings(Sequence< PropertyValue >& _rDriverParams)
+{
+ return m_pImpl->getCurrentSettings(_rDriverParams);
+}
+
+void OTableSubscriptionDialog::successfullyConnected()
+{
+ m_pImpl->successfullyConnected();
+}
+
+void OTableSubscriptionDialog::clearPassword()
+{
+ m_pImpl->clearPassword();
+}
+
+Reference< XPropertySet > const & OTableSubscriptionDialog::getCurrentDataSource()
+{
+ return m_pImpl->getCurrentDataSource();
+}
+
+const SfxItemSet* OTableSubscriptionDialog::getOutputSet() const
+{
+ return m_pOutSet.get();
+}
+
+SfxItemSet* OTableSubscriptionDialog::getWriteOutputSet()
+{
+ return m_pOutSet.get();
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/TextConnectionHelper.cxx b/dbaccess/source/ui/dlg/TextConnectionHelper.cxx
new file mode 100644
index 000000000..15fa887f7
--- /dev/null
+++ b/dbaccess/source/ui/dlg/TextConnectionHelper.cxx
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include "TextConnectionHelper.hxx"
+#include <strings.hrc>
+#include <strings.hxx>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <dsitems.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/mnemonic.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace
+{
+
+OUString lcl_getListEntry(const OUString& rStr, sal_Int32& rIdx)
+{
+ const OUString sTkn {rStr.getToken( 0, '\t', rIdx )};
+ if (rIdx>=0)
+ {
+ rIdx = rStr.indexOf('\t', rIdx);
+ if (rIdx>=0 && ++rIdx>=rStr.getLength())
+ rIdx = -1;
+ }
+ return sTkn;
+}
+
+}
+
+namespace dbaui
+{
+
+ OTextConnectionHelper::OTextConnectionHelper(weld::Widget* pParent, const short _nAvailableSections)
+ : m_aFieldSeparatorList (DBA_RES(STR_AUTOFIELDSEPARATORLIST))
+ , m_aTextSeparatorList (STR_AUTOTEXTSEPARATORLIST)
+ , m_aTextNone (DBA_RES(STR_AUTOTEXT_FIELD_SEP_NONE))
+ , m_nAvailableSections( _nAvailableSections )
+ , m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/textpage.ui"))
+ , m_xContainer(m_xBuilder->weld_widget("TextPage"))
+ , m_xExtensionHeader(m_xBuilder->weld_widget("extensionframe"))
+ , m_xAccessTextFiles(m_xBuilder->weld_radio_button("textfile"))
+ , m_xAccessCSVFiles(m_xBuilder->weld_radio_button("csvfile"))
+ , m_xAccessOtherFiles(m_xBuilder->weld_radio_button("custom"))
+ , m_xOwnExtension(m_xBuilder->weld_entry("extension"))
+ , m_xExtensionExample(m_xBuilder->weld_label("example"))
+ , m_xFormatHeader(m_xBuilder->weld_widget("formatframe"))
+ , m_xFieldSeparatorLabel(m_xBuilder->weld_label("fieldlabel"))
+ , m_xFieldSeparator(m_xBuilder->weld_combo_box("fieldseparator"))
+ , m_xTextSeparatorLabel(m_xBuilder->weld_label("textlabel"))
+ , m_xTextSeparator(m_xBuilder->weld_combo_box("textseparator"))
+ , m_xDecimalSeparatorLabel(m_xBuilder->weld_label("decimallabel"))
+ , m_xDecimalSeparator(m_xBuilder->weld_combo_box("decimalseparator"))
+ , m_xThousandsSeparatorLabel(m_xBuilder->weld_label("thousandslabel"))
+ , m_xThousandsSeparator(m_xBuilder->weld_combo_box("thousandsseparator"))
+ , m_xRowHeader(m_xBuilder->weld_check_button("containsheaders"))
+ , m_xCharSetHeader(m_xBuilder->weld_widget("charsetframe"))
+ , m_xCharSetLabel(m_xBuilder->weld_label("charsetlabel"))
+ , m_xCharSet(new CharSetListBox(m_xBuilder->weld_combo_box("charset")))
+ {
+ for(sal_Int32 nIdx {0}; nIdx>=0;)
+ m_xFieldSeparator->append_text( lcl_getListEntry(m_aFieldSeparatorList, nIdx) );
+
+ for(sal_Int32 nIdx {0}; nIdx>=0;)
+ m_xTextSeparator->append_text( lcl_getListEntry(m_aTextSeparatorList, nIdx) );
+ m_xTextSeparator->append_text(m_aTextNone);
+
+ m_xOwnExtension->connect_changed(LINK(this, OTextConnectionHelper, OnEditModified));
+ m_xAccessTextFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl));
+ m_xAccessCSVFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl));
+ m_xAccessOtherFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl));
+ m_xAccessCSVFiles->set_active(true);
+
+ struct SectionDescriptor
+ {
+ short nFlag;
+ weld::Widget* pFrame;
+ } aSections[] = {
+ { TC_EXTENSION, m_xExtensionHeader.get() },
+ { TC_SEPARATORS, m_xFormatHeader.get() },
+ { TC_HEADER, m_xRowHeader.get() },
+ { TC_CHARSET, m_xCharSetHeader.get() },
+ { 0, nullptr }
+ };
+
+ for ( size_t section=0; section < SAL_N_ELEMENTS( aSections ) - 1; ++section )
+ {
+ if ( ( m_nAvailableSections & aSections[section].nFlag ) != 0 )
+ {
+ // the section is visible, no need to do anything here
+ continue;
+ }
+
+ // hide all elements from this section
+ aSections[section].pFrame->hide();
+ }
+
+ m_xContainer->show();
+ }
+
+ IMPL_LINK_NOARG(OTextConnectionHelper, OnEditModified, weld::Entry&, void)
+ {
+ m_aGetExtensionHandler.Call(this);
+ }
+
+ IMPL_LINK_NOARG(OTextConnectionHelper, OnSetExtensionHdl, weld::Toggleable&, void)
+ {
+ bool bDoEnable = m_xAccessOtherFiles->get_active();
+ m_xOwnExtension->set_sensitive(bDoEnable);
+ m_xExtensionExample->set_sensitive(bDoEnable);
+ m_aGetExtensionHandler.Call(this);
+ }
+
+ void OTextConnectionHelper::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xFieldSeparator.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xTextSeparator.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xDecimalSeparator.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xThousandsSeparator.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xRowHeader.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xCharSet->get_widget()));
+ }
+
+ void OTextConnectionHelper::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFieldSeparatorLabel.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xTextSeparatorLabel.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xDecimalSeparatorLabel.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xThousandsSeparatorLabel.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Widget>(m_xCharSetHeader.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xCharSetLabel.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::ComboBox>(m_xCharSet->get_widget()));
+ }
+
+ void OTextConnectionHelper::implInitControls(const SfxItemSet& _rSet, bool _bValid)
+ {
+ if ( !_bValid )
+ return;
+
+ const SfxStringItem* pDelItem = _rSet.GetItem<SfxStringItem>(DSID_FIELDDELIMITER);
+ const SfxStringItem* pStrItem = _rSet.GetItem<SfxStringItem>(DSID_TEXTDELIMITER);
+ const SfxStringItem* pDecdelItem = _rSet.GetItem<SfxStringItem>(DSID_DECIMALDELIMITER);
+ const SfxStringItem* pThodelItem = _rSet.GetItem<SfxStringItem>(DSID_THOUSANDSDELIMITER);
+ const SfxStringItem* pExtensionItem = _rSet.GetItem<SfxStringItem>(DSID_TEXTFILEEXTENSION);
+ const SfxStringItem* pCharsetItem = _rSet.GetItem<SfxStringItem>(DSID_CHARSET);
+
+ if ( ( m_nAvailableSections & TC_EXTENSION ) != 0 )
+ {
+ m_aOldExtension = pExtensionItem->GetValue();
+ SetExtension( m_aOldExtension );
+ }
+
+ if ( ( m_nAvailableSections & TC_HEADER ) != 0 )
+ {
+ const SfxBoolItem* pHdrItem = _rSet.GetItem<SfxBoolItem>(DSID_TEXTFILEHEADER);
+ m_xRowHeader->set_active(pHdrItem->GetValue());
+ }
+
+ if ( ( m_nAvailableSections & TC_SEPARATORS ) != 0 )
+ {
+ SetSeparator(*m_xFieldSeparator, m_aFieldSeparatorList, pDelItem->GetValue());
+ SetSeparator(*m_xTextSeparator, m_aTextSeparatorList, pStrItem->GetValue());
+ m_xDecimalSeparator->set_entry_text( pDecdelItem->GetValue() );
+ m_xThousandsSeparator->set_entry_text( pThodelItem->GetValue() );
+ }
+
+ if ( ( m_nAvailableSections & TC_CHARSET ) != 0 )
+ {
+ m_xCharSet->SelectEntryByIanaName( pCharsetItem->GetValue() );
+ }
+ }
+
+ bool OTextConnectionHelper::prepareLeave()
+ {
+ OUString sExtension = GetExtension();
+ OUString aErrorText;
+ weld::Widget* pErrorWin = nullptr;
+ OUString aDelText(m_xFieldSeparator->get_active_text());
+ if(aDelText.isEmpty())
+ { // No FieldSeparator
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MISSING);
+ aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label());
+ pErrorWin = m_xFieldSeparator.get();
+ }
+ else if (m_xDecimalSeparator->get_active_text().isEmpty())
+ { // No DecimalSeparator
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MISSING);
+ aErrorText = aErrorText.replaceFirst("#1",m_xDecimalSeparatorLabel->get_label());
+ pErrorWin = m_xDecimalSeparator.get();
+ }
+ else if (m_xTextSeparator->get_active_text() == m_xFieldSeparator->get_active_text())
+ { // Field and TextSeparator must not be the same
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
+ aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label());
+ aErrorText = aErrorText.replaceFirst("#2",m_xFieldSeparatorLabel->get_label());
+ pErrorWin = m_xTextSeparator.get();
+ }
+ else if (m_xDecimalSeparator->get_active_text() == m_xThousandsSeparator->get_active_text())
+ { // Thousands and DecimalSeparator must not be the same
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
+ aErrorText = aErrorText.replaceFirst("#1",m_xDecimalSeparatorLabel->get_label());
+ aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label());
+ pErrorWin = m_xDecimalSeparator.get();
+ }
+ else if (m_xFieldSeparator->get_active_text() == m_xThousandsSeparator->get_active_text())
+ { // Thousands and FieldSeparator must not be the same
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
+ aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label());
+ aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label());
+ pErrorWin = m_xFieldSeparator.get();
+ }
+ else if (m_xFieldSeparator->get_active_text() == m_xDecimalSeparator->get_active_text())
+ { // Tenner and FieldSeparator must not be the same
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
+ aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label());
+ aErrorText = aErrorText.replaceFirst("#2",m_xDecimalSeparatorLabel->get_label());
+ pErrorWin = m_xFieldSeparator.get();
+ }
+ else if (m_xTextSeparator->get_active_text() == m_xThousandsSeparator->get_active_text())
+ { // Thousands and TextSeparator must not be the same
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
+ aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label());
+ aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label());
+ pErrorWin = m_xTextSeparator.get();
+ }
+ else if (m_xTextSeparator->get_active_text() == m_xDecimalSeparator->get_active_text())
+ { // Tenner and TextSeparator must not be the same
+ aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
+ aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label());
+ aErrorText = aErrorText.replaceFirst("#2",m_xDecimalSeparatorLabel->get_label());
+ pErrorWin = m_xTextSeparator.get();
+ }
+ else if ((sExtension.indexOf('*') != -1) || (sExtension.indexOf('?') != -1))
+ {
+ aErrorText = DBA_RES(STR_AUTONO_WILDCARDS);
+ aErrorText = aErrorText.replaceFirst("#1",sExtension);
+ pErrorWin = m_xOwnExtension.get();
+ }
+ else
+ return true;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ MnemonicGenerator::EraseAllMnemonicChars(aErrorText)));
+ xBox->run();
+ pErrorWin->grab_focus();
+ return false;
+ }
+
+ bool OTextConnectionHelper::FillItemSet( SfxItemSet& rSet, const bool _bChangedSomething )
+ {
+ bool bChangedSomething = _bChangedSomething;
+
+ if ( ( m_nAvailableSections & TC_EXTENSION ) != 0 )
+ {
+ OUString sExtension = GetExtension();
+ if( m_aOldExtension != sExtension )
+ {
+ rSet.Put( SfxStringItem( DSID_TEXTFILEEXTENSION, sExtension ) );
+ bChangedSomething = true;
+ }
+ }
+
+ if ( ( m_nAvailableSections & TC_HEADER ) != 0 )
+ {
+ if (m_xRowHeader->get_state_changed_from_saved())
+ {
+ rSet.Put(SfxBoolItem(DSID_TEXTFILEHEADER, m_xRowHeader->get_active()));
+ bChangedSomething = true;
+ }
+ }
+
+ if ( ( m_nAvailableSections & TC_SEPARATORS ) != 0 )
+ {
+ if (m_xFieldSeparator->get_value_changed_from_saved())
+ {
+ rSet.Put( SfxStringItem(DSID_FIELDDELIMITER, GetSeparator( *m_xFieldSeparator, m_aFieldSeparatorList) ) );
+ bChangedSomething = true;
+ }
+ if (m_xTextSeparator->get_value_changed_from_saved())
+ {
+ rSet.Put( SfxStringItem(DSID_TEXTDELIMITER, GetSeparator( *m_xTextSeparator, m_aTextSeparatorList) ) );
+ bChangedSomething = true;
+ }
+
+ if (m_xDecimalSeparator->get_value_changed_from_saved())
+ {
+ rSet.Put( SfxStringItem(DSID_DECIMALDELIMITER, m_xDecimalSeparator->get_active_text().copy(0, 1) ) );
+ bChangedSomething = true;
+ }
+ if (m_xThousandsSeparator->get_value_changed_from_saved())
+ {
+ rSet.Put( SfxStringItem(DSID_THOUSANDSDELIMITER, m_xThousandsSeparator->get_active_text().copy(0,1) ) );
+ bChangedSomething = true;
+ }
+ }
+
+ if ( ( m_nAvailableSections & TC_CHARSET ) != 0 )
+ {
+ if ( m_xCharSet->StoreSelectedCharSet( rSet, DSID_CHARSET ) )
+ bChangedSomething = true;
+ }
+
+ return bChangedSomething;
+ }
+
+ void OTextConnectionHelper::SetExtension(const OUString& _rVal)
+ {
+ if (_rVal == "txt")
+ m_xAccessTextFiles->set_active(true);
+ else if (_rVal == "csv")
+ m_xAccessCSVFiles->set_active(true);
+ else
+ {
+ m_xAccessOtherFiles->set_active(true);
+ m_xExtensionExample->set_label(_rVal);
+ }
+ }
+
+ OUString OTextConnectionHelper::GetExtension() const
+ {
+ OUString sExtension;
+ if (m_xAccessTextFiles->get_active())
+ sExtension = "txt";
+ else if (m_xAccessCSVFiles->get_active())
+ sExtension = "csv";
+ else
+ {
+ sExtension = m_xOwnExtension->get_text();
+ if ( sExtension.startsWith("*.") )
+ sExtension = sExtension.copy(2);
+ }
+ return sExtension;
+ }
+
+ OUString OTextConnectionHelper::GetSeparator(const weld::ComboBox& rBox, std::u16string_view rList)
+ {
+ sal_Unicode const nTok = '\t';
+ int nPos(rBox.find_text(rBox.get_active_text()));
+
+ if (nPos == -1)
+ return rBox.get_active_text();
+
+ if ( m_xTextSeparator.get() != &rBox || nPos != (rBox.get_count()-1) )
+ return OUString(
+ static_cast< sal_Unicode >( o3tl::toInt32(o3tl::getToken(rList, (nPos*2)+1, nTok )) ));
+ // somewhat strange ... translates for instance an "32" into " "
+ return OUString();
+ }
+
+ void OTextConnectionHelper::SetSeparator( weld::ComboBox& rBox, std::u16string_view rList, const OUString& rVal )
+ {
+ if (rVal.getLength()==1)
+ {
+ const sal_Unicode nVal {rVal[0]};
+ for(sal_Int32 nIdx {0}; nIdx>=0;)
+ {
+ sal_Int32 nPrevIdx {nIdx};
+ if (static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(rList, 1, '\t', nIdx))) == nVal)
+ {
+ rBox.set_entry_text(OUString(o3tl::getToken(rList,0, '\t', nPrevIdx)));
+ return;
+ }
+ }
+ rBox.set_entry_text( rVal );
+ }
+ else if ( m_xTextSeparator.get() == &rBox && rVal.isEmpty() )
+ rBox.set_entry_text(m_aTextNone);
+ else
+ rBox.set_entry_text(rVal.copy(0, 1));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/TextConnectionHelper.hxx b/dbaccess/source/ui/dlg/TextConnectionHelper.hxx
new file mode 100644
index 000000000..6755a4223
--- /dev/null
+++ b/dbaccess/source/ui/dlg/TextConnectionHelper.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "adminpages.hxx"
+#include <charsetlistbox.hxx>
+#include <rtl/ustring.hxx>
+
+namespace dbaui
+
+{
+
+ #define TC_EXTENSION (short(0x01)) // a section specifying the extension of the files to connect to
+ #define TC_SEPARATORS (short(0x02)) // a section specifying the various separators
+ #define TC_HEADER (short(0x04)) // a section containing the "Text contains header" check box only
+ #define TC_CHARSET (short(0x08)) // not yet implemented
+
+ class OTextConnectionHelper final
+ {
+ public:
+ OTextConnectionHelper(weld::Widget* pParent , const short _nAvailableSections);
+
+ private:
+ OUString m_aFieldSeparatorList;
+ OUString m_aTextSeparatorList;
+ OUString m_aTextNone;
+ OUString m_aOldExtension;
+ Link<OTextConnectionHelper*, void> m_aGetExtensionHandler; /// to be called if a new type is selected
+
+ short m_nAvailableSections;
+
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Widget> m_xContainer;
+ std::unique_ptr<weld::Widget> m_xExtensionHeader;
+ std::unique_ptr<weld::RadioButton> m_xAccessTextFiles;
+ std::unique_ptr<weld::RadioButton> m_xAccessCSVFiles;
+ std::unique_ptr<weld::RadioButton> m_xAccessOtherFiles;
+ std::unique_ptr<weld::Entry> m_xOwnExtension;
+ std::unique_ptr<weld::Label> m_xExtensionExample;
+ std::unique_ptr<weld::Widget> m_xFormatHeader;
+ std::unique_ptr<weld::Label> m_xFieldSeparatorLabel;
+ std::unique_ptr<weld::ComboBox> m_xFieldSeparator;
+ std::unique_ptr<weld::Label> m_xTextSeparatorLabel;
+ std::unique_ptr<weld::ComboBox> m_xTextSeparator;
+ std::unique_ptr<weld::Label> m_xDecimalSeparatorLabel;
+ std::unique_ptr<weld::ComboBox> m_xDecimalSeparator;
+ std::unique_ptr<weld::Label> m_xThousandsSeparatorLabel;
+ std::unique_ptr<weld::ComboBox> m_xThousandsSeparator;
+ std::unique_ptr<weld::CheckButton> m_xRowHeader;
+ std::unique_ptr<weld::Widget> m_xCharSetHeader;
+ std::unique_ptr<weld::Label> m_xCharSetLabel;
+ std::unique_ptr<CharSetListBox> m_xCharSet;
+
+ DECL_LINK(OnSetExtensionHdl, weld::Toggleable&, void);
+ DECL_LINK(OnEditModified, weld::Entry&, void);
+
+ OUString GetSeparator(const weld::ComboBox& rBox, std::u16string_view rList);
+ void SetSeparator(weld::ComboBox& rBox, std::u16string_view rList, const OUString& rVal);
+ void SetExtension(const OUString& _rVal);
+
+ public:
+ void implInitControls(const SfxItemSet& _rSet, bool _bValid);
+ void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList);
+ void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList);
+ void SetClickHandler(const Link<OTextConnectionHelper*, void>& _rHandler) { m_aGetExtensionHandler = _rHandler; }
+ OUString GetExtension() const;
+ bool FillItemSet( SfxItemSet& rSet, const bool bChangedSomething );
+ bool prepareLeave();
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/UserAdmin.cxx b/dbaccess/source/ui/dlg/UserAdmin.cxx
new file mode 100644
index 000000000..b601c4939
--- /dev/null
+++ b/dbaccess/source/ui/dlg/UserAdmin.cxx
@@ -0,0 +1,316 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "UserAdmin.hxx"
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbcx/XUser.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <IItemSetHelper.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/passwd.hxx>
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::task;
+using namespace dbaui;
+using namespace comphelper;
+
+namespace {
+
+class OPasswordDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Frame> m_xUser;
+ std::unique_ptr<weld::Entry> m_xEDOldPassword;
+ std::unique_ptr<weld::Entry> m_xEDPassword;
+ std::unique_ptr<weld::Entry> m_xEDPasswordRepeat;
+ std::unique_ptr<weld::Button> m_xOKBtn;
+
+ DECL_LINK(OKHdl_Impl, weld::Button&, void);
+ DECL_LINK(ModifiedHdl, weld::Entry&, void);
+
+public:
+ OPasswordDialog(weld::Window* pParent, std::u16string_view rUserName);
+
+ OUString GetOldPassword() const { return m_xEDOldPassword->get_text(); }
+ OUString GetNewPassword() const { return m_xEDPassword->get_text(); }
+};
+
+}
+
+OPasswordDialog::OPasswordDialog(weld::Window* _pParent, std::u16string_view rUserName)
+ : GenericDialogController(_pParent, "dbaccess/ui/password.ui", "PasswordDialog")
+ , m_xUser(m_xBuilder->weld_frame("userframe"))
+ , m_xEDOldPassword(m_xBuilder->weld_entry("oldpassword"))
+ , m_xEDPassword(m_xBuilder->weld_entry("newpassword"))
+ , m_xEDPasswordRepeat(m_xBuilder->weld_entry("confirmpassword"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+{
+ OUString sUser = m_xUser->get_label();
+ sUser = sUser.replaceFirst("$name$: $", rUserName);
+ m_xUser->set_label(sUser);
+ m_xOKBtn->set_sensitive(false);
+
+ m_xOKBtn->connect_clicked( LINK( this, OPasswordDialog, OKHdl_Impl ) );
+ m_xEDOldPassword->connect_changed( LINK( this, OPasswordDialog, ModifiedHdl ) );
+}
+
+IMPL_LINK_NOARG(OPasswordDialog, OKHdl_Impl, weld::Button&, void)
+{
+ if (m_xEDPassword->get_text() == m_xEDPasswordRepeat->get_text())
+ m_xDialog->response(RET_OK);
+ else
+ {
+ OUString aErrorMsg( DBA_RES( STR_ERROR_PASSWORDS_NOT_IDENTICAL));
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ aErrorMsg));
+ xErrorBox->run();
+ m_xEDPassword->set_text(OUString());
+ m_xEDPasswordRepeat->set_text(OUString());
+ m_xEDPassword->grab_focus();
+ }
+}
+
+IMPL_LINK(OPasswordDialog, ModifiedHdl, weld::Entry&, rEdit, void)
+{
+ m_xOKBtn->set_sensitive(!rEdit.get_text().isEmpty());
+}
+
+// OUserAdmin
+OUserAdmin::OUserAdmin(weld::Container* pPage, weld::DialogController* pController,const SfxItemSet& _rAttrSet)
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/useradminpage.ui", "UserAdminPage", _rAttrSet)
+ , m_xUSER(m_xBuilder->weld_combo_box("user"))
+ , m_xNEWUSER(m_xBuilder->weld_button("add"))
+ , m_xCHANGEPWD(m_xBuilder->weld_button("changepass"))
+ , m_xDELETEUSER(m_xBuilder->weld_button("delete"))
+ , m_xTable(m_xBuilder->weld_container("table"))
+ , m_xTableCtrlParent(m_xTable->CreateChildFrame())
+ , m_xTableCtrl(VclPtr<OTableGrantControl>::Create(m_xTableCtrlParent))
+{
+ m_xTableCtrl->Show();
+
+ m_xUSER->connect_changed(LINK(this, OUserAdmin, ListDblClickHdl));
+ m_xNEWUSER->connect_clicked(LINK(this, OUserAdmin, UserHdl));
+ m_xCHANGEPWD->connect_clicked(LINK(this, OUserAdmin, UserHdl));
+ m_xDELETEUSER->connect_clicked(LINK(this, OUserAdmin, UserHdl));
+}
+
+OUserAdmin::~OUserAdmin()
+{
+ m_xConnection = nullptr;
+ m_xTableCtrl.disposeAndClear();
+ m_xTableCtrlParent->dispose();
+ m_xTableCtrlParent.clear();
+}
+
+void OUserAdmin::FillUserNames()
+{
+ if(m_xConnection.is())
+ {
+ m_xUSER->clear();
+
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+
+ if ( xMetaData.is() )
+ {
+ m_UserName = xMetaData->getUserName();
+
+ // first we need the users
+ if ( m_xUsers.is() )
+ {
+ m_xUSER->clear();
+
+ m_aUserNames = m_xUsers->getElementNames();
+ const OUString* pBegin = m_aUserNames.getConstArray();
+ const OUString* pEnd = pBegin + m_aUserNames.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ m_xUSER->append_text(*pBegin);
+
+ m_xUSER->set_active(0);
+ if(m_xUsers->hasByName(m_UserName))
+ {
+ Reference<XAuthorizable> xAuth;
+ m_xUsers->getByName(m_UserName) >>= xAuth;
+ m_xTableCtrl->setGrantUser(xAuth);
+ }
+
+ m_xTableCtrl->setUserName(GetUser());
+ m_xTableCtrl->Init();
+ }
+ }
+ }
+
+ Reference<XAppend> xAppend(m_xUsers,UNO_QUERY);
+ m_xNEWUSER->set_sensitive(xAppend.is());
+ Reference<XDrop> xDrop(m_xUsers,UNO_QUERY);
+ m_xDELETEUSER->set_sensitive(xDrop.is());
+
+ m_xCHANGEPWD->set_sensitive(m_xUsers.is());
+ m_xTableCtrl->Enable(m_xUsers.is());
+}
+
+std::unique_ptr<SfxTabPage> OUserAdmin::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet )
+{
+ return std::make_unique<OUserAdmin>( pPage, pController, *_rAttrSet );
+}
+
+IMPL_LINK(OUserAdmin, UserHdl, weld::Button&, rButton, void)
+{
+ try
+ {
+ if (&rButton == m_xNEWUSER.get())
+ {
+ SfxPasswordDialog aPwdDlg(GetFrameWeld());
+ aPwdDlg.ShowExtras(SfxShowExtras::ALL);
+ if (aPwdDlg.run())
+ {
+ Reference<XDataDescriptorFactory> xUserFactory(m_xUsers,UNO_QUERY);
+ Reference<XPropertySet> xNewUser = xUserFactory->createDataDescriptor();
+ if(xNewUser.is())
+ {
+ xNewUser->setPropertyValue(PROPERTY_NAME,Any(aPwdDlg.GetUser()));
+ xNewUser->setPropertyValue(PROPERTY_PASSWORD,Any(aPwdDlg.GetPassword()));
+ Reference<XAppend> xAppend(m_xUsers,UNO_QUERY);
+ if(xAppend.is())
+ xAppend->appendByDescriptor(xNewUser);
+ }
+ }
+ }
+ else if (&rButton == m_xCHANGEPWD.get())
+ {
+ OUString sName = GetUser();
+
+ if(m_xUsers->hasByName(sName))
+ {
+ Reference<XUser> xUser;
+ m_xUsers->getByName(sName) >>= xUser;
+ if(xUser.is())
+ {
+ OPasswordDialog aDlg(GetFrameWeld(), sName);
+ if (aDlg.run() == RET_OK)
+ {
+ OUString sNewPassword,sOldPassword;
+ sNewPassword = aDlg.GetNewPassword();
+ sOldPassword = aDlg.GetOldPassword();
+
+ if(!sNewPassword.isEmpty())
+ xUser->changePassword(sOldPassword,sNewPassword);
+ }
+ }
+ }
+ }
+ else
+ {// delete user
+ if(m_xUsers.is() && m_xUsers->hasByName(GetUser()))
+ {
+ Reference<XDrop> xDrop(m_xUsers,UNO_QUERY);
+ if(xDrop.is())
+ {
+ std::unique_ptr<weld::MessageDialog> xQry(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ DBA_RES(STR_QUERY_USERADMIN_DELETE_USER)));
+ if (xQry->run() == RET_YES)
+ xDrop->dropByName(GetUser());
+ }
+ }
+ }
+ FillUserNames();
+ }
+ catch(const SQLException& e)
+ {
+ ::dbtools::showError(::dbtools::SQLExceptionInfo(e), GetDialogController()->getDialog()->GetXWindow(), m_xORB);
+ }
+ catch(Exception& )
+ {
+ }
+}
+
+IMPL_LINK_NOARG(OUserAdmin, ListDblClickHdl, weld::ComboBox&, void)
+{
+ m_xTableCtrl->setUserName(GetUser());
+ m_xTableCtrl->UpdateTables();
+ m_xTableCtrl->DeactivateCell();
+ m_xTableCtrl->ActivateCell(m_xTableCtrl->GetCurRow(),m_xTableCtrl->GetCurColumnId());
+}
+
+OUString OUserAdmin::GetUser() const
+{
+ return m_xUSER->get_active_text();
+}
+
+void OUserAdmin::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/)
+{
+}
+
+void OUserAdmin::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/)
+{
+}
+
+void OUserAdmin::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+{
+ m_xTableCtrl->setComponentContext(m_xORB);
+ try
+ {
+ if ( !m_xConnection.is() && m_pAdminDialog )
+ {
+ m_xConnection = m_pAdminDialog->createConnection().first;
+ Reference< XTablesSupplier > xTablesSup(m_xConnection,UNO_QUERY);
+ Reference<XUsersSupplier> xUsersSup(xTablesSup,UNO_QUERY);
+ if ( !xUsersSup.is() )
+ {
+ Reference< XDataDefinitionSupplier > xDriver(m_pAdminDialog->getDriver(),UNO_QUERY);
+ if ( xDriver.is() )
+ {
+ xUsersSup.set(xDriver->getDataDefinitionByConnection(m_xConnection),UNO_QUERY);
+ xTablesSup.set(xUsersSup,UNO_QUERY);
+ }
+ }
+ if ( xUsersSup.is() )
+ {
+ m_xTableCtrl->setTablesSupplier(xTablesSup);
+ m_xUsers = xUsersSup->getUsers();
+ }
+ }
+ FillUserNames();
+ }
+ catch(const SQLException& e)
+ {
+ ::dbtools::showError(::dbtools::SQLExceptionInfo(e), GetDialogController()->getDialog()->GetXWindow(), m_xORB);
+ }
+
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/UserAdmin.hxx b/dbaccess/source/ui/dlg/UserAdmin.hxx
new file mode 100644
index 000000000..e9c2a13e7
--- /dev/null
+++ b/dbaccess/source/ui/dlg/UserAdmin.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableGrantCtrl.hxx>
+#include "adminpages.hxx"
+
+namespace com::sun::star {
+ namespace sdbc {
+ class XConnection;
+ }
+}
+
+namespace dbaui
+{
+
+class OUserAdmin final : public OGenericAdministrationPage
+{
+ std::unique_ptr<weld::ComboBox> m_xUSER;
+ std::unique_ptr<weld::Button> m_xNEWUSER;
+ std::unique_ptr<weld::Button> m_xCHANGEPWD;
+ std::unique_ptr<weld::Button> m_xDELETEUSER;
+ std::unique_ptr<weld::Container> m_xTable;
+ css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent;
+ VclPtr<OTableGrantControl> m_xTableCtrl; // show the grant rights of one user
+
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference< css::container::XNameAccess > m_xUsers;
+ css::uno::Sequence< OUString> m_aUserNames;
+
+ OUString m_UserName;
+
+ // methods
+ DECL_LINK(ListDblClickHdl, weld::ComboBox&, void);
+ DECL_LINK(UserHdl, weld::Button&, void);
+
+ void FillUserNames();
+
+public:
+ OUserAdmin(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet);
+ virtual ~OUserAdmin() override;
+
+ OUString GetUser() const;
+
+ // subclasses must override this, but it isn't pure virtual
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ // <method>OGenericAdministrationPage::fillControls</method>
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ // <method>OGenericAdministrationPage::fillWindows</method>
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/UserAdminDlg.cxx b/dbaccess/source/ui/dlg/UserAdminDlg.cxx
new file mode 100644
index 000000000..ec44c3399
--- /dev/null
+++ b/dbaccess/source/ui/dlg/UserAdminDlg.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include "adminpages.hxx"
+#include "DbAdminImpl.hxx"
+#include <strings.hrc>
+#include "UserAdmin.hxx"
+#include <UserAdminDlg.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+
+ // OUserAdminDlg
+ OUserAdminDlg::OUserAdminDlg(weld::Window* pParent,
+ SfxItemSet* pItems,
+ const Reference< XComponentContext >& rxORB,
+ const css::uno::Any& rDataSourceName,
+ const Reference< XConnection >& xConnection)
+ : SfxTabDialogController(pParent, "dbaccess/ui/useradmindialog.ui", "UserAdminDialog", pItems)
+ , m_pParent(pParent)
+ , m_pItemSet(pItems)
+ , m_xConnection(xConnection)
+ , m_bOwnConnection(!xConnection.is())
+ {
+ m_pImpl.reset(new ODbDataSourceAdministrationHelper(rxORB, m_xDialog.get(), pParent, this));
+ m_pImpl->setDataSourceOrName(rDataSourceName);
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ m_pImpl->translateProperties(xDatasource, *pItems);
+ SetInputSet(pItems);
+ // propagate this set as our new input set and reset the example set
+ m_xExampleSet.reset(new SfxItemSet(*GetInputSetImpl()));
+
+ AddTabPage("settings", OUserAdmin::Create, nullptr);
+
+ // remove the reset button - it's meaning is much too ambiguous in this dialog
+ RemoveResetButton();
+ }
+
+ OUserAdminDlg::~OUserAdminDlg()
+ {
+ if ( m_bOwnConnection )
+ {
+ try
+ {
+ ::comphelper::disposeComponent(m_xConnection);
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+
+ SetInputSet(nullptr);
+ }
+
+ short OUserAdminDlg::run()
+ {
+ try
+ {
+ ::dbtools::DatabaseMetaData aMetaData( createConnection().first );
+ if ( !aMetaData.supportsUserAdministration( getORB() ) )
+ {
+ OUString sError(DBA_RES(STR_USERADMIN_NOT_AVAILABLE));
+ throw SQLException(sError, nullptr, "S1000", 0, Any());
+ }
+ }
+ catch(const SQLException&)
+ {
+ ::dbtools::showError(::dbtools::SQLExceptionInfo(::cppu::getCaughtException()), m_pParent->GetXWindow(), getORB());
+ return RET_CANCEL;
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ short nRet = SfxTabDialogController::run();
+ if ( nRet == RET_OK )
+ m_pImpl->saveChanges(*GetOutputItemSet());
+ return nRet;
+ }
+ void OUserAdminDlg::PageCreated(const OString& rId, SfxTabPage& _rPage)
+ {
+ // register ourself as modified listener
+ static_cast<OGenericAdministrationPage&>(_rPage).SetServiceFactory( m_pImpl->getORB() );
+ static_cast<OGenericAdministrationPage&>(_rPage).SetAdminDialog(this,this);
+ SfxTabDialogController::PageCreated(rId, _rPage);
+ }
+ const SfxItemSet* OUserAdminDlg::getOutputSet() const
+ {
+ return m_pItemSet;
+ }
+ SfxItemSet* OUserAdminDlg::getWriteOutputSet()
+ {
+ return m_pItemSet;
+ }
+ std::pair< Reference<XConnection>,bool> OUserAdminDlg::createConnection()
+ {
+ if ( !m_xConnection.is() )
+ {
+ m_xConnection = m_pImpl->createConnection().first;
+ m_bOwnConnection = m_xConnection.is();
+ }
+ return std::pair< Reference<XConnection>,bool> (m_xConnection,false);
+ }
+ Reference< XComponentContext > OUserAdminDlg::getORB() const
+ {
+ return m_pImpl->getORB();
+ }
+ Reference< XDriver > OUserAdminDlg::getDriver()
+ {
+ return m_pImpl->getDriver();
+ }
+ OUString OUserAdminDlg::getDatasourceType(const SfxItemSet& _rSet) const
+ {
+ return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet);
+ }
+ void OUserAdminDlg::clearPassword()
+ {
+ m_pImpl->clearPassword();
+ }
+ void OUserAdminDlg::setTitle(const OUString& _sTitle)
+ {
+ m_xDialog->set_title(_sTitle);
+ }
+ void OUserAdminDlg::enableConfirmSettings( bool ) {}
+ void OUserAdminDlg::saveDatasource()
+ {
+ PrepareLeaveCurrentPage();
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/admincontrols.cxx b/dbaccess/source/ui/dlg/admincontrols.cxx
new file mode 100644
index 000000000..de515f9e3
--- /dev/null
+++ b/dbaccess/source/ui/dlg/admincontrols.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "admincontrols.hxx"
+#include <dsitems.hxx>
+
+#include <svl/eitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/svapp.hxx>
+
+namespace dbaui
+{
+
+ // MySQLNativeSettings
+ MySQLNativeSettings::MySQLNativeSettings(weld::Widget* pParent, const Link<weld::Widget*,void>& rControlModificationLink)
+ : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/mysqlnativesettings.ui"))
+ , m_xContainer(m_xBuilder->weld_widget("MysqlNativeSettings"))
+ , m_xDatabaseNameLabel(m_xBuilder->weld_label("dbnamelabel"))
+ , m_xDatabaseName(m_xBuilder->weld_entry("dbname"))
+ , m_xHostPortRadio(m_xBuilder->weld_radio_button("hostport"))
+ , m_xSocketRadio(m_xBuilder->weld_radio_button("socketlabel"))
+ , m_xNamedPipeRadio(m_xBuilder->weld_radio_button("namedpipelabel"))
+ , m_xHostNameLabel(m_xBuilder->weld_label("serverlabel"))
+ , m_xHostName(m_xBuilder->weld_entry("server"))
+ , m_xPortLabel(m_xBuilder->weld_label("portlabel"))
+ , m_xPort(m_xBuilder->weld_spin_button("port"))
+ , m_xDefaultPort(m_xBuilder->weld_label("defaultport"))
+ , m_xSocket(m_xBuilder->weld_entry("socket"))
+ , m_xNamedPipe(m_xBuilder->weld_entry("namedpipe"))
+ , m_aControlModificationLink(rControlModificationLink)
+ {
+ m_xDatabaseName->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) );
+ m_xHostName->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) );
+ m_xPort->connect_value_changed( LINK(this, MySQLNativeSettings, SpinModifyHdl) );
+ m_xSocket->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) );
+ m_xNamedPipe->connect_changed( LINK(this, MySQLNativeSettings, EditModifyHdl) );
+ m_xSocketRadio->connect_toggled( LINK(this, MySQLNativeSettings, RadioToggleHdl) );
+ m_xNamedPipeRadio->connect_toggled( LINK(this, MySQLNativeSettings, RadioToggleHdl) );
+ m_xHostPortRadio->connect_toggled( LINK(this, MySQLNativeSettings, RadioToggleHdl) );
+
+ // sockets are available on Unix systems only, named pipes only on Windows
+#ifdef UNX
+ m_xNamedPipeRadio->hide();
+ m_xNamedPipe->hide();
+#else
+ m_xSocketRadio->hide();
+ m_xSocket->hide();
+#endif
+ m_xContainer->show();
+ }
+
+ IMPL_LINK(MySQLNativeSettings, RadioToggleHdl, weld::Toggleable&, rRadioButton, void)
+ {
+ m_aControlModificationLink.Call(&rRadioButton);
+
+ const bool bHostPortRadio = m_xHostPortRadio->get_active();
+ m_xHostNameLabel->set_sensitive(bHostPortRadio);
+ m_xHostName->set_sensitive(bHostPortRadio);
+ m_xPortLabel->set_sensitive(bHostPortRadio);
+ m_xPort->set_sensitive(bHostPortRadio);
+ m_xDefaultPort->set_sensitive(bHostPortRadio);
+
+ m_xSocket->set_sensitive(m_xSocketRadio->get_active());
+ m_xNamedPipe->set_sensitive(m_xNamedPipeRadio->get_active());
+ }
+
+ IMPL_LINK(MySQLNativeSettings, EditModifyHdl, weld::Entry&, rEdit, void)
+ {
+ m_aControlModificationLink.Call(&rEdit);
+ }
+
+ IMPL_LINK(MySQLNativeSettings, SpinModifyHdl, weld::SpinButton&, rEdit, void)
+ {
+ m_aControlModificationLink.Call(&rEdit);
+ }
+
+ void MySQLNativeSettings::fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList )
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xDatabaseName.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xHostName.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xPort.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xSocket.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xNamedPipe.get()));
+ }
+
+ void MySQLNativeSettings::fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList )
+ {
+ _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xDatabaseNameLabel.get() ) );
+ _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xHostNameLabel.get() ) );
+ _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xPortLabel.get() ) );
+ _rControlList.emplace_back( new ODisableWidgetWrapper<weld::Label>( m_xDefaultPort.get() ) );
+ _rControlList.emplace_back( new ODisableWidgetWrapper<weld::RadioButton>( m_xSocketRadio.get() ) );
+ _rControlList.emplace_back( new ODisableWidgetWrapper<weld::RadioButton>( m_xNamedPipeRadio.get() ) );
+ }
+
+ bool MySQLNativeSettings::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = false;
+
+ OGenericAdministrationPage::fillString( *_rSet, m_xHostName.get(), DSID_CONN_HOSTNAME, bChangedSomething );
+ OGenericAdministrationPage::fillString( *_rSet, m_xDatabaseName.get(), DSID_DATABASENAME, bChangedSomething );
+ OGenericAdministrationPage::fillInt32 ( *_rSet, m_xPort.get(), DSID_MYSQL_PORTNUMBER, bChangedSomething );
+#ifdef UNX
+ OGenericAdministrationPage::fillString( *_rSet, m_xSocket.get(), DSID_CONN_SOCKET, bChangedSomething );
+#else
+ OGenericAdministrationPage::fillString( *_rSet, m_xNamedPipe.get(), DSID_NAMED_PIPE, bChangedSomething );
+#endif
+
+ return bChangedSomething;
+ }
+
+ void MySQLNativeSettings::implInitControls(const SfxItemSet& _rSet )
+ {
+ const SfxBoolItem* pInvalid = _rSet.GetItem<SfxBoolItem>(DSID_INVALID_SELECTION);
+ bool bValid = !pInvalid || !pInvalid->GetValue();
+ if ( !bValid )
+ return;
+
+ const SfxStringItem* pDatabaseName = _rSet.GetItem<SfxStringItem>(DSID_DATABASENAME);
+ const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
+ const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_MYSQL_PORTNUMBER);
+ const SfxStringItem* pSocket = _rSet.GetItem<SfxStringItem>(DSID_CONN_SOCKET);
+ const SfxStringItem* pNamedPipe = _rSet.GetItem<SfxStringItem>(DSID_NAMED_PIPE);
+
+ m_xDatabaseName->set_text( pDatabaseName->GetValue() );
+ m_xDatabaseName->save_value();
+
+ m_xHostName->set_text( pHostName->GetValue() );
+ m_xHostName->save_value();
+
+ m_xPort->set_value( pPortNumber->GetValue() );
+ m_xPort->save_value();
+
+ m_xSocket->set_text( pSocket->GetValue() );
+ m_xSocket->save_value();
+
+ m_xNamedPipe->set_text( pNamedPipe->GetValue() );
+ m_xNamedPipe->save_value();
+
+ // if a socket (on Unix) or a pipe name (on Windows) is given, this is preferred over
+ // the port
+#ifdef UNX
+ weld::RadioButton& rSocketPipeRadio = *m_xSocketRadio;
+ const SfxStringItem* pSocketPipeItem = pSocket;
+#else
+ weld::RadioButton& rSocketPipeRadio = *m_xNamedPipeRadio;
+ const SfxStringItem* pSocketPipeItem = pNamedPipe;
+#endif
+ const OUString& rSocketPipe( pSocketPipeItem->GetValue() );
+ if (!rSocketPipe.isEmpty())
+ rSocketPipeRadio.set_active(true);
+ else
+ m_xHostPortRadio->set_active(true);
+ }
+
+ bool MySQLNativeSettings::canAdvance() const
+ {
+ if (m_xDatabaseName->get_text().isEmpty())
+ return false;
+
+ if ( m_xHostPortRadio->get_active()
+ && ( ( m_xHostName->get_text().isEmpty() )
+ || ( m_xPort->get_text().isEmpty() )
+ )
+ )
+ return false;
+
+#ifdef UNX
+ if ( ( m_xSocketRadio->get_active() )
+ && ( m_xSocket->get_text().isEmpty() )
+ )
+#else
+ if ( ( m_xNamedPipeRadio->get_active() )
+ && ( m_xNamedPipe->get_text().isEmpty() )
+ )
+#endif
+ return false;
+
+ return true;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/admincontrols.hxx b/dbaccess/source/ui/dlg/admincontrols.hxx
new file mode 100644
index 000000000..7bd1e5edf
--- /dev/null
+++ b/dbaccess/source/ui/dlg/admincontrols.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "adminpages.hxx"
+
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+
+ // MySQLNativeSettings
+ class MySQLNativeSettings
+ {
+ private:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Widget> m_xContainer;
+ std::unique_ptr<weld::Label> m_xDatabaseNameLabel;
+ std::unique_ptr<weld::Entry> m_xDatabaseName;
+ std::unique_ptr<weld::RadioButton> m_xHostPortRadio;
+ std::unique_ptr<weld::RadioButton> m_xSocketRadio;
+ std::unique_ptr<weld::RadioButton> m_xNamedPipeRadio;
+ std::unique_ptr<weld::Label> m_xHostNameLabel;
+ std::unique_ptr<weld::Entry> m_xHostName;
+ std::unique_ptr<weld::Label> m_xPortLabel;
+ std::unique_ptr<weld::SpinButton> m_xPort;
+ std::unique_ptr<weld::Label> m_xDefaultPort;
+ std::unique_ptr<weld::Entry> m_xSocket;
+ std::unique_ptr<weld::Entry> m_xNamedPipe;
+ Link<weld::Widget*,void> m_aControlModificationLink;
+ DECL_LINK(RadioToggleHdl, weld::Toggleable&, void);
+ DECL_LINK(SpinModifyHdl, weld::SpinButton&, void);
+ DECL_LINK(EditModifyHdl, weld::Entry&, void);
+
+ public:
+ MySQLNativeSettings(weld::Widget* pParent, const Link<weld::Widget*,void>& rControlModificationLink);
+ void fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList );
+ void fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList );
+
+ bool FillItemSet( SfxItemSet* rCoreAttrs );
+ void implInitControls( const SfxItemSet& _rSet );
+
+ bool canAdvance() const;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/adminpages.cxx b/dbaccess/source/ui/dlg/adminpages.cxx
new file mode 100644
index 000000000..5f0eedbb0
--- /dev/null
+++ b/dbaccess/source/ui/dlg/adminpages.cxx
@@ -0,0 +1,278 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "adminpages.hxx"
+#include <core_resource.hxx>
+#include <dbu_dlg.hxx>
+#include <IItemSetHelper.hxx>
+#include <strings.hrc>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <dsitems.hxx>
+#include "dsselect.hxx"
+#include "odbcconfig.hxx"
+#include "optionalboolitem.hxx"
+#include <sqlmessage.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/types.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::dbtools;
+
+ ISaveValueWrapper::~ISaveValueWrapper()
+ {
+ }
+
+ OGenericAdministrationPage::OGenericAdministrationPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& rAttrSet)
+ : SfxTabPage(pPage, pController, rUIXMLDescription, rId, &rAttrSet)
+ , m_abEnableRoadmap(false)
+ , m_pAdminDialog(nullptr)
+ , m_pItemSetHelper(nullptr)
+ {
+ SetExchangeSupport();
+
+ m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * WIZARD_PAGE_X,
+ m_xContainer->get_text_height() * WIZARD_PAGE_Y);
+ }
+
+ DeactivateRC OGenericAdministrationPage::DeactivatePage(SfxItemSet* _pSet)
+ {
+ if (_pSet)
+ {
+ if (!prepareLeave())
+ return DeactivateRC::KeepPage;
+ FillItemSet(_pSet);
+ }
+
+ return DeactivateRC::LeavePage;
+ }
+
+ void OGenericAdministrationPage::Reset(const SfxItemSet* _rCoreAttrs)
+ {
+ implInitControls(*_rCoreAttrs, false);
+ }
+
+ void OGenericAdministrationPage::Activate()
+ {
+ BuilderPage::Activate();
+ OSL_ENSURE(m_pItemSetHelper,"NO ItemSetHelper set!");
+ if ( m_pItemSetHelper )
+ ActivatePage(*m_pItemSetHelper->getOutputSet());
+ }
+
+ void OGenericAdministrationPage::ActivatePage(const SfxItemSet& _rSet)
+ {
+ implInitControls(_rSet, true);
+ }
+
+ void OGenericAdministrationPage::getFlags(const SfxItemSet& _rSet, bool& _rValid, bool& _rReadonly)
+ {
+ const SfxBoolItem* pInvalid = _rSet.GetItem<SfxBoolItem>(DSID_INVALID_SELECTION);
+ _rValid = !pInvalid || !pInvalid->GetValue();
+ const SfxBoolItem* pReadonly = _rSet.GetItem<SfxBoolItem>(DSID_READONLY);
+ _rReadonly = !_rValid || (pReadonly && pReadonly->GetValue());
+ }
+
+ IMPL_LINK(OGenericAdministrationPage, OnControlModified, weld::Widget*, pCtrl, void)
+ {
+ callModifiedHdl(pCtrl);
+ }
+
+ IMPL_LINK(OGenericAdministrationPage, OnControlModifiedButtonClick, weld::Toggleable&, rCtrl, void)
+ {
+ callModifiedHdl(&rCtrl);
+ }
+
+ IMPL_LINK(OGenericAdministrationPage, OnControlEntryModifyHdl, weld::Entry&, rCtrl, void)
+ {
+ callModifiedHdl(&rCtrl);
+ }
+
+ IMPL_LINK(OGenericAdministrationPage, OnControlSpinButtonModifyHdl, weld::SpinButton&, rCtrl, void)
+ {
+ callModifiedHdl(&rCtrl);
+ }
+
+ bool OGenericAdministrationPage::getSelectedDataSource(OUString& _sReturn, OUString const & _sCurr)
+ {
+ // collect all ODBC data source names
+ std::set<OUString> aOdbcDatasources;
+ OOdbcEnumeration aEnumeration;
+ if (!aEnumeration.isLoaded())
+ {
+ // show an error message
+ OUString sError(DBA_RES(STR_COULD_NOT_LOAD_ODBC_LIB));
+ sError = sError.replaceFirst("#lib#", aEnumeration.getLibraryName());
+ std::unique_ptr<weld::MessageDialog> xDialog(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sError));
+ xDialog->run();
+ return false;
+ }
+ else
+ {
+ aEnumeration.getDatasourceNames(aOdbcDatasources);
+ // execute the select dialog
+ ODatasourceSelectDialog aSelector(GetFrameWeld(), aOdbcDatasources);
+ if (!_sCurr.isEmpty())
+ aSelector.Select(_sCurr);
+ if (RET_OK == aSelector.run())
+ _sReturn = aSelector.GetSelected();
+ }
+ return true;
+ }
+
+ void OGenericAdministrationPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ std::vector< std::unique_ptr<ISaveValueWrapper> > aControlList;
+ if ( _bSaveValue )
+ {
+ fillControls(aControlList);
+ for( const auto& pValueWrapper : aControlList )
+ {
+ pValueWrapper->SaveValue();
+ }
+ }
+
+ if ( bReadonly )
+ {
+ fillWindows(aControlList);
+ for( const auto& pValueWrapper : aControlList )
+ {
+ pValueWrapper->Disable();
+ }
+ }
+ }
+
+ void OGenericAdministrationPage::initializePage()
+ {
+ OSL_ENSURE(m_pItemSetHelper,"NO ItemSetHelper set!");
+ if ( m_pItemSetHelper )
+ Reset(m_pItemSetHelper->getOutputSet());
+ }
+ bool OGenericAdministrationPage::commitPage( ::vcl::WizardTypes::CommitPageReason )
+ {
+ return true;
+ }
+ bool OGenericAdministrationPage::canAdvance() const
+ {
+ return true;
+ }
+ void OGenericAdministrationPage::fillBool( SfxItemSet& _rSet, const weld::CheckButton* pCheckBox, sal_uInt16 _nID, bool bOptionalBool, bool& _bChangedSomething, bool _bRevertValue )
+ {
+ if (!(pCheckBox && pCheckBox->get_state_changed_from_saved()))
+ return;
+
+ bool bValue = pCheckBox->get_active();
+ if ( _bRevertValue )
+ bValue = !bValue;
+
+ if (bOptionalBool)
+ {
+ OptionalBoolItem aValue( _nID );
+ if ( pCheckBox->get_state() != TRISTATE_INDET )
+ aValue.SetValue( bValue );
+ _rSet.Put( aValue );
+ }
+ else
+ _rSet.Put( SfxBoolItem( _nID, bValue ) );
+
+ _bChangedSomething = true;
+ }
+ void OGenericAdministrationPage::fillInt32(SfxItemSet& _rSet, const weld::SpinButton* pEdit, sal_uInt16 _nID, bool& _bChangedSomething)
+ {
+ if (pEdit && pEdit->get_value_changed_from_saved())
+ {
+ _rSet.Put(SfxInt32Item(_nID, pEdit->get_value()));
+ _bChangedSomething = true;
+ }
+ }
+ void OGenericAdministrationPage::fillString(SfxItemSet& _rSet, const weld::Entry* pEdit, sal_uInt16 _nID, bool& _bChangedSomething)
+ {
+ if (pEdit && pEdit->get_value_changed_from_saved())
+ {
+ _rSet.Put(SfxStringItem(_nID, pEdit->get_text().trim()));
+ _bChangedSomething = true;
+ }
+ }
+ void OGenericAdministrationPage::fillString(SfxItemSet& _rSet, const dbaui::OConnectionURLEdit* pEdit, sal_uInt16 _nID, bool& _bChangedSomething)
+ {
+ if (pEdit && pEdit->get_value_changed_from_saved())
+ {
+ _rSet.Put(SfxStringItem(_nID, pEdit->GetText().trim()));
+ _bChangedSomething = true;
+ }
+ }
+
+ IMPL_LINK_NOARG(OGenericAdministrationPage, OnTestConnectionButtonClickHdl, weld::Button&, void)
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ bool bSuccess = false;
+ if ( !m_pAdminDialog )
+ return;
+
+ m_pAdminDialog->saveDatasource();
+ OGenericAdministrationPage::implInitControls(*m_pItemSetHelper->getOutputSet(), true);
+ bool bShowMessage = true;
+ try
+ {
+ std::pair< Reference<XConnection>,bool> aConnectionPair = m_pAdminDialog->createConnection();
+ bShowMessage = aConnectionPair.second;
+ bSuccess = aConnectionPair.first.is();
+ ::comphelper::disposeComponent(aConnectionPair.first);
+ }
+ catch(Exception&)
+ {
+ }
+ if ( bShowMessage )
+ {
+ MessageType eImage = MessageType::Info;
+ OUString aMessage,sTitle;
+ sTitle = DBA_RES(STR_CONNECTION_TEST);
+ if ( bSuccess )
+ {
+ aMessage = DBA_RES(STR_CONNECTION_SUCCESS);
+ }
+ else
+ {
+ eImage = MessageType::Error;
+ aMessage = DBA_RES(STR_CONNECTION_NO_SUCCESS);
+ }
+ OSQLMessageBox aMsg(GetFrameWeld(), sTitle, aMessage, MessBoxStyle::Ok, eImage);
+ aMsg.run();
+ }
+ if ( !bSuccess )
+ m_pAdminDialog->clearPassword();
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/adminpages.hxx b/dbaccess/source/ui/dlg/adminpages.hxx
new file mode 100644
index 000000000..de8265751
--- /dev/null
+++ b/dbaccess/source/ui/dlg/adminpages.hxx
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+#include <vcl/wizardmachine.hxx>
+#include <curledit.hxx>
+
+namespace dbaui
+{
+ /// helper class to wrap the savevalue and disable call
+ class SAL_NO_VTABLE ISaveValueWrapper
+ {
+ public:
+ virtual ~ISaveValueWrapper() = 0;
+ virtual void SaveValue() = 0;
+ virtual void Disable() = 0;
+ };
+
+ template < class T > class OSaveValueWidgetWrapper : public ISaveValueWrapper
+ {
+ T* m_pSaveValue;
+ public:
+ explicit OSaveValueWidgetWrapper(T* _pSaveValue) : m_pSaveValue(_pSaveValue)
+ { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); }
+
+ virtual void SaveValue() override { m_pSaveValue->save_value(); }
+ virtual void Disable() override { m_pSaveValue->set_sensitive(false); }
+ };
+
+ template <> class OSaveValueWidgetWrapper<weld::Toggleable> : public ISaveValueWrapper
+ {
+ weld::Toggleable* m_pSaveValue;
+ public:
+ explicit OSaveValueWidgetWrapper(weld::Toggleable* _pSaveValue) : m_pSaveValue(_pSaveValue)
+ { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); }
+
+ virtual void SaveValue() override { m_pSaveValue->save_state(); }
+ virtual void Disable() override { m_pSaveValue->set_sensitive(false); }
+ };
+
+ template <> class OSaveValueWidgetWrapper<dbaui::OConnectionURLEdit> : public ISaveValueWrapper
+ {
+ dbaui::OConnectionURLEdit* m_pSaveValue;
+ public:
+ explicit OSaveValueWidgetWrapper(dbaui::OConnectionURLEdit* _pSaveValue) : m_pSaveValue(_pSaveValue)
+ { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); }
+
+ virtual void SaveValue() override { m_pSaveValue->save_value(); }
+ virtual void Disable() override { m_pSaveValue->set_sensitive(false); }
+ };
+
+ template <class T> class ODisableWidgetWrapper : public ISaveValueWrapper
+ {
+ T* m_pSaveValue;
+ public:
+ explicit ODisableWidgetWrapper(T* _pSaveValue) : m_pSaveValue(_pSaveValue)
+ { OSL_ENSURE(m_pSaveValue,"Illegal argument!"); }
+
+ virtual void SaveValue() override {}
+ virtual void Disable() override { m_pSaveValue->set_sensitive(false); }
+ };
+
+ // OGenericAdministrationPage
+ class IDatabaseSettingsDialog;
+ class IItemSetHelper;
+ class OGenericAdministrationPage :public SfxTabPage
+ ,public ::vcl::IWizardPageController
+ {
+ private:
+ Link<OGenericAdministrationPage const *, void> m_aModifiedHandler; /// to be called if something on the page has been modified
+ bool m_abEnableRoadmap;
+ protected:
+ IDatabaseSettingsDialog* m_pAdminDialog;
+ IItemSetHelper* m_pItemSetHelper;
+
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xORB;
+ public:
+ OGenericAdministrationPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& rAttrSet);
+ /// set a handler which gets called every time something on the page has been modified
+ void SetModifiedHandler(const Link<OGenericAdministrationPage const *, void>& _rHandler) { m_aModifiedHandler = _rHandler; }
+
+ /** Sets the ParentDialog
+ @param _pAdminDialog
+ the ParentDialog
+ @param _pItemSetHelper
+ the itemset helper
+ */
+ void SetAdminDialog(IDatabaseSettingsDialog* _pDialog,IItemSetHelper* _pItemSetHelper)
+ {
+ OSL_ENSURE(_pDialog && _pItemSetHelper,"Values are NULL!");
+ m_pAdminDialog = _pDialog;
+ m_pItemSetHelper = _pItemSetHelper;
+ }
+
+ /** Sets the ServiceFactory
+ @param _rxORB
+ The service factory.
+ */
+ void SetServiceFactory(const css::uno::Reference< css::uno::XComponentContext >& rxORB)
+ {
+ m_xORB = rxORB;
+ }
+
+ /** opens a dialog filled with all data sources available for this type and
+ returns the selected on.
+ @param _eType
+ The type for which the data source dialog should be opened.
+ @param _sReturn
+ <OUT/> contains the selected name.
+ @return
+ <FALSE/> if an error occurred, otherwise <TRUE/>
+ */
+ bool getSelectedDataSource(OUString& _sReturn, OUString const & _sCurr);
+
+ // svt::IWizardPageController
+ virtual void initializePage() override;
+ virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override;
+ virtual bool canAdvance() const override;
+
+ void SetRoadmapStateValue( bool _bDoEnable ) { m_abEnableRoadmap = _bDoEnable; }
+ bool GetRoadmapStateValue() const { return m_abEnableRoadmap; }
+
+ protected:
+ /// default implementation: call FillItemSet, call prepareLeave,
+ virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override;
+ /// default implementation: call implInitControls with the given item set and _bSaveValue = sal_False
+ virtual void Reset(const SfxItemSet* _rCoreAttrs) override;
+ /// default implementation: call implInitControls with the given item set and _bSaveValue = sal_True
+ virtual void ActivatePage(const SfxItemSet& _rSet) override;
+
+ // BuilderPage overridables
+ virtual void Activate() override;
+
+ protected:
+ virtual void callModifiedHdl(weld::Widget* /*pControl*/ = nullptr) { m_aModifiedHandler.Call(this); }
+
+ /// called from within DeactivatePage. The page is allowed to be deactivated if this method returns sal_True
+ virtual bool prepareLeave() { return true; }
+
+ /** called from within Reset and ActivatePage, use to initialize the controls with the items from the given set
+ @param _bSaveValue if set to sal_True, the implementation should call SaveValue on all relevant controls
+ */
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue);
+
+ /// analyze the invalid and the readonly flag which may be present in the set
+ static void getFlags(const SfxItemSet& _rSet, bool& _rValid, bool& _rReadonly);
+
+ /** will be called inside <method>implInitControls</method> to save the value if necessary
+ @param _rControlList
+ The list must be filled with the controls.
+ It is not allowed to clear the list before pushing data into it.
+ */
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) = 0;
+
+ /** will be called inside <method>implInitControls</method> to disable if necessary
+ @param _rControlList
+ The list must be filled with the controls.
+ It is not allowed to clear the list before pushing data into it.
+ */
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) = 0;
+
+ public:
+ /** fills the Boolean value into the item set when the value changed.
+ @param _rSet
+ The item set where to put the new value into.
+ @param _pCheckBox
+ The check box which is checked.
+ @param _nID
+ The id in the itemset to set with the new value.
+ @param _bChangedSomething
+ <TRUE/> if something changed otherwise <FALSE/>
+ @param _bRevertValue
+ set to <TRUE/> if the display value should be reverted before putting it into the set
+ */
+ static void fillBool(SfxItemSet& _rSet, const weld::CheckButton* pCheckBox, sal_uInt16 _nID, bool bOptionalBool, bool& _bChangedSomething, bool _bRevertValue = false);
+
+ /** fills the int value into the item set when the value changed.
+ @param _rSet
+ The item set where to put the new value into.
+ @param _pEdit
+ The check box which is checked.
+ @param _nID
+ The id in the itemset to set with the new value.
+ @param _bChangedSomething
+ <TRUE/> if something changed otherwise <FALSE/>
+ */
+ static void fillInt32(SfxItemSet& _rSet,const weld::SpinButton* pEdit,sal_uInt16 _nID, bool& _bChangedSomething);
+
+ /** fills the String value into the item set when the value changed.
+ @param _rSet
+ The item set where to put the new value into.
+ @param _pEdit
+ The check box which is checked.
+ @param _nID
+ The id in the itemset to set with the new value.
+ @param _bChangedSomething
+ <TRUE/> if something changed otherwise <FALSE/>
+ */
+ static void fillString(SfxItemSet& _rSet,const weld::Entry* pEdit,sal_uInt16 _nID, bool& _bChangedSomething);
+ static void fillString(SfxItemSet& _rSet,const dbaui::OConnectionURLEdit* pEdit,sal_uInt16 _nID, bool& _bChangedSomething);
+
+ protected:
+ /** This link be used for controls where the tabpage does not need to take any special action when the control
+ is modified. The implementation just calls callModifiedHdl.
+ */
+ DECL_LINK(OnControlModified, weld::Widget*, void);
+ DECL_LINK(OnControlEntryModifyHdl, weld::Entry&, void);
+ DECL_LINK(OnControlSpinButtonModifyHdl, weld::SpinButton&, void);
+ DECL_LINK(OnControlModifiedButtonClick, weld::Toggleable&, void);
+ DECL_LINK(OnTestConnectionButtonClickHdl, weld::Button&, void);
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/adodatalinks.cxx b/dbaccess/source/ui/dlg/adodatalinks.cxx
new file mode 100644
index 000000000..82af63688
--- /dev/null
+++ b/dbaccess/source/ui/dlg/adodatalinks.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#if defined(_WIN32)
+// LO/windows.h conflict
+#undef WB_LEFT
+#undef WB_RIGHT
+#include <msdasc.h>
+
+#include <comphelper/scopeguard.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <systools/win32/comtools.hxx>
+#include <systools/win32/oleauto.hxx>
+
+#include <initguid.h>
+#include <adoid.h>
+#include <adoint.h>
+
+#include "adodatalinks.hxx"
+
+namespace {
+
+OUString PromptNew(sal_IntPtr hWnd)
+{
+ try
+ {
+ // Initialize COM
+ sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED);
+
+ // Instantiate DataLinks object.
+ sal::systools::COMReference<IDataSourceLocator> dlPrompt;
+ dlPrompt.CoCreateInstance(CLSID_DataLinks, //clsid -- Data Links UI
+ nullptr, //pUnkOuter
+ CLSCTX_INPROC_SERVER); //dwClsContext
+
+ sal::systools::ThrowIfFailed(dlPrompt->put_hWnd(hWnd), "put_hWnd failed");
+
+ // Prompt for connection information.
+ sal::systools::COMReference<IDispatch> piDispatch;
+ sal::systools::ThrowIfFailed(dlPrompt->PromptNew(&piDispatch), "PromptNew failed");
+ sal::systools::COMReference<ADOConnection> piTmpConnection(piDispatch,
+ sal::systools::COM_QUERY_THROW);
+
+ sal::systools::BStr _result;
+ sal::systools::ThrowIfFailed(piTmpConnection->get_ConnectionString(&_result),
+ "get_ConnectionString failed");
+
+ return OUString(_result);
+ }
+ catch (const sal::systools::ComError&)
+ {
+ return OUString();
+ }
+}
+
+OUString PromptEdit(sal_IntPtr hWnd, OUString const & connstr)
+{
+ try
+ {
+ // Initialize COM
+ sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED);
+
+ sal::systools::COMReference<ADOConnection> piTmpConnection;
+ piTmpConnection.CoCreateInstance(CLSID_CADOConnection, nullptr, CLSCTX_INPROC_SERVER);
+
+ sal::systools::ThrowIfFailed(
+ piTmpConnection->put_ConnectionString(sal::systools::BStr(connstr)),
+ "put_ConnectionString failed");
+
+ // Instantiate DataLinks object.
+ sal::systools::COMReference<IDataSourceLocator> dlPrompt;
+ dlPrompt.CoCreateInstance(CLSID_DataLinks, //clsid -- Data Links UI
+ nullptr, //pUnkOuter
+ CLSCTX_INPROC_SERVER); //dwClsContext
+
+ sal::systools::ThrowIfFailed(dlPrompt->put_hWnd(hWnd), "put_hWnd failed");
+
+ try
+ {
+ // Prompt for connection information.
+ IDispatch* piDispatch = piTmpConnection.get();
+ VARIANT_BOOL pbSuccess;
+ sal::systools::ThrowIfFailed(dlPrompt->PromptEdit(&piDispatch, &pbSuccess),
+ "PromptEdit failed");
+ if (!pbSuccess) //if user press cancel then sal_False == pbSuccess
+ return connstr;
+ }
+ catch (const sal::systools::ComError&)
+ {
+ // Prompt for new connection information.
+ sal::systools::COMReference<IDispatch> piDispatch;
+ sal::systools::ThrowIfFailed(dlPrompt->PromptNew(&piDispatch), "PromptNew failed");
+ piTmpConnection.set(piDispatch, sal::systools::COM_QUERY_THROW);
+ }
+
+ sal::systools::BStr _result;
+ sal::systools::ThrowIfFailed(piTmpConnection->get_ConnectionString(&_result),
+ "get_ConnectionString failed");
+
+ return OUString(_result);
+ }
+ catch (const sal::systools::ComError&)
+ {
+ return connstr;
+ }
+}
+
+}
+
+OUString getAdoDatalink(sal_IntPtr hWnd,OUString const & oldLink)
+{
+ OUString dataLink;
+ if (!oldLink.isEmpty())
+ {
+ dataLink=PromptEdit(hWnd,oldLink);
+ }
+ else
+ dataLink=PromptNew(hWnd);
+ return dataLink;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/adodatalinks.hxx b/dbaccess/source/ui/dlg/adodatalinks.hxx
new file mode 100644
index 000000000..6b753f62e
--- /dev/null
+++ b/dbaccess/source/ui/dlg/adodatalinks.hxx
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+OUString getAdoDatalink(sal_IntPtr hWnd, OUString const& oldLink);
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/adtabdlg.cxx b/dbaccess/source/ui/dlg/adtabdlg.cxx
new file mode 100644
index 000000000..809b483cd
--- /dev/null
+++ b/dbaccess/source/ui/dlg/adtabdlg.cxx
@@ -0,0 +1,467 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <adtabdlg.hxx>
+#include <tools/diagnose_ex.h>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <imageprovider.hxx>
+#include <comphelper/containermultiplexer.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <algorithm>
+
+// slot ids
+using namespace dbaui;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace dbtools;
+
+TableObjectListFacade::~TableObjectListFacade()
+{
+}
+
+namespace {
+
+class TableListFacade : public ::cppu::BaseMutex
+ , public TableObjectListFacade
+ , public ::comphelper::OContainerListener
+{
+ OTableTreeListBox& m_rTableList;
+ Reference< XConnection > m_xConnection;
+ ::rtl::Reference< comphelper::OContainerListenerAdapter>
+ m_pContainerListener;
+ bool m_bAllowViews;
+
+public:
+ TableListFacade(OTableTreeListBox& _rTableList, const Reference< XConnection >& _rxConnection)
+ : ::comphelper::OContainerListener(m_aMutex)
+ ,m_rTableList( _rTableList )
+ ,m_xConnection( _rxConnection )
+ ,m_bAllowViews(true)
+ {
+ }
+ virtual ~TableListFacade() override;
+
+private:
+ virtual void updateTableObjectList( bool _bAllowViews ) override;
+ virtual OUString getSelectedName( OUString& _out_rAliasName ) const override;
+ virtual bool isLeafSelected() const override;
+ // OContainerListener
+ virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override;
+};
+
+}
+
+TableListFacade::~TableListFacade()
+{
+ if ( m_pContainerListener.is() )
+ m_pContainerListener->dispose();
+}
+
+OUString TableListFacade::getSelectedName( OUString& _out_rAliasName ) const
+{
+ weld::TreeView& rTableList = m_rTableList.GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTableList.make_iterator());
+
+ if (!rTableList.get_selected(xEntry.get()))
+ return OUString();
+
+ OUString aCatalog, aSchema, aTableName;
+ std::unique_ptr<weld::TreeIter> xSchema(rTableList.make_iterator(xEntry.get()));
+ if (rTableList.iter_parent(*xSchema))
+ {
+ auto xAll = m_rTableList.getAllObjectsEntry();
+ if (!xAll || !xSchema->equal(*xAll))
+ {
+ std::unique_ptr<weld::TreeIter> xCatalog(rTableList.make_iterator(xSchema.get()));
+ if (rTableList.iter_parent(*xCatalog))
+ {
+ if (!xAll || !xCatalog->equal(*xAll))
+ aCatalog = rTableList.get_text(*xCatalog, 0);
+ }
+ aSchema = rTableList.get_text(*xSchema, 0);
+ }
+ }
+ aTableName = rTableList.get_text(*xEntry, 0);
+
+ OUString aComposedName;
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta( m_xConnection->getMetaData(), UNO_SET_THROW );
+ if ( aCatalog.isEmpty()
+ && !aSchema.isEmpty()
+ && xMeta->supportsCatalogsInDataManipulation()
+ && !xMeta->supportsSchemasInDataManipulation() )
+ {
+ aCatalog = aSchema;
+ aSchema.clear();
+ }
+
+ aComposedName = ::dbtools::composeTableName(
+ xMeta, aCatalog, aSchema, aTableName, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ _out_rAliasName = aTableName;
+ return aComposedName;
+}
+
+void TableListFacade::_elementInserted( const container::ContainerEvent& /*_rEvent*/ )
+{
+ updateTableObjectList(m_bAllowViews);
+}
+
+void TableListFacade::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ )
+{
+ updateTableObjectList(m_bAllowViews);
+}
+
+void TableListFacade::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ )
+{
+}
+
+void TableListFacade::updateTableObjectList( bool _bAllowViews )
+{
+ m_bAllowViews = _bAllowViews;
+ weld::TreeView& rTableList = m_rTableList.GetWidget();
+ rTableList.clear();
+ try
+ {
+ Reference< XTablesSupplier > xTableSupp( m_xConnection, UNO_QUERY_THROW );
+
+ Reference< XViewsSupplier > xViewSupp;
+ Reference< XNameAccess > xTables, xViews;
+ Sequence< OUString > sTables, sViews;
+
+ xTables = xTableSupp->getTables();
+ if ( xTables.is() )
+ {
+ if ( !m_pContainerListener.is() )
+ {
+ Reference< XContainer> xContainer(xTables,uno::UNO_QUERY);
+ if ( xContainer.is() )
+ m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
+ }
+ sTables = xTables->getElementNames();
+ }
+
+ xViewSupp.set( xTableSupp, UNO_QUERY );
+ if ( xViewSupp.is() )
+ {
+ xViews = xViewSupp->getViews();
+ if ( xViews.is() )
+ sViews = xViews->getElementNames();
+ }
+
+ // if no views are allowed remove the views also out the table name filter
+ if ( !_bAllowViews )
+ {
+ const OUString* pTableBegin = sTables.getConstArray();
+ const OUString* pTableEnd = pTableBegin + sTables.getLength();
+ std::vector< OUString > aTables(pTableBegin,pTableEnd);
+
+ const OUString* pViewBegin = sViews.getConstArray();
+ const OUString* pViewEnd = pViewBegin + sViews.getLength();
+ ::comphelper::UStringMixEqual aEqualFunctor;
+ for(;pViewBegin != pViewEnd;++pViewBegin)
+ aTables.erase(std::remove_if(aTables.begin(),aTables.end(),
+ [&aEqualFunctor, pViewBegin](const OUString& lhs)
+ { return aEqualFunctor(lhs, *pViewBegin); } )
+ , aTables.end());
+ sTables = Sequence< OUString>(aTables.data(), aTables.size());
+ sViews = Sequence< OUString>();
+ }
+
+ m_rTableList.UpdateTableList( m_xConnection, sTables, sViews );
+
+ std::unique_ptr<weld::TreeIter> xEntry(rTableList.make_iterator());
+ bool bEntry = rTableList.get_iter_first(*xEntry);
+ while (bEntry && rTableList.iter_has_child(*xEntry))
+ {
+ rTableList.expand_row(*xEntry);
+ bEntry = rTableList.iter_next(*xEntry);
+ }
+ if (bEntry)
+ rTableList.select(*xEntry);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+bool TableListFacade::isLeafSelected() const
+{
+ weld::TreeView& rTableList = m_rTableList.GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTableList.make_iterator());
+ const bool bEntry = rTableList.get_selected(xEntry.get());
+ return bEntry && !rTableList.iter_has_child(*xEntry);
+}
+
+namespace {
+
+class QueryListFacade : public ::cppu::BaseMutex
+ , public TableObjectListFacade
+ , public ::comphelper::OContainerListener
+{
+ weld::TreeView& m_rQueryList;
+ Reference< XConnection > m_xConnection;
+ ::rtl::Reference< comphelper::OContainerListenerAdapter>
+ m_pContainerListener;
+
+public:
+ QueryListFacade( weld::TreeView& _rQueryList, const Reference< XConnection >& _rxConnection )
+ : ::comphelper::OContainerListener(m_aMutex)
+ ,m_rQueryList( _rQueryList )
+ ,m_xConnection( _rxConnection )
+ {
+ }
+ virtual ~QueryListFacade() override;
+
+private:
+ virtual void updateTableObjectList( bool _bAllowViews ) override;
+ virtual OUString getSelectedName( OUString& _out_rAliasName ) const override;
+ virtual bool isLeafSelected() const override;
+ // OContainerListener
+ virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override;
+};
+
+}
+
+QueryListFacade::~QueryListFacade()
+{
+ if ( m_pContainerListener.is() )
+ m_pContainerListener->dispose();
+}
+
+void QueryListFacade::_elementInserted( const container::ContainerEvent& _rEvent )
+{
+ OUString sName;
+ if ( _rEvent.Accessor >>= sName )
+ {
+ OUString aQueryImage(ImageProvider::getDefaultImageResourceID(css::sdb::application::DatabaseObject::QUERY));
+ m_rQueryList.append("", sName, aQueryImage);
+ }
+}
+
+void QueryListFacade::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ )
+{
+ updateTableObjectList(true);
+}
+
+void QueryListFacade::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ )
+{
+}
+
+void QueryListFacade::updateTableObjectList( bool /*_bAllowViews*/ )
+{
+ m_rQueryList.clear();
+ try
+ {
+ OUString aQueryImage(ImageProvider::getDefaultImageResourceID(css::sdb::application::DatabaseObject::QUERY));
+
+ Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSuppQueries->getQueries(), UNO_SET_THROW );
+ if ( !m_pContainerListener.is() )
+ {
+ Reference< XContainer> xContainer(xQueries,UNO_QUERY_THROW);
+ m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
+ }
+ const Sequence< OUString > aQueryNames = xQueries->getElementNames();
+
+ for ( auto const & name : aQueryNames )
+ m_rQueryList.append("", name, aQueryImage);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OUString QueryListFacade::getSelectedName( OUString& _out_rAliasName ) const
+{
+ OUString sSelected;
+ std::unique_ptr<weld::TreeIter> xEntry(m_rQueryList.make_iterator());
+ const bool bEntry = m_rQueryList.get_selected(xEntry.get());
+ if (bEntry)
+ sSelected = _out_rAliasName = m_rQueryList.get_text(*xEntry, 0);
+ return sSelected;
+}
+
+bool QueryListFacade::isLeafSelected() const
+{
+ std::unique_ptr<weld::TreeIter> xEntry(m_rQueryList.make_iterator());
+ const bool bEntry = m_rQueryList.get_selected(xEntry.get());
+ return bEntry && !m_rQueryList.iter_has_child(*xEntry);
+
+}
+
+OAddTableDlg::OAddTableDlg(weld::Window* pParent, IAddTableDialogContext& _rContext)
+ : GenericDialogController(pParent, "dbaccess/ui/tablesjoindialog.ui", "TablesJoinDialog")
+ , m_rContext(_rContext)
+ , m_xCaseTables(m_xBuilder->weld_radio_button("tables"))
+ , m_xCaseQueries(m_xBuilder->weld_radio_button("queries"))
+ // false means: do not show any buttons
+ , m_xTableList(new OTableTreeListBox(m_xBuilder->weld_tree_view("tablelist"), false))
+ , m_xQueryList(m_xBuilder->weld_tree_view("querylist"))
+ , m_xAddButton(m_xBuilder->weld_button("add"))
+ , m_xCloseButton(m_xBuilder->weld_button("close"))
+{
+ weld::TreeView& rTableList = m_xTableList->GetWidget();
+ Size aSize(rTableList.get_approximate_digit_width() * 23,
+ rTableList.get_height_rows(15));
+ rTableList.set_size_request(aSize.Width(), aSize.Height());
+ m_xQueryList->set_size_request(aSize.Width(), aSize.Height());
+
+ m_xCaseTables->connect_toggled(LINK(this, OAddTableDlg, OnTypeSelected));
+ m_xAddButton->connect_clicked( LINK( this, OAddTableDlg, AddClickHdl ) );
+ m_xCloseButton->connect_clicked( LINK( this, OAddTableDlg, CloseClickHdl ) );
+ rTableList.connect_row_activated( LINK( this, OAddTableDlg, TableListDoubleClickHdl ) );
+ rTableList.connect_changed( LINK( this, OAddTableDlg, TableListSelectHdl ) );
+ m_xQueryList->connect_row_activated( LINK( this, OAddTableDlg, TableListDoubleClickHdl ) );
+ m_xQueryList->connect_changed( LINK( this, OAddTableDlg, TableListSelectHdl ) );
+
+ rTableList.set_selection_mode(SelectionMode::Single);
+ m_xTableList->SuppressEmptyFolders();
+
+ m_xQueryList->set_selection_mode(SelectionMode::Single);
+
+ if ( !m_rContext.allowQueries() )
+ {
+ m_xCaseTables->hide();
+ m_xCaseQueries->hide();
+ }
+
+ m_xDialog->set_title(getDialogTitleForContext(m_rContext));
+}
+
+OAddTableDlg::~OAddTableDlg()
+{
+}
+
+void OAddTableDlg::impl_switchTo( ObjectList _eList )
+{
+ switch ( _eList )
+ {
+ case Tables:
+ m_xTableList->GetWidget().show(); m_xCaseTables->set_active(true);
+ m_xQueryList->hide(); m_xCaseQueries->set_active(false);
+ m_xCurrentList.reset( new TableListFacade( *m_xTableList, m_rContext.getConnection() ) );
+ m_xTableList->GetWidget().grab_focus();
+ break;
+
+ case Queries:
+ m_xTableList->GetWidget().hide(); m_xCaseTables->set_active(false);
+ m_xQueryList->show(); m_xCaseQueries->set_active(true);
+ m_xCurrentList.reset( new QueryListFacade( *m_xQueryList, m_rContext.getConnection() ) );
+ m_xQueryList->grab_focus();
+ break;
+ }
+ m_xCurrentList->updateTableObjectList( m_rContext.allowViews() );
+}
+
+void OAddTableDlg::Update()
+{
+ if (!m_xCurrentList)
+ impl_switchTo( Tables );
+ else
+ m_xCurrentList->updateTableObjectList( m_rContext.allowViews() );
+}
+
+IMPL_LINK_NOARG( OAddTableDlg, AddClickHdl, weld::Button&, void )
+{
+ TableListDoubleClickHdl(m_xTableList->GetWidget());
+}
+
+IMPL_LINK_NOARG(OAddTableDlg, TableListDoubleClickHdl, weld::TreeView&, bool)
+{
+ if ( impl_isAddAllowed() )
+ {
+ if ( m_xCurrentList->isLeafSelected() )
+ {
+ OUString sSelectedName, sAliasName;
+ sSelectedName = m_xCurrentList->getSelectedName( sAliasName );
+
+ m_rContext.addTableWindow( sSelectedName, sAliasName );
+ }
+ if ( !impl_isAddAllowed() )
+ m_xDialog->response(RET_CLOSE);
+ }
+ return true;
+}
+
+IMPL_LINK_NOARG( OAddTableDlg, TableListSelectHdl, weld::TreeView&, void )
+{
+ m_xAddButton->set_sensitive( m_xCurrentList->isLeafSelected() );
+}
+
+IMPL_LINK_NOARG( OAddTableDlg, CloseClickHdl, weld::Button&, void )
+{
+ m_xDialog->response(RET_CLOSE);
+}
+
+IMPL_LINK_NOARG(OAddTableDlg, OnTypeSelected, weld::Toggleable&, void)
+{
+ if ( m_xCaseTables->get_active() )
+ impl_switchTo( Tables );
+ else
+ impl_switchTo( Queries );
+}
+
+void OAddTableDlg::OnClose()
+{
+ m_rContext.onWindowClosing();
+}
+
+bool OAddTableDlg::impl_isAddAllowed()
+{
+ return m_rContext.allowAddition();
+}
+
+OUString OAddTableDlg::getDialogTitleForContext( IAddTableDialogContext const & _rContext )
+{
+ OUString sTitle;
+
+ if ( _rContext.allowQueries() )
+ sTitle = DBA_RES( STR_ADD_TABLE_OR_QUERY );
+ else
+ sTitle = DBA_RES( STR_ADD_TABLES );
+
+ return sTitle;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/advancedsettings.cxx b/dbaccess/source/ui/dlg/advancedsettings.cxx
new file mode 100644
index 000000000..40964305a
--- /dev/null
+++ b/dbaccess/source/ui/dlg/advancedsettings.cxx
@@ -0,0 +1,472 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include "advancedsettings.hxx"
+#include <advancedsettingsdlg.hxx>
+#include <dsitems.hxx>
+#include "DbAdminImpl.hxx"
+#include "DriverSettings.hxx"
+#include "optionalboolitem.hxx"
+
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdbc::XDriver;
+
+ // SpecialSettingsPage
+ struct BooleanSettingDesc
+ {
+ std::unique_ptr<weld::CheckButton>& xControl; // the dialog's control which displays this setting
+ OString sControlId; // the widget name of the control in the .ui
+ sal_uInt16 nItemId; // the ID of the item (in an SfxItemSet) which corresponds to this setting
+ bool bInvertedDisplay; // true if and only if the checkbox is checked when the item is sal_False, and vice versa
+ bool bOptionalBool; // type is OptionalBool
+ };
+
+ // SpecialSettingsPage
+ SpecialSettingsPage::SpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs, const DataSourceMetaData& _rDSMeta)
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/specialsettingspage.ui", "SpecialSettingsPage", _rCoreAttrs)
+ , m_aBooleanSettings {
+ { m_xIsSQL92Check, "usesql92", DSID_SQL92CHECK, false, false },
+ { m_xAppendTableAlias, "append", DSID_APPEND_TABLE_ALIAS, false, false },
+ { m_xAsBeforeCorrelationName, "useas", DSID_AS_BEFORE_CORRNAME, false, false },
+ { m_xEnableOuterJoin, "useoj", DSID_ENABLEOUTERJOIN, false, false },
+ { m_xIgnoreDriverPrivileges, "ignoreprivs", DSID_IGNOREDRIVER_PRIV, false, false },
+ { m_xParameterSubstitution, "replaceparams", DSID_PARAMETERNAMESUBST, false, false },
+ { m_xSuppressVersionColumn, "displayver", DSID_SUPPRESSVERSIONCL, true, false },
+ { m_xCatalog, "usecatalogname", DSID_CATALOG, false, false },
+ { m_xSchema, "useschemaname", DSID_SCHEMA, false, false },
+ { m_xIndexAppendix, "createindex", DSID_INDEXAPPENDIX, false, false },
+ { m_xDosLineEnds, "eol", DSID_DOSLINEENDS, false, false },
+ { m_xCheckRequiredFields, "inputchecks", DSID_CHECK_REQUIRED_FIELDS, false, false },
+ { m_xIgnoreCurrency, "ignorecurrency", DSID_IGNORECURRENCY, false, false },
+ { m_xEscapeDateTime, "useodbcliterals", DSID_ESCAPE_DATETIME, false, false },
+ { m_xPrimaryKeySupport, "primarykeys", DSID_PRIMARY_KEY_SUPPORT, false, false },
+ { m_xRespectDriverResultSetType, "resulttype", DSID_RESPECTRESULTSETTYPE, false, false } }
+ , m_bHasBooleanComparisonMode( _rDSMeta.getFeatureSet().has( DSID_BOOLEANCOMPARISON ) )
+ , m_bHasMaxRowScan( _rDSMeta.getFeatureSet().has( DSID_MAX_ROW_SCAN ) )
+ {
+ const FeatureSet& rFeatures( _rDSMeta.getFeatureSet() );
+ // create all the check boxes for the boolean settings
+ for (auto & booleanSetting : m_aBooleanSettings)
+ {
+ sal_uInt16 nItemId = booleanSetting.nItemId;
+ if ( rFeatures.has( nItemId ) )
+ {
+ // check whether this must be a tristate check box
+ const SfxPoolItem& rItem = _rCoreAttrs.Get(nItemId);
+ booleanSetting.bOptionalBool = dynamic_cast<const OptionalBoolItem*>(&rItem) != nullptr;
+ booleanSetting.xControl = m_xBuilder->weld_check_button(booleanSetting.sControlId);
+ if (booleanSetting.bOptionalBool)
+ booleanSetting.xControl->connect_toggled(LINK(this, SpecialSettingsPage, OnTriStateToggleHdl));
+ else
+ booleanSetting.xControl->connect_toggled(LINK(this, SpecialSettingsPage, OnToggleHdl));
+ booleanSetting.xControl->show();
+ }
+ }
+
+ // create the controls for the boolean comparison mode
+ if ( m_bHasBooleanComparisonMode )
+ {
+ m_xBooleanComparisonModeLabel = m_xBuilder->weld_label("comparisonft");
+ m_xBooleanComparisonMode = m_xBuilder->weld_combo_box("comparison");
+ m_xBooleanComparisonMode->connect_changed(LINK(this, SpecialSettingsPage, BooleanComparisonSelectHdl));
+ m_xBooleanComparisonModeLabel->show();
+ m_xBooleanComparisonMode->show();
+ }
+ // create the controls for the max row scan
+ if ( m_bHasMaxRowScan )
+ {
+ m_xMaxRowScanLabel = m_xBuilder->weld_label("rowsft");
+ m_xMaxRowScan = m_xBuilder->weld_spin_button("rows");
+ m_xMaxRowScan->connect_value_changed(LINK(this, OGenericAdministrationPage, OnControlSpinButtonModifyHdl));
+ m_xMaxRowScanLabel->show();
+ m_xMaxRowScan->show();
+ }
+ }
+
+ IMPL_LINK(SpecialSettingsPage, OnTriStateToggleHdl, weld::Toggleable&, rToggle, void)
+ {
+ auto eOldState = m_aTriStates[&rToggle];
+ switch (eOldState)
+ {
+ case TRISTATE_INDET:
+ rToggle.set_state(TRISTATE_FALSE);
+ break;
+ case TRISTATE_TRUE:
+ rToggle.set_state(TRISTATE_INDET);
+ break;
+ case TRISTATE_FALSE:
+ rToggle.set_state(TRISTATE_TRUE);
+ break;
+ }
+ m_aTriStates[&rToggle] = rToggle.get_state();
+ OnToggleHdl(rToggle);
+ }
+
+ IMPL_LINK(SpecialSettingsPage, OnToggleHdl, weld::Toggleable&, rBtn, void)
+ {
+ if (&rBtn == m_xAppendTableAlias.get() && m_xAsBeforeCorrelationName)
+ {
+ // make m_xAsBeforeCorrelationName depend on m_xAppendTableAlias
+ m_xAsBeforeCorrelationName->set_sensitive(m_xAppendTableAlias->get_active());
+ }
+ OnControlModifiedButtonClick(rBtn);
+ }
+
+ IMPL_LINK(SpecialSettingsPage, BooleanComparisonSelectHdl, weld::ComboBox&, rControl, void)
+ {
+ callModifiedHdl(&rControl);
+ }
+
+ SpecialSettingsPage::~SpecialSettingsPage()
+ {
+ }
+
+ void SpecialSettingsPage::fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList )
+ {
+ if ( m_bHasBooleanComparisonMode )
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xBooleanComparisonModeLabel.get()));
+ }
+ if ( m_bHasMaxRowScan )
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xMaxRowScanLabel.get()));
+ }
+ }
+
+ void SpecialSettingsPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ for (auto const& booleanSetting : m_aBooleanSettings)
+ {
+ if (booleanSetting.xControl)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(booleanSetting.xControl.get()));
+ }
+ }
+
+ if ( m_bHasBooleanComparisonMode )
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xBooleanComparisonMode.get()));
+ if ( m_bHasMaxRowScan )
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xMaxRowScan.get()));
+ }
+
+ void SpecialSettingsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags( _rSet, bValid, bReadonly );
+
+ if ( !bValid )
+ {
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+ return;
+ }
+
+ m_aTriStates.clear();
+
+ // the boolean items
+ for (auto const& booleanSetting : m_aBooleanSettings)
+ {
+ if (!booleanSetting.xControl)
+ continue;
+
+ bool bTriState = false;
+
+ std::optional<bool> aValue;
+
+ const SfxPoolItem* pItem = _rSet.GetItem<SfxPoolItem>(booleanSetting.nItemId);
+ if (const SfxBoolItem *pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) )
+ {
+ aValue = pBoolItem->GetValue();
+ }
+ else if (const OptionalBoolItem *pOptionalItem = dynamic_cast<const OptionalBoolItem*>( pItem) )
+ {
+ aValue = pOptionalItem->GetFullValue();
+ bTriState = true;
+ }
+ else
+ OSL_FAIL( "SpecialSettingsPage::implInitControls: unknown boolean item type!" );
+
+ if ( !aValue )
+ {
+ booleanSetting.xControl->set_state(TRISTATE_INDET);
+ }
+ else
+ {
+ bool bValue = *aValue;
+ if ( booleanSetting.bInvertedDisplay )
+ bValue = !bValue;
+ booleanSetting.xControl->set_active(bValue);
+ }
+ if (bTriState)
+ m_aTriStates[booleanSetting.xControl.get()] = booleanSetting.xControl->get_state();
+ }
+
+ if (m_xAppendTableAlias && m_xAsBeforeCorrelationName)
+ {
+ // make m_xAsBeforeCorrelationName depend on m_xAppendTableAlias
+ m_xAsBeforeCorrelationName->set_sensitive(m_xAppendTableAlias->get_active());
+ }
+
+ // the non-boolean items
+ if ( m_bHasBooleanComparisonMode )
+ {
+ const SfxInt32Item* pBooleanComparison = _rSet.GetItem<SfxInt32Item>(DSID_BOOLEANCOMPARISON);
+ m_xBooleanComparisonMode->set_active(static_cast<sal_uInt16>(pBooleanComparison->GetValue()));
+ }
+
+ if ( m_bHasMaxRowScan )
+ {
+ const SfxInt32Item* pMaxRowScan = _rSet.GetItem<SfxInt32Item>(DSID_MAX_ROW_SCAN);
+ m_xMaxRowScan->set_value(pMaxRowScan->GetValue());
+ }
+
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ bool SpecialSettingsPage::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = false;
+
+ // the boolean items
+ for (auto const& booleanSetting : m_aBooleanSettings)
+ {
+ if (!booleanSetting.xControl)
+ continue;
+ fillBool(*_rSet, booleanSetting.xControl.get(), booleanSetting.nItemId, booleanSetting.bOptionalBool, bChangedSomething, booleanSetting.bInvertedDisplay);
+ }
+
+ // the non-boolean items
+ if ( m_bHasBooleanComparisonMode )
+ {
+ if (m_xBooleanComparisonMode->get_value_changed_from_saved())
+ {
+ _rSet->Put(SfxInt32Item(DSID_BOOLEANCOMPARISON, m_xBooleanComparisonMode->get_active()));
+ bChangedSomething = true;
+ }
+ }
+ if ( m_bHasMaxRowScan )
+ {
+ fillInt32(*_rSet,m_xMaxRowScan.get(),DSID_MAX_ROW_SCAN,bChangedSomething);
+ }
+ return bChangedSomething;
+ }
+
+ // GeneratedValuesPage
+ GeneratedValuesPage::GeneratedValuesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs)
+ : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/generatedvaluespage.ui", "GeneratedValuesPage", _rCoreAttrs)
+ , m_xAutoRetrievingEnabled(m_xBuilder->weld_check_button("autoretrieve"))
+ , m_xGrid(m_xBuilder->weld_widget("grid"))
+ , m_xAutoIncrementLabel(m_xBuilder->weld_label("statementft"))
+ , m_xAutoIncrement(m_xBuilder->weld_entry("statement"))
+ , m_xAutoRetrievingLabel(m_xBuilder->weld_label("queryft"))
+ , m_xAutoRetrieving(m_xBuilder->weld_entry("query"))
+ {
+ m_xAutoRetrievingEnabled->connect_toggled(LINK(this, GeneratedValuesPage, OnAutoToggleHdl));
+ m_xAutoIncrement->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ m_xAutoRetrieving->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl));
+ }
+
+ IMPL_LINK(GeneratedValuesPage, OnAutoToggleHdl, weld::Toggleable&, rBtn, void)
+ {
+ m_xGrid->set_sensitive(rBtn.get_active());
+ OnControlModifiedButtonClick(rBtn);
+ }
+
+ GeneratedValuesPage::~GeneratedValuesPage()
+ {
+ }
+
+ void GeneratedValuesPage::fillWindows( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList )
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Widget>(m_xContainer.get()));
+ }
+
+ void GeneratedValuesPage::fillControls( std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList )
+ {
+ _rControlList.emplace_back( new OSaveValueWidgetWrapper<weld::Toggleable>( m_xAutoRetrievingEnabled.get() ) );
+ _rControlList.emplace_back( new OSaveValueWidgetWrapper<weld::Entry>( m_xAutoIncrement.get() ) );
+ _rControlList.emplace_back( new OSaveValueWidgetWrapper<weld::Entry>( m_xAutoRetrieving.get() ) );
+ }
+
+ void GeneratedValuesPage::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue )
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ // collect the items
+ const SfxStringItem* pAutoIncrementItem = _rSet.GetItem<SfxStringItem>(DSID_AUTOINCREMENTVALUE);
+ const SfxStringItem* pAutoRetrieveValueItem = _rSet.GetItem<SfxStringItem>(DSID_AUTORETRIEVEVALUE);
+ const SfxBoolItem* pAutoRetrieveEnabledItem = _rSet.GetItem<SfxBoolItem>(DSID_AUTORETRIEVEENABLED);
+
+ // forward the values to the controls
+ if (bValid)
+ {
+ bool bEnabled = pAutoRetrieveEnabledItem->GetValue();
+ m_xAutoRetrievingEnabled->set_active(bEnabled);
+
+ m_xAutoIncrement->set_text(pAutoIncrementItem->GetValue());
+ m_xAutoIncrement->save_value();
+ m_xAutoRetrieving->set_text(pAutoRetrieveValueItem->GetValue());
+ m_xAutoRetrieving->save_value();
+ }
+ OGenericAdministrationPage::implInitControls( _rSet, _bSaveValue );
+ }
+
+ bool GeneratedValuesPage::FillItemSet(SfxItemSet* _rSet)
+ {
+ bool bChangedSomething = false;
+
+ fillString( *_rSet, m_xAutoIncrement.get(), DSID_AUTOINCREMENTVALUE, bChangedSomething );
+ fillBool( *_rSet, m_xAutoRetrievingEnabled.get(), DSID_AUTORETRIEVEENABLED, false, bChangedSomething );
+ fillString( *_rSet, m_xAutoRetrieving.get(), DSID_AUTORETRIEVEVALUE, bChangedSomething );
+
+ return bChangedSomething;
+ }
+
+ // AdvancedSettingsDialog
+ AdvancedSettingsDialog::AdvancedSettingsDialog(weld::Window* pParent, SfxItemSet* _pItems,
+ const Reference< XComponentContext >& _rxContext, const Any& _aDataSourceName )
+ : SfxTabDialogController(pParent, "dbaccess/ui/advancedsettingsdialog.ui", "AdvancedSettingsDialog", _pItems)
+ {
+ m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxContext, m_xDialog.get(), pParent, this));
+ m_pImpl->setDataSourceOrName(_aDataSourceName);
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ m_pImpl->translateProperties(xDatasource, *_pItems);
+ SetInputSet(_pItems);
+ // propagate this set as our new input set and reset the example set
+ m_xExampleSet.reset(new SfxItemSet(*GetInputSetImpl()));
+
+ const OUString eType = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(*_pItems);
+
+ DataSourceMetaData aMeta( eType );
+ const FeatureSet& rFeatures( aMeta.getFeatureSet() );
+
+ // auto-generated values?
+ if (rFeatures.supportsGeneratedValues())
+ AddTabPage("generated", ODriversSettings::CreateGeneratedValuesPage, nullptr);
+ else
+ RemoveTabPage("generated");
+
+ // any "special settings"?
+ if (rFeatures.supportsAnySpecialSetting())
+ AddTabPage("special", ODriversSettings::CreateSpecialSettingsPage, nullptr);
+ else
+ RemoveTabPage("special");
+
+ // remove the reset button - it's meaning is much too ambiguous in this dialog
+ RemoveResetButton();
+ }
+
+ AdvancedSettingsDialog::~AdvancedSettingsDialog()
+ {
+ SetInputSet(nullptr);
+ }
+
+ bool AdvancedSettingsDialog::doesHaveAnyAdvancedSettings( const OUString& _sURL )
+ {
+ DataSourceMetaData aMeta( _sURL );
+ const FeatureSet& rFeatures( aMeta.getFeatureSet() );
+ return rFeatures.supportsGeneratedValues() || rFeatures.supportsAnySpecialSetting();
+ }
+
+ short AdvancedSettingsDialog::Ok()
+ {
+ short nRet = SfxTabDialogController::Ok();
+ if ( nRet == RET_OK )
+ {
+ m_xExampleSet->Put(*GetOutputItemSet());
+ m_pImpl->saveChanges(*m_xExampleSet);
+ }
+ return nRet;
+ }
+
+ void AdvancedSettingsDialog::PageCreated(const OString& rId, SfxTabPage& _rPage)
+ {
+ // register ourself as modified listener
+ static_cast<OGenericAdministrationPage&>(_rPage).SetServiceFactory( getORB() );
+ static_cast<OGenericAdministrationPage&>(_rPage).SetAdminDialog(this,this);
+ SfxTabDialogController::PageCreated(rId, _rPage);
+ }
+
+ const SfxItemSet* AdvancedSettingsDialog::getOutputSet() const
+ {
+ return m_xExampleSet.get();
+ }
+
+ SfxItemSet* AdvancedSettingsDialog::getWriteOutputSet()
+ {
+ return m_xExampleSet.get();
+ }
+
+ std::pair< Reference< XConnection >, bool > AdvancedSettingsDialog::createConnection()
+ {
+ return m_pImpl->createConnection();
+ }
+
+ Reference< XComponentContext > AdvancedSettingsDialog::getORB() const
+ {
+ return m_pImpl->getORB();
+ }
+
+ Reference< XDriver > AdvancedSettingsDialog::getDriver()
+ {
+ return m_pImpl->getDriver();
+ }
+
+ OUString AdvancedSettingsDialog::getDatasourceType(const SfxItemSet& _rSet) const
+ {
+ return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet);
+ }
+
+ void AdvancedSettingsDialog::clearPassword()
+ {
+ m_pImpl->clearPassword();
+ }
+
+ void AdvancedSettingsDialog::setTitle(const OUString& _sTitle)
+ {
+ m_xDialog->set_title(_sTitle);
+ }
+
+ void AdvancedSettingsDialog::enableConfirmSettings( bool ) {}
+
+ void AdvancedSettingsDialog::saveDatasource()
+ {
+ PrepareLeaveCurrentPage();
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/advancedsettings.hxx b/dbaccess/source/ui/dlg/advancedsettings.hxx
new file mode 100644
index 000000000..38f100612
--- /dev/null
+++ b/dbaccess/source/ui/dlg/advancedsettings.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "adminpages.hxx"
+#include <dsmeta.hxx>
+#include <vector>
+
+namespace dbaui
+{
+ struct BooleanSettingDesc;
+
+ // SpecialSettingsPage
+ // implements the "Special Settings" page of the advanced database settings
+ class SpecialSettingsPage final : public OGenericAdministrationPage
+ {
+ std::unique_ptr<weld::CheckButton> m_xIsSQL92Check;
+ std::unique_ptr<weld::CheckButton> m_xAppendTableAlias;
+ std::unique_ptr<weld::CheckButton> m_xAsBeforeCorrelationName;
+ std::unique_ptr<weld::CheckButton> m_xEnableOuterJoin;
+ std::unique_ptr<weld::CheckButton> m_xIgnoreDriverPrivileges;
+ std::unique_ptr<weld::CheckButton> m_xParameterSubstitution;
+ std::unique_ptr<weld::CheckButton> m_xSuppressVersionColumn;
+ std::unique_ptr<weld::CheckButton> m_xCatalog;
+ std::unique_ptr<weld::CheckButton> m_xSchema;
+ std::unique_ptr<weld::CheckButton> m_xIndexAppendix;
+ std::unique_ptr<weld::CheckButton> m_xDosLineEnds;
+ std::unique_ptr<weld::CheckButton> m_xCheckRequiredFields;
+ std::unique_ptr<weld::CheckButton> m_xIgnoreCurrency;
+ std::unique_ptr<weld::CheckButton> m_xEscapeDateTime;
+ std::unique_ptr<weld::CheckButton> m_xPrimaryKeySupport;
+ std::unique_ptr<weld::CheckButton> m_xRespectDriverResultSetType;
+
+ std::unique_ptr<weld::Label> m_xBooleanComparisonModeLabel;
+ std::unique_ptr<weld::ComboBox> m_xBooleanComparisonMode;
+
+ std::unique_ptr<weld::Label> m_xMaxRowScanLabel;
+ std::unique_ptr<weld::SpinButton> m_xMaxRowScan;
+
+ std::map<weld::Toggleable*, TriState> m_aTriStates;
+
+ std::vector< BooleanSettingDesc > m_aBooleanSettings;
+
+ bool m_bHasBooleanComparisonMode;
+ bool m_bHasMaxRowScan;
+
+ public:
+ DECL_LINK(OnToggleHdl, weld::Toggleable&, void);
+ DECL_LINK(OnTriStateToggleHdl, weld::Toggleable&, void);
+
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+
+ SpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs, const DataSourceMetaData& _rDSMeta);
+ virtual ~SpecialSettingsPage() override;
+
+ private:
+ // OGenericAdministrationPage overridables
+ virtual void implInitControls (const SfxItemSet& _rSet, bool _bSaveValue ) override;
+
+ // <method>OGenericAdministrationPage::fillControls</method>
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ // <method>OGenericAdministrationPage::fillWindows</method>
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ DECL_LINK(BooleanComparisonSelectHdl, weld::ComboBox&, void);
+ };
+
+ // GeneratedValuesPage
+ class GeneratedValuesPage final : public OGenericAdministrationPage
+ {
+ std::unique_ptr<weld::CheckButton> m_xAutoRetrievingEnabled;
+ std::unique_ptr<weld::Widget> m_xGrid;
+ std::unique_ptr<weld::Label> m_xAutoIncrementLabel;
+ std::unique_ptr<weld::Entry> m_xAutoIncrement;
+ std::unique_ptr<weld::Label> m_xAutoRetrievingLabel;
+ std::unique_ptr<weld::Entry> m_xAutoRetrieving;
+
+ public:
+ virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override;
+
+ GeneratedValuesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~GeneratedValuesPage() override;
+
+ private:
+ DECL_LINK(OnAutoToggleHdl, weld::Toggleable&, void);
+
+ // subclasses must override this, but it isn't pure virtual
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ // <method>OGenericAdministrationPage::fillControls</method>
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ // <method>OGenericAdministrationPage::fillWindows</method>
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dbadmin.cxx b/dbaccess/source/ui/dlg/dbadmin.cxx
new file mode 100644
index 000000000..c6ca46f75
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dbadmin.cxx
@@ -0,0 +1,433 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ConnectionPage.hxx"
+#include "DbAdminImpl.hxx"
+#include "DriverSettings.hxx"
+#include "adminpages.hxx"
+#include <dbadmin.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <dsitems.hxx>
+#include "dsnItem.hxx"
+#include "optionalboolitem.hxx"
+#include <stringlistitem.hxx>
+
+#include <unotools/confignode.hxx>
+
+namespace dbaui
+{
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::util;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+// ODbAdminDialog
+ODbAdminDialog::ODbAdminDialog(weld::Window* pParent,
+ SfxItemSet const * _pItems,
+ const Reference< XComponentContext >& _rxContext)
+ : SfxTabDialogController(pParent, "dbaccess/ui/admindialog.ui", "AdminDialog", _pItems)
+ , m_sMainPageID("advanced")
+{
+ m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxContext, m_xDialog.get(), pParent, this));
+
+ // add the initial tab page
+ AddTabPage(m_sMainPageID, OConnectionTabPage::Create, nullptr);
+
+ // remove the reset button - it's meaning is much too ambiguous in this dialog
+ RemoveResetButton();
+}
+
+ODbAdminDialog::~ODbAdminDialog()
+{
+ SetInputSet(nullptr);
+}
+
+short ODbAdminDialog::Ok()
+{
+ SfxTabDialogController::Ok();
+ return ( AR_LEAVE_MODIFIED == implApplyChanges() ) ? RET_OK : RET_CANCEL;
+ // TODO : AR_ERROR is not handled correctly, we always close the dialog here
+}
+
+void ODbAdminDialog::PageCreated(const OString& rId, SfxTabPage& _rPage)
+{
+ // register ourself as modified listener
+ static_cast<OGenericAdministrationPage&>(_rPage).SetServiceFactory( getORB() );
+ static_cast<OGenericAdministrationPage&>(_rPage).SetAdminDialog(this,this);
+
+ SfxTabDialogController::PageCreated(rId, _rPage);
+}
+
+void ODbAdminDialog::addDetailPage(const OString& rPageId, TranslateId pTextId, CreateTabPage pCreateFunc)
+{
+ AddTabPage(rPageId, DBA_RES(pTextId), pCreateFunc);
+}
+
+void ODbAdminDialog::impl_selectDataSource(const css::uno::Any& _aDataSourceName)
+{
+ m_pImpl->setDataSourceOrName(_aDataSourceName);
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ impl_resetPages( xDatasource );
+
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(getOutputSet()->GetItem(DSID_TYPECOLLECTION));
+ assert(pCollectionItem && "must exist");
+ ::dbaccess::ODsnTypeCollection* pCollection = pCollectionItem->getCollection();
+ ::dbaccess::DATASOURCE_TYPE eType = pCollection->determineType(getDatasourceType(*getOutputSet()));
+
+ // and insert the new ones
+ switch ( eType )
+ {
+ case ::dbaccess::DST_DBASE:
+ addDetailPage("dbase", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateDbase);
+ break;
+
+ case ::dbaccess::DST_ADO:
+ addDetailPage("ado", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateAdo);
+ break;
+
+ case ::dbaccess::DST_FLAT:
+ addDetailPage("text", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateText);
+ break;
+
+ case ::dbaccess::DST_ODBC:
+ addDetailPage("odbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateODBC);
+ break;
+
+ case ::dbaccess::DST_MYSQL_ODBC:
+ addDetailPage("mysqlodbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateMySQLODBC);
+ break;
+
+ case ::dbaccess::DST_MYSQL_JDBC:
+ addDetailPage("mysqljdbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateMySQLJDBC);
+ break;
+
+ case ::dbaccess::DST_ORACLE_JDBC:
+ addDetailPage("oraclejdbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateOracleJDBC);
+ break;
+
+ case ::dbaccess::DST_LDAP:
+ addDetailPage("ldap",STR_PAGETITLE_ADVANCED,ODriversSettings::CreateLDAP);
+ break;
+ case ::dbaccess::DST_USERDEFINE1: /// first user defined driver
+ case ::dbaccess::DST_USERDEFINE2:
+ case ::dbaccess::DST_USERDEFINE3:
+ case ::dbaccess::DST_USERDEFINE4:
+ case ::dbaccess::DST_USERDEFINE5:
+ case ::dbaccess::DST_USERDEFINE6:
+ case ::dbaccess::DST_USERDEFINE7:
+ case ::dbaccess::DST_USERDEFINE8:
+ case ::dbaccess::DST_USERDEFINE9:
+ case ::dbaccess::DST_USERDEFINE10:
+ {
+ OUString aTitle(DBA_RES(STR_PAGETITLE_ADVANCED));
+ AddTabPage("user" + OString::number(eType - dbaccess::DST_USERDEFINE1 + 1), aTitle, ODriversSettings::CreateUser);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ODbAdminDialog::impl_resetPages(const Reference< XPropertySet >& _rxDatasource)
+{
+ // the selection is valid if and only if we have a datasource now
+ GetInputSetImpl()->Put(SfxBoolItem(DSID_INVALID_SELECTION, !_rxDatasource.is()));
+ // (sal_False tells the tab pages to disable and reset all their controls, which is different
+ // from "just set them to readonly")
+
+ // reset the pages
+
+ // prevent flicker
+ m_xDialog->freeze();
+
+ // remove all items which relate to indirect properties from the input set
+ // (without this, the following may happen: select an arbitrary data source where some indirect properties
+ // are set. Select another data source of the same type, where the indirect props are not set (yet). Then,
+ // the indirect property values of the first ds are shown in the second ds ...)
+ const ODbDataSourceAdministrationHelper::MapInt2String& rMap = m_pImpl->getIndirectProperties();
+ for (auto const& elem : rMap)
+ GetInputSetImpl()->ClearItem( static_cast<sal_uInt16>(elem.first) );
+
+ // extract all relevant data from the property set of the data source
+ m_pImpl->translateProperties(_rxDatasource, *GetInputSetImpl());
+
+ // reset the example set
+ m_xExampleSet.reset(new SfxItemSet(*GetInputSetImpl()));
+
+ // special case: MySQL Native does not have the generic "advanced" page
+
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(getOutputSet()->GetItem(DSID_TYPECOLLECTION));
+ assert(pCollectionItem && "must exist");
+ ::dbaccess::ODsnTypeCollection* pCollection = pCollectionItem->getCollection();
+ if ( pCollection->determineType(getDatasourceType( *m_xExampleSet )) == ::dbaccess::DST_MYSQL_NATIVE )
+ {
+ OString sMySqlNative("mysqlnative");
+ AddTabPage(sMySqlNative, DBA_RES(STR_PAGETITLE_CONNECTION), ODriversSettings::CreateMySQLNATIVE);
+ RemoveTabPage("advanced");
+ m_sMainPageID = sMySqlNative;
+ }
+
+ SetCurPageId(m_sMainPageID);
+ SfxTabPage* pConnectionPage = GetTabPage(m_sMainPageID);
+ if ( pConnectionPage )
+ pConnectionPage->Reset(GetInputSetImpl());
+ // if this is NULL, the page has not been created yet, which means we're called before the
+ // dialog was displayed (probably from inside the ctor)
+
+ m_xDialog->thaw();
+}
+
+void ODbAdminDialog::setTitle(const OUString& rTitle)
+{
+ m_xDialog->set_title(rTitle);
+}
+
+void ODbAdminDialog::enableConfirmSettings( bool ) {}
+
+void ODbAdminDialog::saveDatasource()
+{
+ PrepareLeaveCurrentPage();
+}
+
+ODbAdminDialog::ApplyResult ODbAdminDialog::implApplyChanges()
+{
+ if (!PrepareLeaveCurrentPage())
+ { // the page did not allow us to leave
+ return AR_KEEP;
+ }
+
+ if ( !m_pImpl->saveChanges(*m_xExampleSet) )
+ return AR_KEEP;
+
+ return AR_LEAVE_MODIFIED;
+}
+
+void ODbAdminDialog::selectDataSource(const css::uno::Any& _aDataSourceName)
+{
+ impl_selectDataSource(_aDataSourceName);
+}
+
+const SfxItemSet* ODbAdminDialog::getOutputSet() const
+{
+ return GetExampleSet();
+}
+
+SfxItemSet* ODbAdminDialog::getWriteOutputSet()
+{
+ return m_xExampleSet.get();
+}
+
+std::pair< Reference<XConnection>,bool> ODbAdminDialog::createConnection()
+{
+ return m_pImpl->createConnection();
+}
+
+Reference< XComponentContext > ODbAdminDialog::getORB() const
+{
+ return m_pImpl->getORB();
+}
+
+Reference< XDriver > ODbAdminDialog::getDriver()
+{
+ return m_pImpl->getDriver();
+}
+
+OUString ODbAdminDialog::getDatasourceType(const SfxItemSet& _rSet) const
+{
+ return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet);
+}
+
+void ODbAdminDialog::clearPassword()
+{
+ m_pImpl->clearPassword();
+}
+
+void ODbAdminDialog::createItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults, ::dbaccess::ODsnTypeCollection* _pTypeCollection)
+{
+ // just to be sure...
+ _rpSet = nullptr;
+ _rpPool = nullptr;
+ _rpDefaults = nullptr;
+
+ const OUString sFilterAll( "%" );
+ // create and initialize the defaults
+ _rpDefaults = new std::vector<SfxPoolItem*>(DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1);
+ SfxPoolItem** pCounter = _rpDefaults->data(); // want to modify this without affecting the out param _rppDefaults
+ *pCounter++ = new SfxStringItem(DSID_NAME, OUString());
+ *pCounter++ = new SfxStringItem(DSID_ORIGINALNAME, OUString());
+ *pCounter++ = new SfxStringItem(DSID_CONNECTURL, OUString());
+ *pCounter++ = new OStringListItem(DSID_TABLEFILTER, Sequence< OUString >(&sFilterAll, 1));
+ *pCounter++ = new DbuTypeCollectionItem(DSID_TYPECOLLECTION, _pTypeCollection);
+ *pCounter++ = new SfxBoolItem(DSID_INVALID_SELECTION, false);
+ *pCounter++ = new SfxBoolItem(DSID_READONLY, false);
+ *pCounter++ = new SfxStringItem(DSID_USER, OUString());
+ *pCounter++ = new SfxStringItem(DSID_PASSWORD, OUString());
+ *pCounter++ = new SfxStringItem(DSID_ADDITIONALOPTIONS, OUString());
+ *pCounter++ = new SfxStringItem(DSID_CHARSET, OUString());
+ *pCounter++ = new SfxBoolItem(DSID_PASSWORDREQUIRED, false);
+ *pCounter++ = new SfxBoolItem(DSID_SHOWDELETEDROWS, false);
+ *pCounter++ = new SfxBoolItem(DSID_ALLOWLONGTABLENAMES, false);
+ *pCounter++ = new SfxStringItem(DSID_JDBCDRIVERCLASS, OUString());
+ *pCounter++ = new SfxStringItem(DSID_FIELDDELIMITER, OUString(','));
+ *pCounter++ = new SfxStringItem(DSID_TEXTDELIMITER, OUString('"'));
+ *pCounter++ = new SfxStringItem(DSID_DECIMALDELIMITER, OUString('.'));
+ *pCounter++ = new SfxStringItem(DSID_THOUSANDSDELIMITER, OUString());
+ *pCounter++ = new SfxStringItem(DSID_TEXTFILEEXTENSION, "txt");
+ *pCounter++ = new SfxBoolItem(DSID_TEXTFILEHEADER, true);
+ *pCounter++ = new SfxBoolItem(DSID_PARAMETERNAMESUBST, false);
+ *pCounter++ = new SfxInt32Item(DSID_CONN_PORTNUMBER, 8100);
+ *pCounter++ = new SfxBoolItem(DSID_SUPPRESSVERSIONCL, false);
+ *pCounter++ = new SfxBoolItem(DSID_CONN_SHUTSERVICE, false);
+ *pCounter++ = new SfxInt32Item(DSID_CONN_DATAINC, 20);
+ *pCounter++ = new SfxInt32Item(DSID_CONN_CACHESIZE, 20);
+ *pCounter++ = new SfxStringItem(DSID_CONN_CTRLUSER, OUString());
+ *pCounter++ = new SfxStringItem(DSID_CONN_CTRLPWD, OUString());
+ *pCounter++ = new SfxBoolItem(DSID_USECATALOG, false);
+ *pCounter++ = new SfxStringItem(DSID_CONN_HOSTNAME, OUString());
+ *pCounter++ = new SfxStringItem(DSID_CONN_LDAP_BASEDN, OUString());
+ *pCounter++ = new SfxInt32Item(DSID_CONN_LDAP_PORTNUMBER, 389);
+ *pCounter++ = new SfxInt32Item(DSID_CONN_LDAP_ROWCOUNT, 100);
+ *pCounter++ = new SfxBoolItem(DSID_SQL92CHECK, false);
+ *pCounter++ = new SfxStringItem(DSID_AUTOINCREMENTVALUE, OUString());
+ *pCounter++ = new SfxStringItem(DSID_AUTORETRIEVEVALUE, OUString());
+ *pCounter++ = new SfxBoolItem(DSID_AUTORETRIEVEENABLED, false);
+ *pCounter++ = new SfxBoolItem(DSID_APPEND_TABLE_ALIAS, false);
+ *pCounter++ = new SfxInt32Item(DSID_MYSQL_PORTNUMBER, 3306);
+ *pCounter++ = new SfxBoolItem(DSID_IGNOREDRIVER_PRIV, true);
+ *pCounter++ = new SfxInt32Item(DSID_BOOLEANCOMPARISON, 0);
+ *pCounter++ = new SfxInt32Item(DSID_ORACLE_PORTNUMBER, 1521);
+ *pCounter++ = new SfxBoolItem(DSID_ENABLEOUTERJOIN, true);
+ *pCounter++ = new SfxBoolItem(DSID_CATALOG, true);
+ *pCounter++ = new SfxBoolItem(DSID_SCHEMA, true);
+ *pCounter++ = new SfxBoolItem(DSID_INDEXAPPENDIX, true);
+ *pCounter++ = new SfxBoolItem(DSID_CONN_LDAP_USESSL, false);
+ *pCounter++ = new SfxStringItem(DSID_DOCUMENT_URL, OUString());
+ *pCounter++ = new SfxBoolItem(DSID_DOSLINEENDS, false);
+ *pCounter++ = new SfxStringItem(DSID_DATABASENAME, OUString());
+ *pCounter++ = new SfxBoolItem(DSID_AS_BEFORE_CORRNAME, false);
+ *pCounter++ = new SfxBoolItem(DSID_CHECK_REQUIRED_FIELDS, true);
+ *pCounter++ = new SfxBoolItem(DSID_IGNORECURRENCY, false);
+ *pCounter++ = new SfxStringItem(DSID_CONN_SOCKET, OUString());
+ *pCounter++ = new SfxBoolItem(DSID_ESCAPE_DATETIME, true);
+ *pCounter++ = new SfxStringItem(DSID_NAMED_PIPE, OUString());
+ *pCounter++ = new OptionalBoolItem( DSID_PRIMARY_KEY_SUPPORT );
+ *pCounter++ = new SfxInt32Item(DSID_MAX_ROW_SCAN, 100);
+ *pCounter++ = new SfxBoolItem( DSID_RESPECTRESULTSETTYPE,false );
+
+ // create the pool
+ static SfxItemInfo const aItemInfos[DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1] =
+ {
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ {0,false},
+ };
+
+ OSL_ENSURE(SAL_N_ELEMENTS(aItemInfos) == DSID_LAST_ITEM_ID,"Invalid Ids!");
+ _rpPool = new SfxItemPool("DSAItemPool", DSID_FIRST_ITEM_ID, DSID_LAST_ITEM_ID,
+ aItemInfos, _rpDefaults);
+ _rpPool->FreezeIdRanges();
+
+ // and, finally, the set
+ _rpSet.reset(new SfxItemSet(*_rpPool));
+}
+
+void ODbAdminDialog::destroyItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults)
+{
+ // _first_ delete the set (referring the pool)
+ _rpSet.reset();
+
+ // delete the pool
+ if (_rpPool)
+ {
+ _rpPool->ReleaseDefaults(true);
+ // the "true" means delete the items, too
+ _rpPool = nullptr;
+ }
+
+ // reset the defaults ptr
+ _rpDefaults = nullptr;
+ // no need to explicitly delete the defaults, this has been done by the ReleaseDefaults
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dbfindex.cxx b/dbaccess/source/ui/dlg/dbfindex.cxx
new file mode 100644
index 000000000..89f74ab72
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dbfindex.cxx
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "dbfindex.hxx"
+#include <comphelper/processfactory.hxx>
+#include <osl/file.hxx>
+#include <osl/thread.hxx>
+#include <tools/config.hxx>
+#include <osl/diagnose.h>
+#include <unotools/localfilehelper.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/pathoptions.hxx>
+#include <ucbhelper/content.hxx>
+#include <svl/filenotation.hxx>
+#include <rtl/strbuf.hxx>
+
+namespace dbaui
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::svt;
+
+constexpr OStringLiteral aGroupIdent("dBase III");
+
+
+ODbaseIndexDialog::ODbaseIndexDialog(weld::Window * pParent, const OUString& aDataSrcName)
+ : GenericDialogController(pParent, "dbaccess/ui/dbaseindexdialog.ui", "DBaseIndexDialog")
+ , m_aDSN(aDataSrcName)
+ , m_xPB_OK(m_xBuilder->weld_button("ok"))
+ , m_xCB_Tables(m_xBuilder->weld_combo_box("table"))
+ , m_xIndexes(m_xBuilder->weld_widget("frame"))
+ , m_xLB_TableIndexes(m_xBuilder->weld_tree_view("tableindex"))
+ , m_xLB_FreeIndexes(m_xBuilder->weld_tree_view("freeindex"))
+ , m_xAdd(m_xBuilder->weld_button("add"))
+ , m_xRemove(m_xBuilder->weld_button("remove"))
+ , m_xAddAll(m_xBuilder->weld_button("addall"))
+ , m_xRemoveAll(m_xBuilder->weld_button("removeall"))
+{
+ int nWidth = m_xLB_TableIndexes->get_approximate_digit_width() * 18;
+ int nHeight = m_xLB_TableIndexes->get_height_rows(10);
+ m_xLB_TableIndexes->set_size_request(nWidth, nHeight);
+ m_xLB_FreeIndexes->set_size_request(nWidth, nHeight);
+
+ m_xCB_Tables->connect_changed( LINK(this, ODbaseIndexDialog, TableSelectHdl) );
+ m_xAdd->connect_clicked( LINK(this, ODbaseIndexDialog, AddClickHdl) );
+ m_xRemove->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveClickHdl) );
+ m_xAddAll->connect_clicked( LINK(this, ODbaseIndexDialog, AddAllClickHdl) );
+ m_xRemoveAll->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveAllClickHdl) );
+ m_xPB_OK->connect_clicked( LINK(this, ODbaseIndexDialog, OKClickHdl) );
+
+ m_xLB_FreeIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) );
+ m_xLB_TableIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) );
+
+ Init();
+ SetCtrls();
+}
+
+ODbaseIndexDialog::~ODbaseIndexDialog()
+{
+}
+
+void ODbaseIndexDialog::checkButtons()
+{
+ m_xAdd->set_sensitive(0 != m_xLB_FreeIndexes->count_selected_rows());
+ m_xAddAll->set_sensitive(0 != m_xLB_FreeIndexes->n_children());
+
+ m_xRemove->set_sensitive(0 != m_xLB_TableIndexes->count_selected_rows());
+ m_xRemoveAll->set_sensitive(0 != m_xLB_TableIndexes->n_children());
+}
+
+OTableIndex ODbaseIndexDialog::implRemoveIndex(const OUString& _rName, TableIndexList& _rList, weld::TreeView& _rDisplay, bool _bMustExist)
+{
+ OTableIndex aReturn;
+
+ TableIndexList::iterator aSearch = std::find_if(_rList.begin(), _rList.end(),
+ [&_rName](const OTableIndex& rIndex) { return rIndex.GetIndexFileName() == _rName; });
+ if (aSearch != _rList.end())
+ {
+ sal_Int32 nPos = static_cast<sal_Int32>(std::distance(_rList.begin(), aSearch));
+
+ aReturn = *aSearch;
+
+ _rList.erase(aSearch);
+ _rDisplay.remove_text(_rName);
+
+ // adjust selection if necessary
+ if (static_cast<sal_uInt32>(nPos) == _rList.size())
+ _rDisplay.select(static_cast<sal_uInt16>(nPos)-1);
+ else
+ _rDisplay.select(static_cast<sal_uInt16>(nPos));
+ }
+ OSL_ENSURE(!_bMustExist || !aReturn.GetIndexFileName().isEmpty(), "ODbaseIndexDialog::implRemoveIndex : did not find the index!");
+ return aReturn;
+}
+
+void ODbaseIndexDialog::implInsertIndex(const OTableIndex& _rIndex, TableIndexList& _rList, weld::TreeView& _rDisplay)
+{
+ _rList.push_front(_rIndex);
+ _rDisplay.append_text(_rIndex.GetIndexFileName());
+ _rDisplay.select(0);
+}
+
+OTableIndex ODbaseIndexDialog::RemoveTableIndex( std::u16string_view _rTableName, const OUString& _rIndexName )
+{
+ OTableIndex aReturn;
+
+ // does the table exist ?
+ TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(),
+ [&] (const OTableInfo& arg) { return arg.aTableName == _rTableName; });
+
+ if (aTablePos == m_aTableInfoList.end())
+ return aReturn;
+
+ return implRemoveIndex(_rIndexName, aTablePos->aIndexList, *m_xLB_TableIndexes, true/*_bMustExist*/);
+}
+
+void ODbaseIndexDialog::InsertTableIndex( std::u16string_view _rTableName, const OTableIndex& _rIndex)
+{
+ TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(),
+ [&] (const OTableInfo& arg) { return arg.aTableName == _rTableName; });
+
+ if (aTablePos == m_aTableInfoList.end())
+ return;
+
+ implInsertIndex(_rIndex, aTablePos->aIndexList, *m_xLB_TableIndexes);
+}
+
+IMPL_LINK_NOARG(ODbaseIndexDialog, OKClickHdl, weld::Button&, void)
+{
+ // let all tables write their INF file
+
+ for (auto const& tableInfo : m_aTableInfoList)
+ tableInfo.WriteInfFile(m_aDSN);
+
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ODbaseIndexDialog, AddClickHdl, weld::Button&, void)
+{
+ OUString aSelection = m_xLB_FreeIndexes->get_selected_text();
+ OUString aTableName = m_xCB_Tables->get_active_text();
+ OTableIndex aIndex = RemoveFreeIndex( aSelection, true );
+ InsertTableIndex( aTableName, aIndex );
+
+ checkButtons();
+}
+
+IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveClickHdl, weld::Button&, void)
+{
+ OUString aSelection = m_xLB_TableIndexes->get_selected_text();
+ OUString aTableName = m_xCB_Tables->get_active_text();
+ OTableIndex aIndex = RemoveTableIndex( aTableName, aSelection );
+ InsertFreeIndex( aIndex );
+
+ checkButtons();
+}
+
+IMPL_LINK_NOARG(ODbaseIndexDialog, AddAllClickHdl, weld::Button&, void)
+{
+ const sal_Int32 nCnt = m_xLB_FreeIndexes->n_children();
+ OUString aTableName = m_xCB_Tables->get_active_text();
+
+ for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos)
+ InsertTableIndex(aTableName, RemoveFreeIndex(m_xLB_FreeIndexes->get_text(0), true));
+
+ checkButtons();
+}
+
+IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveAllClickHdl, weld::Button&, void)
+{
+ const sal_Int32 nCnt = m_xLB_TableIndexes->n_children();
+ OUString aTableName = m_xCB_Tables->get_active_text();
+
+ for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos)
+ InsertFreeIndex(RemoveTableIndex(aTableName, m_xLB_TableIndexes->get_text(0)));
+
+ checkButtons();
+}
+
+IMPL_LINK_NOARG(ODbaseIndexDialog, OnListEntrySelected, weld::TreeView&, void)
+{
+ checkButtons();
+}
+
+IMPL_LINK(ODbaseIndexDialog, TableSelectHdl, weld::ComboBox&, rComboBox, void)
+{
+ // search the table
+ TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(),
+ [&] (const OTableInfo& arg) { return arg.aTableName == rComboBox.get_active_text() ; });
+
+ if (aTablePos == m_aTableInfoList.end())
+ return;
+
+ // fill the listbox for the indexes
+ m_xLB_TableIndexes->clear();
+ for (auto const& index : aTablePos->aIndexList)
+ m_xLB_TableIndexes->append_text(index.GetIndexFileName());
+
+ if (!aTablePos->aIndexList.empty())
+ m_xLB_TableIndexes->select(0);
+
+ checkButtons();
+}
+
+void ODbaseIndexDialog::Init()
+{
+ m_xPB_OK->set_sensitive(false);
+ m_xIndexes->set_sensitive(false);
+
+ // All indices are first added to a list of free indices.
+ // Afterwards, check the index of each table in the Inf-file.
+ // These indices are removed from the list of free indices and
+ // entered in the indexlist of the table.
+
+ // if the string does not contain a path, cut the string
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ {
+ SvtPathOptions aPathOptions;
+ m_aDSN = aPathOptions.SubstituteVariable(m_aDSN);
+ }
+ aURL.SetSmartURL(m_aDSN);
+
+ // String aFileName = aURL.PathToFileName();
+ m_aDSN = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ ::ucbhelper::Content aFile;
+ bool bFolder=true;
+ try
+ {
+ aFile = ::ucbhelper::Content(m_aDSN,Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ bFolder = aFile.isFolder();
+ }
+ catch(Exception&)
+ {
+ return;
+ }
+
+ // first assume for all indexes they're free
+
+ OUString const aIndexExt("ndx");
+ OUString const aTableExt("dbf");
+
+ std::vector< OUString > aUsedIndexes;
+
+ aURL.SetSmartProtocol(INetProtocol::File);
+ const Sequence<OUString> aFolderUrls = ::utl::LocalFileHelper::GetFolderContents(m_aDSN, bFolder);
+ for(const OUString& rURL : aFolderUrls)
+ {
+ OUString aName;
+ osl::FileBase::getSystemPathFromFileURL(rURL,aName);
+ aURL.SetSmartURL(aName);
+ OUString aExt = aURL.getExtension();
+ if (aExt == aIndexExt)
+ {
+ m_aFreeIndexList.emplace_back(aURL.getName() );
+ }
+ else if (aExt == aTableExt)
+ {
+ m_aTableInfoList.emplace_back(aURL.getName() );
+ OTableInfo& rTabInfo = m_aTableInfoList.back();
+
+ // open the INF file
+ aURL.setExtension(u"inf");
+ OFileNotation aTransformer(aURL.GetURLNoPass(), OFileNotation::N_URL);
+ Config aInfFile( aTransformer.get(OFileNotation::N_SYSTEM) );
+ aInfFile.SetGroup( aGroupIdent );
+
+ // fill the indexes list
+ OString aNDX;
+ sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
+ OString aKeyName;
+ OUString aEntry;
+
+ for( sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++ )
+ {
+ // does the key point to an index file ?
+ aKeyName = aInfFile.GetKeyName( nKey );
+ aNDX = aKeyName.copy(0,3);
+
+ // yes -> add to the tables index list
+ if (aNDX == "NDX")
+ {
+ aEntry = OStringToOUString(aInfFile.ReadKey(aKeyName), osl_getThreadTextEncoding());
+ rTabInfo.aIndexList.emplace_back( aEntry );
+
+ // and remove it from the free index list
+ aUsedIndexes.push_back(aEntry);
+ // do this later below. We may not have encountered the index file, yet, thus we may not
+ // know the index as being free, yet
+ }
+ }
+ }
+ }
+
+ for (auto const& usedIndex : aUsedIndexes)
+ RemoveFreeIndex( usedIndex, false );
+
+ if (!m_aTableInfoList.empty())
+ {
+ m_xPB_OK->set_sensitive(true);
+ m_xIndexes->set_sensitive(true);
+ }
+
+ checkButtons();
+}
+
+void ODbaseIndexDialog::SetCtrls()
+{
+ // ComboBox tables
+ for (auto const& tableInfo : m_aTableInfoList)
+ m_xCB_Tables->append_text(tableInfo.aTableName);
+
+ // put the first dataset into Edit
+ if (!m_aTableInfoList.empty())
+ {
+ const OTableInfo& rTabInfo = m_aTableInfoList.front();
+ m_xCB_Tables->set_entry_text(rTabInfo.aTableName);
+
+ // build ListBox of the table indices
+ for (auto const& index : rTabInfo.aIndexList)
+ m_xLB_TableIndexes->append_text(index.GetIndexFileName());
+
+ if (!rTabInfo.aIndexList.empty())
+ m_xLB_TableIndexes->select(0);
+ }
+
+ // ListBox of the free indices
+ for (auto const& freeIndex : m_aFreeIndexList)
+ m_xLB_FreeIndexes->append_text(freeIndex.GetIndexFileName());
+
+ if (!m_aFreeIndexList.empty())
+ m_xLB_FreeIndexes->select(0);
+
+ TableSelectHdl(*m_xCB_Tables);
+ checkButtons();
+}
+
+void OTableInfo::WriteInfFile( const OUString& rDSN ) const
+{
+ // open INF file
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ OUString aDsn = rDSN;
+ {
+ SvtPathOptions aPathOptions;
+ aDsn = aPathOptions.SubstituteVariable(aDsn);
+ }
+ aURL.SetSmartURL(aDsn);
+ aURL.Append(aTableName);
+ aURL.setExtension(u"inf");
+
+ OFileNotation aTransformer(aURL.GetURLNoPass(), OFileNotation::N_URL);
+ Config aInfFile( aTransformer.get(OFileNotation::N_SYSTEM) );
+ aInfFile.SetGroup( aGroupIdent );
+
+ // first, delete all table indices
+ OString aNDX;
+ sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
+ sal_uInt16 nKey = 0;
+
+ while( nKey < nKeyCnt )
+ {
+ // Does the key point to an index file?...
+ OString aKeyName = aInfFile.GetKeyName( nKey );
+ aNDX = aKeyName.copy(0,3);
+
+ //...if yes, delete index file, nKey is at subsequent key
+ if (aNDX == "NDX")
+ {
+ aInfFile.DeleteKey(aKeyName);
+ nKeyCnt--;
+ }
+ else
+ nKey++;
+
+ }
+
+ // now add all saved indices
+ sal_uInt16 nPos = 0;
+ for (auto const& index : aIndexList)
+ {
+ OStringBuffer aKeyName("NDX");
+ if( nPos > 0 ) // first index contains no number
+ aKeyName.append(static_cast<sal_Int32>(nPos));
+ aInfFile.WriteKey(
+ aKeyName.makeStringAndClear(),
+ OUStringToOString(index.GetIndexFileName(),
+ osl_getThreadTextEncoding()));
+ ++nPos;
+ }
+
+ aInfFile.Flush();
+
+ // if only [dbase] is left in INF-file, delete file
+ if(nPos)
+ return;
+
+ try
+ {
+ ::ucbhelper::Content aContent(aURL.GetURLNoPass(),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ aContent.executeCommand( "delete", Any( true ) );
+ }
+ catch (const Exception& )
+ {
+ // simply silent this. The strange algorithm here does a lot of
+ // things even if no files at all were created or accessed, so it's
+ // possible that the file we're trying to delete does not even
+ // exist, and this is a valid condition.
+ }
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dbfindex.hxx b/dbaccess/source/ui/dlg/dbfindex.hxx
new file mode 100644
index 000000000..53b75640e
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dbfindex.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <deque>
+
+namespace dbaui
+{
+
+// OTableIndex
+/// represents a single dbf index
+class OTableIndex
+{
+private:
+ OUString aIndexFileName;
+
+public:
+ OTableIndex() { }
+ explicit OTableIndex( const OUString& rFileName ) : aIndexFileName( rFileName ) { }
+
+ const OUString& GetIndexFileName() const { return aIndexFileName; }
+};
+
+typedef std::deque< OTableIndex > TableIndexList;
+
+// OTableInfo
+class ODbaseIndexDialog;
+/** holds the INF file of a table
+*/
+class OTableInfo
+{
+ friend class ODbaseIndexDialog;
+private:
+ OUString aTableName;
+ TableIndexList aIndexList;
+
+public:
+ explicit OTableInfo( const OUString& rName ) : aTableName(rName) { }
+
+ void WriteInfFile( const OUString& rDSN ) const;
+};
+
+typedef std::deque< OTableInfo > TableInfoList;
+
+// IndexDialog
+class ODbaseIndexDialog : public weld::GenericDialogController
+{
+protected:
+ OUString m_aDSN;
+ TableInfoList m_aTableInfoList;
+ TableIndexList m_aFreeIndexList;
+
+ std::unique_ptr<weld::Button> m_xPB_OK;
+ std::unique_ptr<weld::ComboBox> m_xCB_Tables;
+ std::unique_ptr<weld::Widget> m_xIndexes;
+ std::unique_ptr<weld::TreeView> m_xLB_TableIndexes;
+ std::unique_ptr<weld::TreeView> m_xLB_FreeIndexes;
+
+ std::unique_ptr<weld::Button> m_xAdd;
+ std::unique_ptr<weld::Button> m_xRemove;
+ std::unique_ptr<weld::Button> m_xAddAll;
+ std::unique_ptr<weld::Button> m_xRemoveAll;
+
+ DECL_LINK( TableSelectHdl, weld::ComboBox&, void );
+ DECL_LINK( AddClickHdl, weld::Button&, void );
+ DECL_LINK( RemoveClickHdl, weld::Button&, void );
+ DECL_LINK( AddAllClickHdl, weld::Button&, void );
+ DECL_LINK( RemoveAllClickHdl, weld::Button&, void );
+ DECL_LINK( OKClickHdl, weld::Button&, void );
+ DECL_LINK( OnListEntrySelected, weld::TreeView&, void );
+
+ void Init();
+ void SetCtrls();
+
+ static OTableIndex implRemoveIndex(const OUString& _rName, TableIndexList& _rList, weld::TreeView& _rDisplay, bool _bMustExist);
+ static void implInsertIndex(const OTableIndex& _rIndex, TableIndexList& _rList, weld::TreeView& _rDisplay);
+
+ OTableIndex RemoveFreeIndex( const OUString& _rName, bool _bMustExist ) { return implRemoveIndex(_rName, m_aFreeIndexList, *m_xLB_FreeIndexes, _bMustExist); }
+ void InsertFreeIndex( const OTableIndex& _rIndex ) { implInsertIndex(_rIndex, m_aFreeIndexList, *m_xLB_FreeIndexes); }
+ OTableIndex RemoveTableIndex( std::u16string_view _rTableName, const OUString& _rIndexName );
+ void InsertTableIndex( std::u16string_view _rTableName, const OTableIndex& _rIndex );
+
+ void checkButtons();
+
+public:
+ ODbaseIndexDialog(weld::Window * pParent, const OUString& rDataSrcName);
+ virtual ~ODbaseIndexDialog() override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dbwiz.cxx b/dbaccess/source/ui/dlg/dbwiz.cxx
new file mode 100644
index 000000000..fa0653502
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dbwiz.cxx
@@ -0,0 +1,336 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <dbwiz.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <dsitems.hxx>
+#include "dsnItem.hxx"
+#include "adminpages.hxx"
+#include "generalpage.hxx"
+#include <unotools/confignode.hxx>
+#include "ConnectionPage.hxx"
+#include "DriverSettings.hxx"
+#include "DbAdminImpl.hxx"
+#include <helpids.h>
+
+namespace dbaui
+{
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::util;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+
+#define START_PAGE 0
+#define CONNECTION_PAGE 1
+#define ADDITIONAL_PAGE_DBASE 2
+#define ADDITIONAL_PAGE_FLAT 3
+#define ADDITIONAL_PAGE_LDAP 4
+//5 was ADDITIONAL_PAGE_ADABAS
+#define ADDITIONAL_PAGE_MYSQL_JDBC 6
+#define ADDITIONAL_PAGE_MYSQL_ODBC 7
+#define ADDITIONAL_PAGE_ORACLE_JDBC 8
+#define ADDITIONAL_PAGE_ADO 9
+#define ADDITIONAL_PAGE_ODBC 10
+#define ADDITIONAL_USERDEFINED 11
+#define ADDITIONAL_PAGE_MYSQL_NATIVE 12
+
+// ODbTypeWizDialog
+ODbTypeWizDialog::ODbTypeWizDialog(weld::Window* _pParent, SfxItemSet const * _pItems,
+ const Reference< XComponentContext >& _rxORB, const css::uno::Any& _aDataSourceName)
+ : WizardMachine(_pParent, WizardButtonFlags::NEXT | WizardButtonFlags::PREVIOUS | WizardButtonFlags::FINISH | WizardButtonFlags::CANCEL | WizardButtonFlags::HELP )
+{
+ m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxORB, m_xAssistant.get(), _pParent, this));
+ m_pImpl->setDataSourceOrName(_aDataSourceName);
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ m_pOutSet.reset(new SfxItemSet( *_pItems->GetPool(), _pItems->GetRanges() ));
+
+ m_pImpl->translateProperties(xDatasource, *m_pOutSet);
+ m_eType = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(*m_pOutSet);
+
+ defaultButton(WizardButtonFlags::NEXT);
+ enableButtons(WizardButtonFlags::FINISH, false);
+ enableAutomaticNextButtonState();
+
+ m_xPrevPage->set_help_id(HID_DBWIZ_PREVIOUS);
+ m_xNextPage->set_help_id(HID_DBWIZ_NEXT);
+ m_xCancel->set_help_id(HID_DBWIZ_CANCEL);
+ m_xFinish->set_help_id(HID_DBWIZ_FINISH);
+ // no local resources needed anymore
+
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(_pItems->GetItem(DSID_TYPECOLLECTION));
+ assert(pCollectionItem && "must exist");
+ m_pCollection = pCollectionItem->getCollection();
+
+ ActivatePage();
+ setTitleBase(DBA_RES(STR_DATABASE_TYPE_CHANGE));
+
+ m_xAssistant->set_current_page(0);
+}
+
+ODbTypeWizDialog::~ODbTypeWizDialog()
+{
+}
+
+IMPL_LINK(ODbTypeWizDialog, OnTypeSelected, OGeneralPage&, _rTabPage, void)
+{
+ m_eType = _rTabPage.GetSelectedType();
+ const bool bURLRequired = m_pCollection->isConnectionUrlRequired(m_eType);
+ enableButtons(WizardButtonFlags::NEXT,bURLRequired);
+ enableButtons(WizardButtonFlags::FINISH,!bURLRequired);
+}
+
+WizardState ODbTypeWizDialog::determineNextState( WizardState _nCurrentState ) const
+{
+ WizardState nNextState = WZS_INVALID_STATE;
+ switch(_nCurrentState)
+ {
+ case START_PAGE:
+ switch(m_pCollection->determineType(m_eType))
+ {
+ case ::dbaccess::DST_MOZILLA:
+ case ::dbaccess::DST_OUTLOOK:
+ case ::dbaccess::DST_OUTLOOKEXP:
+ case ::dbaccess::DST_EVOLUTION:
+ case ::dbaccess::DST_EVOLUTION_GROUPWISE:
+ case ::dbaccess::DST_EVOLUTION_LDAP:
+ case ::dbaccess::DST_KAB:
+ case ::dbaccess::DST_MACAB:
+ nNextState = WZS_INVALID_STATE;
+ break;
+ case ::dbaccess::DST_MYSQL_NATIVE:
+ nNextState = ADDITIONAL_PAGE_MYSQL_NATIVE;
+ break;
+ default:
+ nNextState = CONNECTION_PAGE;
+ break;
+ }
+ break;
+ case CONNECTION_PAGE:
+ switch(m_pCollection->determineType(m_eType))
+ {
+ case ::dbaccess::DST_MOZILLA:
+ case ::dbaccess::DST_THUNDERBIRD:
+ case ::dbaccess::DST_OUTLOOK:
+ case ::dbaccess::DST_OUTLOOKEXP:
+ case ::dbaccess::DST_EVOLUTION:
+ case ::dbaccess::DST_EVOLUTION_GROUPWISE:
+ case ::dbaccess::DST_EVOLUTION_LDAP:
+ case ::dbaccess::DST_KAB:
+ case ::dbaccess::DST_MACAB:
+ case ::dbaccess::DST_MSACCESS:
+ case ::dbaccess::DST_MSACCESS_2007:
+ case ::dbaccess::DST_JDBC:
+ case ::dbaccess::DST_CALC:
+ case ::dbaccess::DST_WRITER:
+ nNextState = WZS_INVALID_STATE;
+ break;
+ case ::dbaccess::DST_DBASE:
+ nNextState = ADDITIONAL_PAGE_DBASE;
+ break;
+ case ::dbaccess::DST_FLAT:
+ nNextState = ADDITIONAL_PAGE_FLAT;
+ break;
+ case ::dbaccess::DST_LDAP:
+ nNextState = ADDITIONAL_PAGE_LDAP;
+ break;
+ case ::dbaccess::DST_MYSQL_JDBC:
+ nNextState = ADDITIONAL_PAGE_MYSQL_JDBC;
+ break;
+ case ::dbaccess::DST_MYSQL_ODBC:
+ nNextState = ADDITIONAL_PAGE_MYSQL_ODBC;
+ break;
+ case ::dbaccess::DST_ORACLE_JDBC:
+ nNextState = ADDITIONAL_PAGE_ORACLE_JDBC;
+ break;
+ case ::dbaccess::DST_ADO:
+ nNextState = ADDITIONAL_PAGE_ADO;
+ break;
+ case ::dbaccess::DST_ODBC:
+ nNextState = ADDITIONAL_PAGE_ODBC;
+ break;
+ default:
+ nNextState = WZS_INVALID_STATE;
+ break;
+ }
+ break;
+ }
+
+ return nNextState;
+}
+
+const SfxItemSet* ODbTypeWizDialog::getOutputSet() const
+{
+ return m_pOutSet.get();
+}
+
+SfxItemSet* ODbTypeWizDialog::getWriteOutputSet()
+{
+ return m_pOutSet.get();
+}
+
+std::pair< Reference<XConnection>,bool> ODbTypeWizDialog::createConnection()
+{
+ return m_pImpl->createConnection();
+}
+
+Reference< XComponentContext > ODbTypeWizDialog::getORB() const
+{
+ return m_pImpl->getORB();
+}
+
+Reference< XDriver > ODbTypeWizDialog::getDriver()
+{
+ return m_pImpl->getDriver();
+}
+
+OUString ODbTypeWizDialog::getDatasourceType(const SfxItemSet& _rSet) const
+{
+ return dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet);
+}
+
+void ODbTypeWizDialog::clearPassword()
+{
+ m_pImpl->clearPassword();
+}
+
+std::unique_ptr<BuilderPage> ODbTypeWizDialog::createPage(WizardState _nState)
+{
+ TranslateId pStringId = STR_PAGETITLE_ADVANCED;
+ std::unique_ptr<BuilderPage> xPage;
+
+ OString sIdent(OString::number(_nState));
+ weld::Container* pPageContainer = m_xAssistant->append_page(sIdent);
+
+ switch(_nState)
+ {
+ case START_PAGE: // start state
+ {
+ xPage = std::make_unique<OGeneralPageDialog>(pPageContainer, this, *m_pOutSet);
+ OGeneralPage* pGeneralPage = static_cast<OGeneralPage*>(xPage.get());
+ pGeneralPage->SetTypeSelectHandler( LINK( this, ODbTypeWizDialog, OnTypeSelected));
+ pStringId = STR_PAGETITLE_GENERAL;
+ }
+ break;
+ case CONNECTION_PAGE:
+ xPage = OConnectionTabPage::Create(pPageContainer, this, m_pOutSet.get());
+ pStringId = STR_PAGETITLE_CONNECTION;
+ break;
+
+ case ADDITIONAL_PAGE_DBASE:
+ xPage = ODriversSettings::CreateDbase(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_FLAT:
+ xPage = ODriversSettings::CreateText(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_LDAP:
+ xPage = ODriversSettings::CreateLDAP(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_MYSQL_JDBC:
+ xPage = ODriversSettings::CreateMySQLJDBC(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_MYSQL_NATIVE:
+ xPage = ODriversSettings::CreateMySQLNATIVE(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_MYSQL_ODBC:
+ xPage = ODriversSettings::CreateMySQLODBC(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_ORACLE_JDBC:
+ xPage = ODriversSettings::CreateOracleJDBC(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_ADO:
+ xPage = ODriversSettings::CreateAdo(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_PAGE_ODBC:
+ xPage = ODriversSettings::CreateODBC(pPageContainer, this, m_pOutSet.get());
+ break;
+ case ADDITIONAL_USERDEFINED:
+ xPage = ODriversSettings::CreateUser(pPageContainer, this, m_pOutSet.get());
+ break;
+ default:
+ OSL_FAIL("Wrong state!");
+ break;
+ }
+
+ // register ourself as modified listener
+ if ( xPage )
+ {
+ static_cast<OGenericAdministrationPage*>(xPage.get())->SetServiceFactory( m_pImpl->getORB() );
+ static_cast<OGenericAdministrationPage*>(xPage.get())->SetAdminDialog(this,this);
+ m_xAssistant->set_page_title(sIdent, DBA_RES(pStringId));
+ defaultButton( _nState == START_PAGE ? WizardButtonFlags::NEXT : WizardButtonFlags::FINISH );
+ enableButtons( WizardButtonFlags::FINISH, _nState != START_PAGE);
+ }
+ return xPage;
+}
+
+bool ODbTypeWizDialog::leaveState(WizardState _nState)
+{
+ SfxTabPage* pPage = static_cast<SfxTabPage*>(WizardMachine::GetPage(_nState));
+ if ( pPage )
+ pPage->FillItemSet(m_pOutSet.get());
+ return true;
+}
+
+void ODbTypeWizDialog::setTitle(const OUString& _sTitle)
+{
+ m_xAssistant->set_title(_sTitle);
+}
+
+void ODbTypeWizDialog::enableConfirmSettings( bool _bEnable )
+{
+ enableButtons( WizardButtonFlags::FINISH, _bEnable );
+ // TODO:
+ // this is hacky. At the moment, this method is used in only one case.
+ // As soon as it is to be used more wide-spread, we should find a proper concept
+ // for enabling both the Next and Finish buttons, depending on the current page state.
+ // Plus, the concept must also care for the case where those pages are embedded into
+ // a normal tab dialog.
+}
+
+void ODbTypeWizDialog::saveDatasource()
+{
+ SfxTabPage* pPage = static_cast<SfxTabPage*>(WizardMachine::GetPage(getCurrentState()));
+ if ( pPage )
+ pPage->FillItemSet(m_pOutSet.get());
+
+ OUString sOldURL;
+ if ( m_pImpl->getCurrentDataSource().is() )
+ m_pImpl->getCurrentDataSource()->getPropertyValue(PROPERTY_URL) >>= sOldURL;
+ DataSourceInfoConverter::convert( getORB(), m_pCollection,sOldURL,m_eType,m_pImpl->getCurrentDataSource());
+}
+
+vcl::IWizardPageController* ODbTypeWizDialog::getPageController(BuilderPage* pCurrentPage) const
+{
+ OGenericAdministrationPage* pPage = static_cast<OGenericAdministrationPage*>(pCurrentPage);
+ return pPage;
+}
+
+bool ODbTypeWizDialog::onFinish()
+{
+ saveDatasource();
+ return m_pImpl->saveChanges(*m_pOutSet) && WizardMachine::onFinish();
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dbwizsetup.cxx b/dbaccess/source/ui/dlg/dbwizsetup.cxx
new file mode 100644
index 000000000..f687740dd
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dbwizsetup.cxx
@@ -0,0 +1,994 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <dbwizsetup.hxx>
+#include <dsmeta.hxx>
+#include "DBSetupConnectionPages.hxx"
+#include <strings.hrc>
+#include <strings.hxx>
+#include <dsitems.hxx>
+#include "dsnItem.hxx"
+
+#include <unotools/pathoptions.hxx>
+#include <svl/stritem.hxx>
+#include "adminpages.hxx"
+#include <sfx2/docfilt.hxx>
+#include <unotools/ucbhelper.hxx>
+#include "generalpage.hxx"
+#include <unotools/confignode.hxx>
+#include "DbAdminImpl.hxx"
+#include <helpids.h>
+#include "ConnectionPageSetup.hxx"
+#include <UITools.hxx>
+#include <dbaccess/AsynchronousLink.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/frame/TerminationVetoException.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/task/XInteractionHandler2.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+
+#include <comphelper/interaction.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <connectivity/DriversConfig.hxx>
+
+namespace dbaui
+{
+using namespace dbtools;
+using namespace vcl;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::task;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::io;
+using namespace com::sun::star::util;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+using namespace com::sun::star::frame;
+using namespace com::sun::star::ucb;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::document;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+using vcl::RoadmapWizardTypes::WizardPath;
+
+// ODbTypeWizDialogSetup
+ODbTypeWizDialogSetup::ODbTypeWizDialogSetup(weld::Window* _pParent
+ ,SfxItemSet const * _pItems
+ ,const Reference< XComponentContext >& _rxORB
+ ,const css::uno::Any& _aDataSourceName
+ )
+ : vcl::RoadmapWizardMachine( _pParent )
+
+ , m_bIsConnectable( false)
+ , m_sRM_IntroText( DBA_RES( STR_PAGETITLE_INTROPAGE ) )
+ , m_sRM_dBaseText( DBA_RES( STR_PAGETITLE_DBASE ) )
+ , m_sRM_TextText( DBA_RES( STR_PAGETITLE_TEXT ) )
+ , m_sRM_MSAccessText( DBA_RES( STR_PAGETITLE_MSACCESS ) )
+ , m_sRM_LDAPText( DBA_RES( STR_PAGETITLE_LDAP ) )
+ , m_sRM_ADOText( DBA_RES( STR_PAGETITLE_ADO ) )
+ , m_sRM_JDBCText( DBA_RES( STR_PAGETITLE_JDBC ) )
+ , m_sRM_MySQLNativePageTitle( DBA_RES( STR_PAGETITLE_MYSQL_NATIVE ) )
+ , m_sRM_OracleText( DBA_RES( STR_PAGETITLE_ORACLE ) )
+ , m_sRM_MySQLText( DBA_RES( STR_PAGETITLE_MYSQL ) )
+ , m_sRM_ODBCText( DBA_RES( STR_PAGETITLE_ODBC ) )
+ , m_sRM_DocumentOrSpreadSheetText( DBA_RES( STR_PAGETITLE_DOCUMENT_OR_SPREADSHEET ) )
+ , m_sRM_AuthentificationText( DBA_RES( STR_PAGETITLE_AUTHENTIFICATION ) )
+ , m_sRM_FinalText( DBA_RES( STR_PAGETITLE_FINAL ) )
+ , m_sWorkPath( SvtPathOptions().GetWorkPath() )
+ , m_pGeneralPage( nullptr )
+ , m_pMySQLIntroPage( nullptr )
+ , m_pFinalPage( nullptr )
+{
+ // no local resources needed anymore
+ // extract the datasource type collection from the item set
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>(_pItems->GetItem(DSID_TYPECOLLECTION));
+ assert(pCollectionItem && "must exist");
+ m_pCollection = pCollectionItem->getCollection();
+
+ assert(m_pCollection && "ODbTypeWizDialogSetup::ODbTypeWizDialogSetup : really need a DSN type collection !");
+
+ m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxORB, m_xAssistant.get(), _pParent, this));
+ m_pImpl->setDataSourceOrName(_aDataSourceName);
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ m_pOutSet.reset( new SfxItemSet( *_pItems->GetPool(), _pItems->GetRanges() ) );
+
+ m_pImpl->translateProperties(xDatasource, *m_pOutSet);
+
+ defaultButton(WizardButtonFlags::NEXT);
+ enableButtons(WizardButtonFlags::FINISH, true);
+ enableAutomaticNextButtonState();
+
+ ::dbaccess::ODsnTypeCollection::TypeIterator aIter = m_pCollection->begin();
+ ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end();
+ for(PathId i = 1;aIter != aEnd;++aIter,++i)
+ {
+ const OUString& sURLPrefix = aIter.getURLPrefix();
+ WizardPath aPath;
+ aPath.push_back(PAGE_DBSETUPWIZARD_INTRO);
+ m_pCollection->fillPageIds(sURLPrefix,aPath);
+ aPath.push_back(PAGE_DBSETUPWIZARD_AUTHENTIFICATION);
+ aPath.push_back(PAGE_DBSETUPWIZARD_FINAL);
+
+ declareAuthDepPath(sURLPrefix,i,aPath);
+ }
+
+ WizardPath aPath;
+ aPath.push_back(PAGE_DBSETUPWIZARD_INTRO);
+ declarePath( static_cast<PathId>(m_pCollection->size()+1), aPath);
+
+ m_xPrevPage->set_help_id(HID_DBWIZ_PREVIOUS);
+ m_xNextPage->set_help_id(HID_DBWIZ_NEXT);
+ m_xCancel->set_help_id(HID_DBWIZ_CANCEL);
+ m_xFinish->set_help_id(HID_DBWIZ_FINISH);
+ ActivatePage();
+ setTitleBase(DBA_RES(STR_DBWIZARDTITLE));
+ m_xAssistant->set_current_page(0);
+}
+
+void ODbTypeWizDialogSetup::declareAuthDepPath( const OUString& _sURL, PathId _nPathId, const WizardPath& _rPaths)
+{
+ bool bHasAuthentication = DataSourceMetaData::getAuthentication( _sURL ) != AuthNone;
+
+ // collect the elements of the path
+ WizardPath aPath;
+
+ for (auto const& path : _rPaths)
+ {
+ if ( bHasAuthentication || ( path != PAGE_DBSETUPWIZARD_AUTHENTIFICATION ) )
+ aPath.push_back(path);
+ }
+
+ // call base method
+ ::vcl::RoadmapWizardMachine::declarePath( _nPathId, aPath );
+}
+
+OUString ODbTypeWizDialogSetup::getStateDisplayName(WizardState _nState) const
+{
+ OUString sRoadmapItem;
+ switch( _nState )
+ {
+ case PAGE_DBSETUPWIZARD_INTRO:
+ sRoadmapItem = m_sRM_IntroText;
+ break;
+
+ case PAGE_DBSETUPWIZARD_DBASE:
+ sRoadmapItem = m_sRM_dBaseText;
+ break;
+ case PAGE_DBSETUPWIZARD_ADO:
+ sRoadmapItem = m_sRM_ADOText;
+ break;
+ case PAGE_DBSETUPWIZARD_TEXT:
+ sRoadmapItem = m_sRM_TextText;
+ break;
+ case PAGE_DBSETUPWIZARD_MSACCESS:
+ sRoadmapItem = m_sRM_MSAccessText;
+ break;
+ case PAGE_DBSETUPWIZARD_LDAP:
+ sRoadmapItem = m_sRM_LDAPText;
+ break;
+ case PAGE_DBSETUPWIZARD_JDBC:
+ sRoadmapItem = m_sRM_JDBCText;
+ break;
+ case PAGE_DBSETUPWIZARD_ORACLE:
+ sRoadmapItem = m_sRM_OracleText;
+ break;
+ case PAGE_DBSETUPWIZARD_MYSQL_INTRO:
+ sRoadmapItem = m_sRM_MySQLText;
+ break;
+ case PAGE_DBSETUPWIZARD_MYSQL_JDBC:
+ sRoadmapItem = m_sRM_JDBCText;
+ break;
+ case PAGE_DBSETUPWIZARD_MYSQL_NATIVE:
+ sRoadmapItem = m_sRM_MySQLNativePageTitle;
+ break;
+ case PAGE_DBSETUPWIZARD_MYSQL_ODBC:
+ sRoadmapItem = m_sRM_ODBCText;
+ break;
+ case PAGE_DBSETUPWIZARD_ODBC:
+ sRoadmapItem = m_sRM_ODBCText;
+ break;
+ case PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET:
+ sRoadmapItem = m_sRM_DocumentOrSpreadSheetText;
+ break;
+ case PAGE_DBSETUPWIZARD_AUTHENTIFICATION:
+ sRoadmapItem = m_sRM_AuthentificationText;
+ break;
+ case PAGE_DBSETUPWIZARD_USERDEFINED:
+ sRoadmapItem = DBA_RES(STR_PAGETITLE_CONNECTION);
+ break;
+ case PAGE_DBSETUPWIZARD_FINAL:
+ sRoadmapItem = m_sRM_FinalText;
+ break;
+ default:
+ break;
+ }
+ return sRoadmapItem;
+}
+
+ODbTypeWizDialogSetup::~ODbTypeWizDialogSetup()
+{
+}
+
+IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnTypeSelected, OGeneralPage&, void)
+{
+ activateDatabasePath();
+}
+
+static void lcl_removeUnused(const ::comphelper::NamedValueCollection& _aOld,const ::comphelper::NamedValueCollection& _aNew,::comphelper::NamedValueCollection& _rDSInfo)
+{
+ _rDSInfo.merge(_aNew,true);
+ uno::Sequence< beans::NamedValue > aOldValues = _aOld.getNamedValues();
+ const beans::NamedValue* pIter = aOldValues.getConstArray();
+ const beans::NamedValue* pEnd = pIter + aOldValues.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( !_aNew.has(pIter->Name) )
+ {
+ _rDSInfo.remove(pIter->Name);
+ }
+ }
+}
+
+void DataSourceInfoConverter::convert(const Reference<XComponentContext> & xContext, const ::dbaccess::ODsnTypeCollection* _pCollection,const OUString& _sOldURLPrefix,const OUString& _sNewURLPrefix,const css::uno::Reference< css::beans::XPropertySet >& _xDatasource)
+{
+ if ( _pCollection->getPrefix(_sOldURLPrefix) == _pCollection->getPrefix(_sNewURLPrefix) )
+ return ;
+ uno::Sequence< beans::PropertyValue> aInfo;
+ _xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo;
+ ::comphelper::NamedValueCollection aDS(aInfo);
+
+ ::connectivity::DriversConfig aDriverConfig(xContext);
+
+ const ::comphelper::NamedValueCollection& aOldProperties = aDriverConfig.getProperties(_sOldURLPrefix);
+ const ::comphelper::NamedValueCollection& aNewProperties = aDriverConfig.getProperties(_sNewURLPrefix);
+ lcl_removeUnused(aOldProperties,aNewProperties,aDS);
+
+ aDS >>= aInfo;
+ _xDatasource->setPropertyValue(PROPERTY_INFO,uno::Any(aInfo));
+}
+
+void ODbTypeWizDialogSetup::activateDatabasePath()
+{
+ switch ( m_pGeneralPage->GetDatabaseCreationMode() )
+ {
+ case OGeneralPageWizard::eCreateNew:
+ {
+ sal_Int32 nCreateNewDBIndex = m_pCollection->getIndexOf( m_pGeneralPage->GetSelectedType() );
+ if ( nCreateNewDBIndex == -1 )
+ nCreateNewDBIndex = m_pCollection->getIndexOf( u"sdbc:dbase:" );
+ OSL_ENSURE( nCreateNewDBIndex != -1, "ODbTypeWizDialogSetup::activateDatabasePath: the GeneralPage should have prevented this!" );
+ activatePath( static_cast< PathId >( nCreateNewDBIndex + 1 ), true );
+
+ enableState(PAGE_DBSETUPWIZARD_FINAL );
+ enableButtons( WizardButtonFlags::FINISH, true);
+ }
+ break;
+ case OGeneralPageWizard::eConnectExternal:
+ {
+ OUString sOld = m_sURL;
+ m_sURL = m_pGeneralPage->GetSelectedType();
+ DataSourceInfoConverter::convert(getORB(), m_pCollection,sOld,m_sURL,m_pImpl->getCurrentDataSource());
+ ::dbaccess::DATASOURCE_TYPE eType = VerifyDataSourceType(m_pCollection->determineType(m_sURL));
+ if (eType == ::dbaccess::DST_UNKNOWN)
+ m_pCollection->determineType(m_sOldURL);
+
+ activatePath( static_cast<PathId>(m_pCollection->getIndexOf(m_sURL) + 1), true);
+ updateTypeDependentStates();
+ }
+ break;
+ case OGeneralPageWizard::eOpenExisting:
+ {
+ activatePath( static_cast<PathId>(m_pCollection->size() + 1), true );
+ enableButtons( WizardButtonFlags::FINISH, !m_pGeneralPage->GetSelectedDocumentURL().isEmpty() );
+ }
+ break;
+ default:
+ OSL_FAIL( "ODbTypeWizDialogSetup::activateDatabasePath: unknown creation mode!" );
+ }
+
+ enableButtons( WizardButtonFlags::NEXT, m_pGeneralPage->GetDatabaseCreationMode() != OGeneralPageWizard::eOpenExisting );
+ // TODO: this should go into the base class. Point is, we activate a path whose *last*
+ // step is also the current one. The base class should automatically disable
+ // the Next button in such a case. However, not for this patch ...
+}
+
+void ODbTypeWizDialogSetup::updateTypeDependentStates()
+{
+ bool bDoEnable = false;
+ bool bIsConnectionRequired = m_pCollection->isConnectionUrlRequired(m_sURL);
+ if (!bIsConnectionRequired)
+ {
+ bDoEnable = true;
+ }
+ else if ( m_sURL == m_sOldURL )
+ {
+ bDoEnable = m_bIsConnectable;
+ }
+ enableState(PAGE_DBSETUPWIZARD_AUTHENTIFICATION, bDoEnable);
+ enableState(PAGE_DBSETUPWIZARD_FINAL, bDoEnable );
+ enableButtons( WizardButtonFlags::FINISH, bDoEnable);
+}
+
+void ODbTypeWizDialogSetup::resetPages(const Reference< XPropertySet >& _rxDatasource)
+{
+ // remove all items which relate to indirect properties from the input set
+ // (without this, the following may happen: select an arbitrary data source where some indirect properties
+ // are set. Select another data source of the same type, where the indirect props are not set (yet). Then,
+ // the indirect property values of the first ds are shown in the second ds ...)
+ const ODbDataSourceAdministrationHelper::MapInt2String& rMap = m_pImpl->getIndirectProperties();
+ for (auto const& elem : rMap)
+ getWriteOutputSet()->ClearItem( static_cast<sal_uInt16>(elem.first) );
+
+ // extract all relevant data from the property set of the data source
+ m_pImpl->translateProperties(_rxDatasource, *getWriteOutputSet());
+}
+
+const SfxItemSet* ODbTypeWizDialogSetup::getOutputSet() const
+{
+ return m_pOutSet.get();
+}
+
+SfxItemSet* ODbTypeWizDialogSetup::getWriteOutputSet()
+{
+ return m_pOutSet.get();
+}
+
+std::pair< Reference<XConnection>,bool> ODbTypeWizDialogSetup::createConnection()
+{
+ return m_pImpl->createConnection();
+}
+
+Reference< XComponentContext > ODbTypeWizDialogSetup::getORB() const
+{
+ return m_pImpl->getORB();
+}
+
+Reference< XDriver > ODbTypeWizDialogSetup::getDriver()
+{
+ return m_pImpl->getDriver();
+}
+
+::dbaccess::DATASOURCE_TYPE ODbTypeWizDialogSetup::VerifyDataSourceType(const ::dbaccess::DATASOURCE_TYPE DatabaseType) const
+{
+ ::dbaccess::DATASOURCE_TYPE LocDatabaseType = DatabaseType;
+ if ((LocDatabaseType == ::dbaccess::DST_MYSQL_JDBC) || (LocDatabaseType == ::dbaccess::DST_MYSQL_ODBC) || (LocDatabaseType == ::dbaccess::DST_MYSQL_NATIVE))
+ {
+ if (m_pMySQLIntroPage != nullptr)
+ {
+ switch( m_pMySQLIntroPage->getMySQLMode() )
+ {
+ case OMySQLIntroPageSetup::VIA_JDBC:
+ return ::dbaccess::DST_MYSQL_JDBC;
+ case OMySQLIntroPageSetup::VIA_NATIVE:
+ return ::dbaccess::DST_MYSQL_NATIVE;
+ case OMySQLIntroPageSetup::VIA_ODBC:
+ return ::dbaccess::DST_MYSQL_ODBC;
+ }
+ }
+ }
+ return LocDatabaseType;
+}
+
+OUString ODbTypeWizDialogSetup::getDatasourceType(const SfxItemSet& _rSet) const
+{
+ OUString sRet = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(_rSet);
+ if (m_pMySQLIntroPage && m_pMySQLIntroPage->IsVisible())
+ {
+ switch( m_pMySQLIntroPage->getMySQLMode() )
+ {
+ case OMySQLIntroPageSetup::VIA_JDBC:
+ sRet = "sdbc:mysql:jdbc:";
+ break;
+ case OMySQLIntroPageSetup::VIA_NATIVE:
+ sRet = "sdbc:mysql:mysqlc:";
+ break;
+ case OMySQLIntroPageSetup::VIA_ODBC:
+ sRet = "sdbc:mysql:odbc:";
+ break;
+ }
+ }
+ return sRet;
+}
+
+void ODbTypeWizDialogSetup::clearPassword()
+{
+ m_pImpl->clearPassword();
+}
+
+void ODbTypeWizDialogSetup::SetIntroPage(OMySQLIntroPageSetup* pPage)
+{
+ m_pMySQLIntroPage = pPage;
+ m_pMySQLIntroPage->SetClickHdl(LINK( this, ODbTypeWizDialogSetup, ImplClickHdl ) );
+}
+
+void ODbTypeWizDialogSetup::SetGeneralPage(OGeneralPageWizard* pPage)
+{
+ m_pGeneralPage = pPage;
+ m_pGeneralPage->SetTypeSelectHandler(LINK(this, ODbTypeWizDialogSetup, OnTypeSelected));
+ m_pGeneralPage->SetCreationModeHandler(LINK( this, ODbTypeWizDialogSetup, OnChangeCreationMode ) );
+ m_pGeneralPage->SetDocumentSelectionHandler(LINK( this, ODbTypeWizDialogSetup, OnRecentDocumentSelected ) );
+ m_pGeneralPage->SetChooseDocumentHandler(LINK( this, ODbTypeWizDialogSetup, OnSingleDocumentChosen ) );
+}
+
+void ODbTypeWizDialogSetup::SetFinalPage(OFinalDBPageSetup* pPage)
+{
+ m_pFinalPage = pPage;
+}
+
+std::unique_ptr<BuilderPage> ODbTypeWizDialogSetup::createPage(WizardState _nState)
+{
+ std::unique_ptr<OGenericAdministrationPage> xPage;
+
+ OString sIdent(OString::number(_nState));
+ weld::Container* pPageContainer = m_xAssistant->append_page(sIdent);
+
+ switch(_nState)
+ {
+ case PAGE_DBSETUPWIZARD_INTRO:
+ xPage = std::make_unique<OGeneralPageWizard>(pPageContainer,this,*m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_DBASE:
+ xPage = OConnectionTabPageSetup::CreateDbaseTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_ADO:
+ xPage = OConnectionTabPageSetup::CreateADOTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_TEXT:
+ xPage = OTextConnectionPageSetup::CreateTextTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_ODBC:
+ xPage = OConnectionTabPageSetup::CreateODBCTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_JDBC:
+ xPage = OJDBCConnectionPageSetup::CreateJDBCTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_MYSQL_ODBC:
+ m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:odbc:")));
+ xPage = OConnectionTabPageSetup::CreateODBCTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_MYSQL_JDBC:
+ m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:jdbc:")));
+ xPage = OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+ case PAGE_DBSETUPWIZARD_MYSQL_NATIVE:
+ m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:mysqlc:")));
+ xPage = MySQLNativeSetupPage::Create(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_ORACLE:
+ xPage = OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_LDAP:
+ xPage = OLDAPConnectionPageSetup::CreateLDAPTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET:
+ xPage = OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_MSACCESS:
+ xPage = OConnectionTabPageSetup::CreateMSAccessTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+ case PAGE_DBSETUPWIZARD_MYSQL_INTRO:
+ xPage = OMySQLIntroPageSetup::CreateMySQLIntroTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_AUTHENTIFICATION:
+ xPage = OAuthentificationPageSetup::CreateAuthentificationTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_USERDEFINED:
+ xPage = OConnectionTabPageSetup::CreateUserDefinedTabPage(pPageContainer, this, *m_pOutSet);
+ break;
+
+ case PAGE_DBSETUPWIZARD_FINAL:
+ xPage = OFinalDBPageSetup::CreateFinalDBTabPageSetup(pPageContainer, this, *m_pOutSet);
+ break;
+ }
+
+ if ( xPage )
+ {
+ if ((_nState != PAGE_DBSETUPWIZARD_INTRO) && (_nState != PAGE_DBSETUPWIZARD_AUTHENTIFICATION))
+ {
+ xPage->SetModifiedHandler(LINK( this, ODbTypeWizDialogSetup, ImplModifiedHdl ) );
+ }
+
+ xPage->SetServiceFactory( m_pImpl->getORB() );
+ xPage->SetAdminDialog(this, this);
+
+ defaultButton( _nState == PAGE_DBSETUPWIZARD_FINAL ? WizardButtonFlags::FINISH : WizardButtonFlags::NEXT );
+ enableButtons( WizardButtonFlags::FINISH, _nState == PAGE_DBSETUPWIZARD_FINAL );
+ enableButtons( WizardButtonFlags::NEXT, _nState != PAGE_DBSETUPWIZARD_FINAL );
+
+ m_xAssistant->set_page_title(sIdent, getStateDisplayName(_nState));
+ }
+ return xPage;
+}
+
+IMPL_LINK(ODbTypeWizDialogSetup, ImplModifiedHdl, OGenericAdministrationPage const *, _pConnectionPageSetup, void)
+{
+ m_bIsConnectable = _pConnectionPageSetup->GetRoadmapStateValue( );
+ enableState(PAGE_DBSETUPWIZARD_FINAL, m_bIsConnectable);
+ enableState(PAGE_DBSETUPWIZARD_AUTHENTIFICATION, m_bIsConnectable);
+ if (getCurrentState() == PAGE_DBSETUPWIZARD_FINAL)
+ enableButtons( WizardButtonFlags::FINISH, true);
+ else
+ enableButtons( WizardButtonFlags::FINISH, m_bIsConnectable);
+ enableButtons( WizardButtonFlags::NEXT, m_bIsConnectable && (getCurrentState() != PAGE_DBSETUPWIZARD_FINAL));
+}
+
+IMPL_LINK(ODbTypeWizDialogSetup, ImplClickHdl, OMySQLIntroPageSetup*, _pMySQLIntroPageSetup, void)
+{
+ OUString sURLPrefix;
+ switch( _pMySQLIntroPageSetup->getMySQLMode() )
+ {
+ case OMySQLIntroPageSetup::VIA_ODBC:
+ sURLPrefix = "sdbc:mysql:odbc:";
+ break;
+ case OMySQLIntroPageSetup::VIA_JDBC:
+ sURLPrefix = "sdbc:mysql:jdbc:";
+ break;
+ case OMySQLIntroPageSetup::VIA_NATIVE:
+ sURLPrefix = "sdbc:mysql:mysqlc:";
+ break;
+ }
+ activatePath( static_cast<PathId>(m_pCollection->getIndexOf(sURLPrefix) + 1), true);
+}
+
+IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnChangeCreationMode, OGeneralPageWizard&, void)
+{
+ activateDatabasePath();
+}
+
+IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnRecentDocumentSelected, OGeneralPageWizard&, void)
+{
+ enableButtons( WizardButtonFlags::FINISH, !m_pGeneralPage->GetSelectedDocumentURL().isEmpty() );
+}
+
+IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnSingleDocumentChosen, OGeneralPageWizard&, void)
+{
+ if (prepareLeaveCurrentState(WizardTypes::eFinish))
+ onFinish();
+}
+
+void ODbTypeWizDialogSetup::enterState(WizardState _nState)
+{
+ m_sURL = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(*m_pOutSet);
+ RoadmapWizardMachine::enterState(_nState);
+ switch(_nState)
+ {
+ case PAGE_DBSETUPWIZARD_INTRO:
+ m_sOldURL = m_sURL;
+ break;
+ case PAGE_DBSETUPWIZARD_FINAL:
+ enableButtons( WizardButtonFlags::FINISH, true);
+ if ( m_pFinalPage )
+ m_pFinalPage->enableTableWizardCheckBox(m_pCollection->supportsTableCreation(m_sURL));
+ break;
+ }
+}
+
+void ODbTypeWizDialogSetup::saveDatasource()
+{
+ SfxTabPage* pPage = static_cast<SfxTabPage*>(GetPage(getCurrentState()));
+ if ( pPage )
+ pPage->FillItemSet(m_pOutSet.get());
+}
+
+bool ODbTypeWizDialogSetup::leaveState(WizardState _nState)
+{
+ if (_nState == PAGE_DBSETUPWIZARD_MYSQL_INTRO)
+ return true;
+ if ( _nState == PAGE_DBSETUPWIZARD_INTRO && m_sURL != m_sOldURL )
+ {
+ resetPages(m_pImpl->getCurrentDataSource());
+ }
+ SfxTabPage* pPage = static_cast<SfxTabPage*>(GetPage(_nState));
+ return pPage && pPage->DeactivatePage(m_pOutSet.get()) != DeactivateRC::KeepPage;
+}
+
+void ODbTypeWizDialogSetup::setTitle(const OUString& _sTitle)
+{
+ m_xAssistant->set_title(_sTitle);
+}
+
+void ODbTypeWizDialogSetup::enableConfirmSettings( bool /*_bEnable*/ )
+{
+}
+
+namespace
+{
+ bool lcl_handle( const Reference< XInteractionHandler2 >& _rxHandler, const Any& _rRequest )
+ {
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest( _rRequest );
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ pRequest->addContinuation( pAbort );
+
+ return _rxHandler->handleInteractionRequest( pRequest );
+ }
+}
+
+bool ODbTypeWizDialogSetup::SaveDatabaseDocument()
+{
+ Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(getORB(), nullptr) );
+ try
+ {
+ if (callSaveAsDialog())
+ {
+ m_pImpl->saveChanges(*m_pOutSet);
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ Reference< XModel > xModel( getDataSourceOrModel( xDatasource ), UNO_QUERY_THROW );
+ Reference< XStorable > xStore( xModel, UNO_QUERY_THROW );
+
+ if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eCreateNew )
+ CreateDatabase();
+
+ ::comphelper::NamedValueCollection aArgs( xModel->getArgs() );
+ aArgs.put( "Overwrite", true );
+ aArgs.put( "InteractionHandler", xHandler );
+ aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
+ aArgs.put( "IgnoreFirebirdMigration", true );
+
+ OUString sPath = ODbDataSourceAdministrationHelper::getDocumentUrl( *m_pOutSet );
+ xStore->storeAsURL( sPath, aArgs.getPropertyValues() );
+
+ if ( !m_pFinalPage || m_pFinalPage->IsDatabaseDocumentToBeRegistered() )
+ RegisterDataSourceByLocation( sPath );
+
+ return true;
+ }
+ }
+ catch ( const Exception& e )
+ {
+ Any aError = ::cppu::getCaughtException();
+ if ( xHandler.is() )
+ {
+ if ( !lcl_handle( xHandler, aError ) )
+ {
+ InteractiveIOException aRequest;
+ aRequest.Classification = InteractionClassification_ERROR;
+ if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) )
+ // assume saving the document failed
+ aRequest.Code = IOErrorCode_CANT_WRITE;
+ else
+ aRequest.Code = IOErrorCode_GENERAL;
+ aRequest.Message = e.Message;
+ aRequest.Context = e.Context;
+ lcl_handle( xHandler, Any( aRequest ) );
+ }
+ }
+ }
+ return false;
+}
+
+ bool ODbTypeWizDialogSetup::IsDatabaseDocumentToBeOpened() const
+ {
+ if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eOpenExisting )
+ return true;
+
+ if ( m_pFinalPage != nullptr )
+ return m_pFinalPage->IsDatabaseDocumentToBeOpened();
+
+ return true;
+ }
+
+ bool ODbTypeWizDialogSetup::IsTableWizardToBeStarted() const
+ {
+ if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eOpenExisting )
+ return false;
+
+ if ( m_pFinalPage != nullptr )
+ return m_pFinalPage->IsTableWizardToBeStarted();
+
+ return false;
+ }
+
+ void ODbTypeWizDialogSetup::CreateDatabase()
+ {
+ OUString sUrl;
+ const OUString eType = m_pGeneralPage->GetSelectedType();
+ if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase(eType) )
+ {
+ sUrl = eType;
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ OSL_ENSURE(xDatasource.is(),"DataSource is null!");
+ if ( xDatasource.is() )
+ xDatasource->setPropertyValue( PROPERTY_INFO, Any( m_pCollection->getDefaultDBSettings( eType ) ) );
+ m_pImpl->translateProperties(xDatasource,*m_pOutSet);
+ }
+ else if ( m_pCollection->isFileSystemBased(eType) )
+ {
+ Reference< XSimpleFileAccess3 > xSimpleFileAccess(ucb::SimpleFileAccess::create(getORB()));
+ INetURLObject aDBPathURL(m_sWorkPath);
+ aDBPathURL.Append(m_aDocURL.getBase());
+ createUniqueFolderName(&aDBPathURL);
+ sUrl = aDBPathURL.GetMainURL( INetURLObject::DecodeMechanism::NONE);
+ xSimpleFileAccess->createFolder(sUrl);
+ sUrl = eType + sUrl;
+ }
+ m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, sUrl));
+ m_pImpl->saveChanges(*m_pOutSet);
+ }
+
+ void ODbTypeWizDialogSetup::RegisterDataSourceByLocation(std::u16string_view _sPath)
+ {
+ Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource();
+ Reference< XDatabaseContext > xDatabaseContext( DatabaseContext::create(getORB()) );
+ INetURLObject aURL( _sPath );
+ OUString sFilename = aURL.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ OUString sDatabaseName = ::dbtools::createUniqueName(xDatabaseContext, sFilename, false);
+ xDatabaseContext->registerObject(sDatabaseName, xDatasource);
+ }
+
+ bool ODbTypeWizDialogSetup::callSaveAsDialog()
+ {
+ bool bRet = false;
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE, m_xAssistant.get());
+ aFileDlg.SetContext(sfx2::FileDialogHelper::BaseSaveAs);
+ std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter();
+ if ( pFilter )
+ {
+ OUString sDefaultName = DBA_RES( STR_DATABASEDEFAULTNAME );
+ OUString sExtension = pFilter->GetDefaultExtension();
+ sDefaultName += sExtension.replaceAt( 0, 1, u"" );
+ INetURLObject aWorkURL( m_sWorkPath );
+ aWorkURL.Append( sDefaultName );
+ sDefaultName = createUniqueFileName( aWorkURL );
+ aFileDlg.SetFileName( sDefaultName );
+
+ aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension());
+ aFileDlg.SetCurrentFilter(pFilter->GetUIName());
+ }
+ if ( aFileDlg.Execute() == ERRCODE_NONE )
+ {
+ m_aDocURL = INetURLObject(aFileDlg.GetPath());
+
+ if( m_aDocURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ OUString sFileName = m_aDocURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if ( ::utl::UCBContentHelper::IsDocument(sFileName) )
+ ::utl::UCBContentHelper::Kill(sFileName);
+ m_pOutSet->Put(SfxStringItem(DSID_DOCUMENT_URL, sFileName));
+ bRet = true;
+ }
+ }
+ return bRet;
+ }
+
+ void ODbTypeWizDialogSetup::createUniqueFolderName(INetURLObject* pURL)
+ {
+ Reference< XSimpleFileAccess3 > xSimpleFileAccess(ucb::SimpleFileAccess::create(getORB()));
+ OUString sLastSegmentName = pURL->getName();
+ bool bFolderExists = true;
+ sal_Int32 i = 1;
+ while (bFolderExists)
+ {
+ bFolderExists = xSimpleFileAccess->isFolder(pURL->GetMainURL( INetURLObject::DecodeMechanism::NONE ));
+ if (bFolderExists)
+ {
+ i++;
+ pURL->setName(OUStringConcatenation(sLastSegmentName + OUString::number(i)));
+ }
+ }
+ }
+
+ OUString ODbTypeWizDialogSetup::createUniqueFileName(const INetURLObject& _rURL)
+ {
+ Reference< XSimpleFileAccess3 > xSimpleFileAccess(ucb::SimpleFileAccess::create(getORB()));
+ OUString BaseName = _rURL.getBase();
+
+ bool bElementExists = true;
+
+ INetURLObject aExistenceCheck( _rURL );
+ for ( sal_Int32 i = 1; bElementExists; )
+ {
+ bElementExists = xSimpleFileAccess->exists( aExistenceCheck.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ if ( bElementExists )
+ {
+ aExistenceCheck.setBase( OUStringConcatenation(BaseName + OUString::number( i ) ));
+ ++i;
+ }
+ }
+ return aExistenceCheck.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ }
+
+ vcl::IWizardPageController* ODbTypeWizDialogSetup::getPageController(BuilderPage* pCurrentPage) const
+ {
+ OGenericAdministrationPage* pPage = static_cast<OGenericAdministrationPage*>(pCurrentPage);
+ return pPage;
+ }
+
+ namespace
+ {
+ typedef ::cppu::WeakImplHelper< XTerminateListener
+ > AsyncLoader_Base;
+ class AsyncLoader : public AsyncLoader_Base
+ {
+ private:
+ Reference< XComponentLoader > m_xFrameLoader;
+ Reference< XDesktop2 > m_xDesktop;
+ Reference< XInteractionHandler2 > m_xInteractionHandler;
+ OUString m_sURL;
+ OAsynchronousLink m_aAsyncCaller;
+
+ public:
+ AsyncLoader( const Reference< XComponentContext >& _rxORB, const OUString& _rURL );
+
+ void doLoadAsync();
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override;
+ virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ private:
+ DECL_LINK( OnOpenDocument, void*, void );
+ };
+
+ AsyncLoader::AsyncLoader( const Reference< XComponentContext >& _rxORB, const OUString& _rURL )
+ :m_sURL( _rURL )
+ ,m_aAsyncCaller( LINK( this, AsyncLoader, OnOpenDocument ) )
+ {
+ try
+ {
+ m_xDesktop.set( Desktop::create(_rxORB) );
+ m_xFrameLoader.set( m_xDesktop, UNO_QUERY_THROW );
+ m_xInteractionHandler = InteractionHandler::createWithParent(_rxORB, nullptr);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void AsyncLoader::doLoadAsync()
+ {
+ OSL_ENSURE( !m_aAsyncCaller.IsRunning(), "AsyncLoader:doLoadAsync: already running!" );
+
+ acquire();
+ try
+ {
+ if ( m_xDesktop.is() )
+ m_xDesktop->addTerminateListener( this );
+ }
+ catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
+
+ m_aAsyncCaller.Call();
+ }
+
+ IMPL_LINK_NOARG( AsyncLoader, OnOpenDocument, void*, void )
+ {
+ try
+ {
+ if ( m_xFrameLoader.is() )
+ {
+ ::comphelper::NamedValueCollection aLoadArgs;
+ aLoadArgs.put( "InteractionHandler", m_xInteractionHandler );
+ aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
+
+ Sequence< PropertyValue > aLoadArgPV;
+ aLoadArgs >>= aLoadArgPV;
+
+ m_xFrameLoader->loadComponentFromURL( m_sURL,
+ "_default",
+ FrameSearchFlag::ALL,
+ aLoadArgPV
+ );
+ }
+ }
+ catch( const Exception& )
+ {
+ // do not assert.
+ // Such an exception happens for instance of the to-be-loaded document does not exist anymore.
+ }
+
+ try
+ {
+ if ( m_xDesktop.is() )
+ m_xDesktop->removeTerminateListener( this );
+ }
+ catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
+
+ release();
+ }
+
+ void SAL_CALL AsyncLoader::queryTermination( const css::lang::EventObject& /*Event*/ )
+ {
+ throw TerminationVetoException();
+ }
+
+ void SAL_CALL AsyncLoader::notifyTermination( const css::lang::EventObject& /*Event*/ )
+ {
+ }
+ void SAL_CALL AsyncLoader::disposing( const css::lang::EventObject& /*Source*/ )
+ {
+ }
+ }
+
+ bool ODbTypeWizDialogSetup::onFinish()
+ {
+ if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eOpenExisting )
+ {
+ // we're not going to re-use the XModel we have - since the document the user
+ // wants us to load could be a non-database document. Instead, we asynchronously
+ // open the selected document. Thus, the wizard's return value is RET_CANCEL,
+ // which means to not continue loading the database document
+ if ( !WizardMachine::Finish() )
+ return false;
+
+ try
+ {
+ rtl::Reference<AsyncLoader> pAsyncLoader = new AsyncLoader( getORB(), m_pGeneralPage->GetSelectedDocumentURL() );
+ pAsyncLoader->doLoadAsync();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return true;
+ }
+
+ if (getCurrentState() != PAGE_DBSETUPWIZARD_FINAL)
+ {
+ skipUntil(PAGE_DBSETUPWIZARD_FINAL);
+ }
+ if (getCurrentState() == PAGE_DBSETUPWIZARD_FINAL)
+ return SaveDatabaseDocument() && WizardMachine::onFinish();
+ else
+ {
+ enableButtons( WizardButtonFlags::FINISH, false );
+ return false;
+ }
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/detailpages.cxx b/dbaccess/source/ui/dlg/detailpages.cxx
new file mode 100644
index 000000000..8a06d7de1
--- /dev/null
+++ b/dbaccess/source/ui/dlg/detailpages.cxx
@@ -0,0 +1,717 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_java.h>
+#include <core_resource.hxx>
+#include "detailpages.hxx"
+#include <sqlmessage.hxx>
+#include <dsmeta.hxx>
+#include "advancedsettings.hxx"
+#include "DbAdminImpl.hxx"
+#include <dsitems.hxx>
+#include "dbfindex.hxx"
+#include "dsnItem.hxx"
+
+#include <IItemSetHelper.hxx>
+#include <strings.hrc>
+
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#if HAVE_FEATURE_JAVA
+#include <jvmaccess/virtualmachine.hxx>
+#endif
+#include <connectivity/CommonTools.hxx>
+#include "DriverSettings.hxx"
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::dbtools;
+
+ OCommonBehaviourTabPage::OCommonBehaviourTabPage(weld::Container* pPage, weld::DialogController* pController,
+ const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& rCoreAttrs,
+ OCommonBehaviourTabPageFlags nControlFlags)
+ : OGenericAdministrationPage(pPage, pController, rUIXMLDescription, rId, rCoreAttrs)
+ , m_nControlFlags(nControlFlags)
+ {
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions)
+ {
+ m_xOptionsLabel = m_xBuilder->weld_label("optionslabel");
+ m_xOptionsLabel->show();
+ m_xOptions = m_xBuilder->weld_entry("options");
+ m_xOptions->show();
+ m_xOptions->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl));
+ }
+
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset)
+ {
+ m_xDataConvertLabel = m_xBuilder->weld_label("charsetheader");
+ m_xDataConvertLabel->show();
+ m_xCharsetLabel = m_xBuilder->weld_label("charsetlabel");
+ m_xCharsetLabel->show();
+ m_xCharset.reset(new CharSetListBox(m_xBuilder->weld_combo_box("charset")));
+ m_xCharset->show();
+ m_xCharset->connect_changed(LINK(this, OCommonBehaviourTabPage, CharsetSelectHdl));
+ }
+ }
+
+ IMPL_LINK_NOARG(OCommonBehaviourTabPage, CharsetSelectHdl, weld::ComboBox&, void)
+ {
+ callModifiedHdl();
+ }
+
+ OCommonBehaviourTabPage::~OCommonBehaviourTabPage()
+ {
+ m_xCharset.reset();
+ }
+
+ void OCommonBehaviourTabPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xOptionsLabel.get()));
+ }
+
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xCharsetLabel.get()));
+ }
+ }
+
+ void OCommonBehaviourTabPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions)
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xOptions.get()));
+
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset)
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xCharset->get_widget()));
+ }
+
+ void OCommonBehaviourTabPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ // collect the items
+ const SfxStringItem* pOptionsItem = _rSet.GetItem<SfxStringItem>(DSID_ADDITIONALOPTIONS);
+ const SfxStringItem* pCharsetItem = _rSet.GetItem<SfxStringItem>(DSID_CHARSET);
+
+ // forward the values to the controls
+ if (bValid)
+ {
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions)
+ {
+ m_xOptions->set_text(pOptionsItem->GetValue());
+ m_xOptions->save_value();
+ }
+
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset)
+ {
+ m_xCharset->SelectEntryByIanaName( pCharsetItem->GetValue() );
+ }
+ }
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ bool OCommonBehaviourTabPage::FillItemSet(SfxItemSet* _rSet)
+ {
+ bool bChangedSomething = false;
+
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions)
+ {
+ fillString(*_rSet,m_xOptions.get(),DSID_ADDITIONALOPTIONS,bChangedSomething);
+ }
+
+ if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset)
+ {
+ if ( m_xCharset->StoreSelectedCharSet( *_rSet, DSID_CHARSET ) )
+ bChangedSomething = true;
+ }
+
+ return bChangedSomething;
+ }
+
+ // ODbaseDetailsPage
+ ODbaseDetailsPage::ODbaseDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/dbasepage.ui", "DbasePage",
+ _rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset)
+ , m_xShowDeleted(m_xBuilder->weld_check_button("showDelRowsCheckbutton"))
+ , m_xFT_Message(m_xBuilder->weld_label("specMessageLabel"))
+ , m_xIndexes(m_xBuilder->weld_button("indiciesButton"))
+ {
+ m_xIndexes->connect_clicked(LINK(this, ODbaseDetailsPage, OnButtonClicked));
+ m_xShowDeleted->connect_toggled(LINK(this, ODbaseDetailsPage, OnButtonToggled));
+ }
+
+ ODbaseDetailsPage::~ODbaseDetailsPage()
+ {
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateDbase(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet)
+ {
+ return std::make_unique<ODbaseDetailsPage>(pPage, pController, *_rAttrSet);
+ }
+
+ void ODbaseDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ // get the DSN string (needed for the index dialog)
+ const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL);
+ const DbuTypeCollectionItem* pTypesItem = _rSet.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
+ ::dbaccess::ODsnTypeCollection* pTypeCollection = pTypesItem ? pTypesItem->getCollection() : nullptr;
+ if (pTypeCollection && pUrlItem && pUrlItem->GetValue().getLength())
+ m_sDsn = pTypeCollection->cutPrefix(pUrlItem->GetValue());
+
+ // get the other relevant items
+ const SfxBoolItem* pDeletedItem = _rSet.GetItem<SfxBoolItem>(DSID_SHOWDELETEDROWS);
+
+ if ( bValid )
+ {
+ m_xShowDeleted->set_active(pDeletedItem->GetValue());
+ m_xFT_Message->set_visible(m_xShowDeleted->get_active());
+ }
+
+ OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ bool ODbaseDetailsPage::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet);
+
+ fillBool(*_rSet, m_xShowDeleted.get(), DSID_SHOWDELETEDROWS, false, bChangedSomething);
+ return bChangedSomething;
+ }
+
+ IMPL_LINK_NOARG(ODbaseDetailsPage, OnButtonClicked, weld::Button&, void)
+ {
+ ODbaseIndexDialog aIndexDialog(GetFrameWeld(), m_sDsn);
+ aIndexDialog.run();
+ }
+
+ IMPL_LINK_NOARG(ODbaseDetailsPage, OnButtonToggled, weld::Toggleable&, void)
+ {
+ m_xFT_Message->set_visible(m_xShowDeleted->get_active());
+ // it was the checkbox -> we count as modified from now on
+ callModifiedHdl();
+ }
+
+
+ // OAdoDetailsPage
+ OAdoDetailsPage::OAdoDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/autocharsetpage.ui", "AutoCharset",
+ rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset )
+ {
+
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateAdo(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet)
+ {
+ return std::make_unique<OAdoDetailsPage>(pPage, pController, *rAttrSet);
+ }
+
+ // OOdbcDetailsPage
+ OOdbcDetailsPage::OOdbcDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/odbcpage.ui", "ODBC", rCoreAttrs,
+ OCommonBehaviourTabPageFlags::UseCharset | OCommonBehaviourTabPageFlags::UseOptions)
+ , m_xUseCatalog(m_xBuilder->weld_check_button("useCatalogCheckbutton"))
+ {
+ m_xUseCatalog->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick));
+ }
+
+ OOdbcDetailsPage::~OOdbcDetailsPage()
+ {
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateODBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet)
+ {
+ return std::make_unique<OOdbcDetailsPage>(pPage, pController, *pAttrSet);
+ }
+
+ bool OOdbcDetailsPage::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet);
+ fillBool(*_rSet,m_xUseCatalog.get(),DSID_USECATALOG,false,bChangedSomething);
+ return bChangedSomething;
+ }
+ void OOdbcDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ const SfxBoolItem* pUseCatalogItem = _rSet.GetItem<SfxBoolItem>(DSID_USECATALOG);
+
+ if ( bValid )
+ m_xUseCatalog->set_active(pUseCatalogItem->GetValue());
+
+ OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue);
+ }
+ // OOdbcDetailsPage
+ OUserDriverDetailsPage::OUserDriverDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/userdetailspage.ui", "UserDetailsPage",
+ rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset | OCommonBehaviourTabPageFlags::UseOptions)
+ , m_xFTHostname(m_xBuilder->weld_label("hostnameft"))
+ , m_xEDHostname(m_xBuilder->weld_entry("hostname"))
+ , m_xPortNumber(m_xBuilder->weld_label("portnumberft"))
+ , m_xNFPortNumber(m_xBuilder->weld_spin_button("portnumber"))
+ , m_xUseCatalog(m_xBuilder->weld_check_button("usecatalog"))
+ {
+ m_xUseCatalog->connect_toggled(LINK(this, OGenericAdministrationPage, OnControlModifiedButtonClick));
+ }
+
+ OUserDriverDetailsPage::~OUserDriverDetailsPage()
+ {
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateUser(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet)
+ {
+ return std::make_unique<OUserDriverDetailsPage>(pPage, pController, *pAttrSet);
+ }
+
+ bool OUserDriverDetailsPage::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet);
+
+ fillInt32(*_rSet,m_xNFPortNumber.get(),DSID_CONN_PORTNUMBER,bChangedSomething);
+ fillString(*_rSet,m_xEDHostname.get(),DSID_CONN_HOSTNAME,bChangedSomething);
+ fillBool(*_rSet,m_xUseCatalog.get(),DSID_USECATALOG,false,bChangedSomething);
+
+ return bChangedSomething;
+ }
+ void OUserDriverDetailsPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OCommonBehaviourTabPage::fillControls(_rControlList);
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xEDHostname.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xUseCatalog.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::SpinButton>(m_xNFPortNumber.get()));
+ }
+ void OUserDriverDetailsPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OCommonBehaviourTabPage::fillWindows(_rControlList);
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFTHostname.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xPortNumber.get()));
+ }
+ void OUserDriverDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ const SfxBoolItem* pUseCatalogItem = _rSet.GetItem<SfxBoolItem>(DSID_USECATALOG);
+ const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
+ const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_CONN_PORTNUMBER);
+
+ if ( bValid )
+ {
+ m_xEDHostname->set_text(pHostName->GetValue());
+ m_xEDHostname->save_value();
+
+ m_xNFPortNumber->set_value(pPortNumber->GetValue());
+ m_xNFPortNumber->save_value();
+
+ m_xUseCatalog->set_active(pUseCatalogItem->GetValue());
+ }
+
+ OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue);
+ }
+ // OMySQLODBCDetailsPage
+ OMySQLODBCDetailsPage::OMySQLODBCDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/autocharsetpage.ui", "AutoCharset",
+ rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset )
+ {
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateMySQLODBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet)
+ {
+ return std::make_unique<OMySQLODBCDetailsPage>(pPage, pController, *pAttrSet);
+ }
+
+ // OMySQLJDBCDetailsPage
+ OGeneralSpecialJDBCDetailsPage::OGeneralSpecialJDBCDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs ,sal_uInt16 _nPortId, bool bShowSocket)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/generalspecialjdbcdetailspage.ui", "GeneralSpecialJDBCDetails",
+ rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset)
+ , m_nPortId(_nPortId)
+ , m_bUseClass(true)
+ , m_xEDHostname(m_xBuilder->weld_entry("hostNameEntry"))
+ , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumberSpinbutton"))
+ , m_xFTSocket(m_xBuilder->weld_label("socketLabel"))
+ , m_xEDSocket(m_xBuilder->weld_entry("socketEntry"))
+ , m_xFTDriverClass(m_xBuilder->weld_label("driverClassLabel"))
+ , m_xEDDriverClass(m_xBuilder->weld_entry("jdbcDriverClassEntry"))
+ , m_xTestJavaDriver(m_xBuilder->weld_button("testDriverClassButton"))
+ {
+ const SfxStringItem* pUrlItem = rCoreAttrs.GetItem<SfxStringItem>(DSID_CONNECTURL);
+ const DbuTypeCollectionItem* pTypesItem = rCoreAttrs.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
+ ::dbaccess::ODsnTypeCollection* pTypeCollection = pTypesItem ? pTypesItem->getCollection() : nullptr;
+ if (pTypeCollection && pUrlItem && pUrlItem->GetValue().getLength() )
+ {
+ m_sDefaultJdbcDriverName = pTypeCollection->getJavaDriverClass(pUrlItem->GetValue());
+ }
+ if ( m_sDefaultJdbcDriverName.getLength() )
+ {
+ m_xEDDriverClass->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl));
+ m_xTestJavaDriver->connect_clicked(LINK(this,OGeneralSpecialJDBCDetailsPage,OnTestJavaClickHdl));
+ }
+ else
+ {
+ m_bUseClass = false;
+ m_xFTDriverClass->hide();
+ m_xEDDriverClass->hide();
+ m_xTestJavaDriver->hide();
+ }
+
+ m_xFTSocket->set_visible(bShowSocket && !m_bUseClass);
+ m_xEDSocket->set_visible(bShowSocket && !m_bUseClass);
+
+ m_xEDHostname->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl));
+ m_xNFPortNumber->connect_value_changed(LINK(this,OGenericAdministrationPage,OnControlSpinButtonModifyHdl));
+ m_xEDSocket->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl));
+ }
+
+ OGeneralSpecialJDBCDetailsPage::~OGeneralSpecialJDBCDetailsPage()
+ {
+ }
+
+ bool OGeneralSpecialJDBCDetailsPage::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet);
+ if ( m_bUseClass )
+ fillString(*_rSet,m_xEDDriverClass.get(),DSID_JDBCDRIVERCLASS,bChangedSomething);
+ fillString(*_rSet,m_xEDHostname.get(),DSID_CONN_HOSTNAME,bChangedSomething);
+ fillString(*_rSet,m_xEDSocket.get(),DSID_CONN_SOCKET,bChangedSomething);
+ fillInt32(*_rSet,m_xNFPortNumber.get(),m_nPortId,bChangedSomething );
+
+ return bChangedSomething;
+ }
+ void OGeneralSpecialJDBCDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ const SfxStringItem* pDrvItem = _rSet.GetItem<SfxStringItem>(DSID_JDBCDRIVERCLASS);
+ const SfxStringItem* pHostName = _rSet.GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
+ const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(m_nPortId);
+ const SfxStringItem* pSocket = _rSet.GetItem<SfxStringItem>(DSID_CONN_SOCKET);
+
+ if ( bValid )
+ {
+ if ( m_bUseClass )
+ {
+ m_xEDDriverClass->set_text(pDrvItem->GetValue());
+ m_xEDDriverClass->save_value();
+ }
+
+ m_xEDHostname->set_text(pHostName->GetValue());
+ m_xEDHostname->save_value();
+
+ m_xNFPortNumber->set_value(pPortNumber->GetValue());
+ m_xNFPortNumber->save_value();
+
+ m_xEDSocket->set_text(pSocket->GetValue());
+ m_xEDSocket->save_value();
+ }
+
+ OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue);
+
+ // to get the correct value when saveValue was called by base class
+ if ( m_bUseClass && m_xEDDriverClass->get_text().trim().isEmpty() )
+ {
+ m_xEDDriverClass->set_text(m_sDefaultJdbcDriverName);
+ m_xEDDriverClass->save_value();
+ }
+ }
+ IMPL_LINK_NOARG(OGeneralSpecialJDBCDetailsPage, OnTestJavaClickHdl, weld::Button&, void)
+ {
+ OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF");
+ OSL_ENSURE(m_bUseClass,"Who called me?");
+
+ bool bSuccess = false;
+#if HAVE_FEATURE_JAVA
+ try
+ {
+ if (!m_xEDDriverClass->get_text().trim().isEmpty())
+ {
+// TODO change jvmaccess
+ ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() );
+ m_xEDDriverClass->set_text(m_xEDDriverClass->get_text().trim()); // fdo#68341
+ bSuccess = ::connectivity::existsJavaClassByName(xJVM,m_xEDDriverClass->get_text());
+ }
+ }
+ catch(Exception&)
+ {
+ }
+#endif
+ TranslateId pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS;
+ const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error;
+ OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt);
+ aMsg.run();
+ }
+
+ void OGeneralSpecialJDBCDetailsPage::callModifiedHdl(weld::Widget* pControl)
+ {
+ if (m_bUseClass && pControl == m_xEDDriverClass.get())
+ m_xTestJavaDriver->set_sensitive(!m_xEDDriverClass->get_text().trim().isEmpty());
+
+ // tell the listener we were modified
+ OGenericAdministrationPage::callModifiedHdl();
+ }
+
+ // MySQLNativePage
+ MySQLNativePage::MySQLNativePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/mysqlnativepage.ui", "MysqlNativePage", rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset)
+ , m_xMySQLSettingsContainer(m_xBuilder->weld_widget("MySQLSettingsContainer"))
+ , m_xMySQLSettings(new MySQLNativeSettings(m_xMySQLSettingsContainer.get(), LINK(this,OGenericAdministrationPage,OnControlModified)))
+ , m_xSeparator1(m_xBuilder->weld_label("connectionheader"))
+ , m_xSeparator2(m_xBuilder->weld_label("userheader"))
+ , m_xUserNameLabel(m_xBuilder->weld_label("usernamelabel"))
+ , m_xUserName(m_xBuilder->weld_entry("username"))
+ , m_xPasswordRequired(m_xBuilder->weld_check_button("passwordrequired"))
+ {
+ m_xUserName->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl));
+ }
+
+ MySQLNativePage::~MySQLNativePage()
+ {
+ m_xMySQLSettings.reset();
+ }
+
+ void MySQLNativePage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OCommonBehaviourTabPage::fillControls( _rControlList );
+ m_xMySQLSettings->fillControls( _rControlList );
+
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Entry>(m_xUserName.get()));
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xPasswordRequired.get()));
+ }
+
+ void MySQLNativePage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OCommonBehaviourTabPage::fillWindows( _rControlList );
+ m_xMySQLSettings->fillWindows( _rControlList);
+
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xSeparator1.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xSeparator2.get()));
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xUserNameLabel.get()));
+ }
+
+ bool MySQLNativePage::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet( _rSet );
+
+ bChangedSomething |= m_xMySQLSettings->FillItemSet( _rSet );
+
+ if (m_xUserName->get_value_changed_from_saved())
+ {
+ _rSet->Put( SfxStringItem( DSID_USER, m_xUserName->get_text() ) );
+ _rSet->Put( SfxStringItem( DSID_PASSWORD, OUString()));
+ bChangedSomething = true;
+ }
+ fillBool(*_rSet,m_xPasswordRequired.get(),DSID_PASSWORDREQUIRED,false,bChangedSomething);
+
+ return bChangedSomething;
+ }
+ void MySQLNativePage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ m_xMySQLSettings->implInitControls( _rSet );
+
+ const SfxStringItem* pUidItem = _rSet.GetItem<SfxStringItem>(DSID_USER);
+ const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED);
+
+ if ( bValid )
+ {
+ m_xUserName->set_text(pUidItem->GetValue());
+ m_xUserName->save_value();
+ m_xPasswordRequired->set_active(pAllowEmptyPwd->GetValue());
+ }
+
+ OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateMySQLJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet )
+ {
+ return std::make_unique<OGeneralSpecialJDBCDetailsPage>(pPage, pController, *_rAttrSet,DSID_MYSQL_PORTNUMBER);
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateMySQLNATIVE(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet)
+ {
+ return std::make_unique<MySQLNativePage>(pPage, pController, *pAttrSet);
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateOracleJDBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet)
+ {
+ return std::make_unique<OGeneralSpecialJDBCDetailsPage>(pPage, pController, *_rAttrSet,DSID_ORACLE_PORTNUMBER, false);
+ }
+
+ // OLDAPDetailsPage
+ OLDAPDetailsPage::OLDAPDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/ldappage.ui", "LDAP",
+ rCoreAttrs, OCommonBehaviourTabPageFlags::NONE)
+ , m_xETBaseDN(m_xBuilder->weld_entry("baseDNEntry"))
+ , m_xCBUseSSL(m_xBuilder->weld_check_button("useSSLCheckbutton"))
+ , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumberSpinbutton"))
+ , m_xNFRowCount(m_xBuilder->weld_spin_button("LDAPRowCountspinbutton"))
+ {
+ m_xETBaseDN->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl));
+ m_xNFPortNumber->connect_value_changed(LINK(this,OGenericAdministrationPage,OnControlSpinButtonModifyHdl));
+ m_xNFRowCount->connect_value_changed(LINK(this,OGenericAdministrationPage,OnControlSpinButtonModifyHdl));
+
+ m_iNormalPort = 389;
+ m_iSSLPort = 636;
+ m_xCBUseSSL->connect_toggled(LINK(this, OLDAPDetailsPage, OnCheckBoxClick));
+ }
+
+ OLDAPDetailsPage::~OLDAPDetailsPage()
+ {
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateLDAP(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet)
+ {
+ return std::make_unique<OLDAPDetailsPage>(pPage, pController, *_rAttrSet);
+ }
+
+ bool OLDAPDetailsPage::FillItemSet( SfxItemSet* _rSet )
+ {
+ bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(_rSet);
+
+ fillString(*_rSet,m_xETBaseDN.get(),DSID_CONN_LDAP_BASEDN,bChangedSomething);
+ fillInt32(*_rSet,m_xNFPortNumber.get(),DSID_CONN_LDAP_PORTNUMBER,bChangedSomething);
+ fillInt32(*_rSet,m_xNFRowCount.get(),DSID_CONN_LDAP_ROWCOUNT,bChangedSomething);
+ fillBool(*_rSet,m_xCBUseSSL.get(),DSID_CONN_LDAP_USESSL,false,bChangedSomething);
+ return bChangedSomething;
+ }
+
+ IMPL_LINK(OLDAPDetailsPage, OnCheckBoxClick, weld::Toggleable&, rCheckBox, void)
+ {
+ OnControlModifiedButtonClick(rCheckBox);
+ callModifiedHdl();
+ if (m_xCBUseSSL->get_active())
+ {
+ m_iNormalPort = m_xNFPortNumber->get_value();
+ m_xNFPortNumber->set_value(m_iSSLPort);
+ }
+ else
+ {
+ m_iSSLPort = m_xNFPortNumber->get_value();
+ m_xNFPortNumber->set_value(m_iNormalPort);
+ }
+ }
+
+ void OLDAPDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ const SfxStringItem* pBaseDN = _rSet.GetItem<SfxStringItem>(DSID_CONN_LDAP_BASEDN);
+ const SfxBoolItem* pUseSSL = _rSet.GetItem<SfxBoolItem>(DSID_CONN_LDAP_USESSL);
+ const SfxInt32Item* pPortNumber = _rSet.GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER);
+ const SfxInt32Item* pRowCount = _rSet.GetItem<SfxInt32Item>(DSID_CONN_LDAP_ROWCOUNT);
+
+ if ( bValid )
+ {
+ m_xETBaseDN->set_text(pBaseDN->GetValue());
+ m_xNFPortNumber->set_value(pPortNumber->GetValue());
+ m_xNFRowCount->set_value(pRowCount->GetValue());
+ m_xCBUseSSL->set_active(pUseSSL->GetValue());
+ }
+
+ OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ // OTextDetailsPage
+ OTextDetailsPage::OTextDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/emptypage.ui", "EmptyPage", rCoreAttrs, OCommonBehaviourTabPageFlags::NONE)
+ , m_xTextConnectionHelper(new OTextConnectionHelper(m_xContainer.get(), TC_EXTENSION | TC_HEADER | TC_SEPARATORS | TC_CHARSET))
+ {
+ }
+
+ OTextDetailsPage::~OTextDetailsPage()
+ {
+ m_xTextConnectionHelper.reset();
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateText(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet)
+ {
+ return std::make_unique<OTextDetailsPage>(pPage, pController, *pAttrSet);
+ }
+
+ void OTextDetailsPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OCommonBehaviourTabPage::fillControls(_rControlList);
+ m_xTextConnectionHelper->fillControls(_rControlList);
+
+ }
+ void OTextDetailsPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ OCommonBehaviourTabPage::fillWindows(_rControlList);
+ m_xTextConnectionHelper->fillWindows(_rControlList);
+
+ }
+ void OTextDetailsPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ m_xTextConnectionHelper->implInitControls(_rSet, bValid);
+ OCommonBehaviourTabPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ bool OTextDetailsPage::FillItemSet( SfxItemSet* rSet )
+ {
+ bool bChangedSomething = OCommonBehaviourTabPage::FillItemSet(rSet);
+ bChangedSomething = m_xTextConnectionHelper->FillItemSet(*rSet, bChangedSomething);
+ return bChangedSomething;
+ }
+
+ bool OTextDetailsPage::prepareLeave()
+ {
+ return m_xTextConnectionHelper->prepareLeave();
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateGeneratedValuesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet)
+ {
+ return std::make_unique<GeneratedValuesPage>(pPage, pController, *_rAttrSet);
+ }
+
+ std::unique_ptr<SfxTabPage> ODriversSettings::CreateSpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet)
+ {
+ OUString eType = ODbDataSourceAdministrationHelper::getDatasourceType( *_rAttrSet );
+ DataSourceMetaData aMetaData( eType );
+ return std::make_unique<SpecialSettingsPage>(pPage, pController, *_rAttrSet, aMetaData);
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/detailpages.hxx b/dbaccess/source/ui/dlg/detailpages.hxx
new file mode 100644
index 000000000..2952f42e6
--- /dev/null
+++ b/dbaccess/source/ui/dlg/detailpages.hxx
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "adminpages.hxx"
+#include <charsetlistbox.hxx>
+#include "TextConnectionHelper.hxx"
+#include "admincontrols.hxx"
+
+#include <o3tl/typed_flags_set.hxx>
+
+enum class OCommonBehaviourTabPageFlags {
+ NONE = 0x0000,
+ UseCharset = 0x0002,
+ UseOptions = 0x0004,
+};
+namespace o3tl {
+ template<> struct typed_flags<OCommonBehaviourTabPageFlags> : is_typed_flags<OCommonBehaviourTabPageFlags, 0x0006> {};
+}
+
+namespace dbaui
+{
+ /** eases the implementation of tab pages handling user/password and/or character
+ set and/or generic options input
+ <BR>
+ The controls to be used have to be defined within the resource, as usual, but
+ this class does all the handling necessary.
+ */
+ class OCommonBehaviourTabPage : public OGenericAdministrationPage
+ {
+ OCommonBehaviourTabPageFlags m_nControlFlags;
+
+ std::unique_ptr<weld::Label> m_xOptionsLabel;
+ std::unique_ptr<weld::Entry> m_xOptions;
+
+ std::unique_ptr<weld::Label> m_xDataConvertLabel;
+ std::unique_ptr<weld::Label> m_xCharsetLabel;
+ std::unique_ptr<CharSetListBox> m_xCharset;
+
+ std::unique_ptr<weld::CheckButton> m_xAutoRetrievingEnabled;
+ std::unique_ptr<weld::Label> m_xAutoIncrementLabel;
+ std::unique_ptr<weld::Entry> m_xAutoIncrement;
+ std::unique_ptr<weld::Label> m_xAutoRetrievingLabel;
+ std::unique_ptr<weld::Entry> m_xAutoRetrieving;
+
+ public:
+ virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override;
+
+ OCommonBehaviourTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& _rCoreAttrs, OCommonBehaviourTabPageFlags nControlFlags);
+ protected:
+
+ virtual ~OCommonBehaviourTabPage() override;
+
+ // subclasses must override this, but it isn't pure virtual
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ // <method>OGenericAdministrationPage::fillControls</method>
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ // <method>OGenericAdministrationPage::fillWindows</method>
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ private:
+ DECL_LINK(CharsetSelectHdl, weld::ComboBox&, void);
+ };
+
+
+ // ODbaseDetailsPage
+ class ODbaseDetailsPage : public OCommonBehaviourTabPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+
+ ODbaseDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~ODbaseDetailsPage() override;
+ private:
+ OUString m_sDsn;
+
+ std::unique_ptr<weld::CheckButton> m_xShowDeleted;
+ std::unique_ptr<weld::Label> m_xFT_Message;
+ std::unique_ptr<weld::Button> m_xIndexes;
+
+ protected:
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ private:
+ DECL_LINK(OnButtonClicked, weld::Button&, void);
+ DECL_LINK(OnButtonToggled, weld::Toggleable&, void);
+ };
+
+ // OAdoDetailsPage
+ class OAdoDetailsPage : public OCommonBehaviourTabPage
+ {
+ public:
+ OAdoDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ };
+
+ // OOdbcDetailsPage
+ class OOdbcDetailsPage : public OCommonBehaviourTabPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+
+ OOdbcDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ virtual ~OOdbcDetailsPage() override;
+ protected:
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ private:
+ std::unique_ptr<weld::CheckButton> m_xUseCatalog;
+ };
+
+ // OUserDriverDetailsPage
+ class OUserDriverDetailsPage : public OCommonBehaviourTabPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+
+ OUserDriverDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~OUserDriverDetailsPage() override;
+ protected:
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ private:
+ std::unique_ptr<weld::Label> m_xFTHostname;
+ std::unique_ptr<weld::Entry> m_xEDHostname;
+ std::unique_ptr<weld::Label> m_xPortNumber;
+ std::unique_ptr<weld::SpinButton> m_xNFPortNumber;
+ std::unique_ptr<weld::CheckButton> m_xUseCatalog;
+ };
+
+ // OMySQLODBCDetailsPage
+ class OMySQLODBCDetailsPage : public OCommonBehaviourTabPage
+ {
+ public:
+ OMySQLODBCDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ };
+
+ // OGeneralSpecialJDBCDetailsPage
+ class OGeneralSpecialJDBCDetailsPage final : public OCommonBehaviourTabPage
+ {
+ public:
+ OGeneralSpecialJDBCDetailsPage(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& _rCoreAttrs,
+ sal_uInt16 _nPortId,
+ bool bShowSocket = true);
+ virtual ~OGeneralSpecialJDBCDetailsPage() override;
+
+ private:
+
+ virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override;
+
+ DECL_LINK(OnTestJavaClickHdl, weld::Button&, void);
+
+ OUString m_sDefaultJdbcDriverName;
+ sal_uInt16 m_nPortId;
+ bool m_bUseClass;
+
+ std::unique_ptr<weld::Entry> m_xEDHostname;
+ std::unique_ptr<weld::SpinButton> m_xNFPortNumber;
+ std::unique_ptr<weld::Label> m_xFTSocket;
+ std::unique_ptr<weld::Entry> m_xEDSocket;
+ std::unique_ptr<weld::Label> m_xFTDriverClass;
+ std::unique_ptr<weld::Entry> m_xEDDriverClass;
+ std::unique_ptr<weld::Button> m_xTestJavaDriver;
+ };
+
+ // MySQLNativePage
+ class MySQLNativePage : public OCommonBehaviourTabPage
+ {
+ public:
+ MySQLNativePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ virtual ~MySQLNativePage() override;
+
+ private:
+ std::unique_ptr<weld::Widget> m_xMySQLSettingsContainer;
+ std::unique_ptr<MySQLNativeSettings> m_xMySQLSettings;
+ std::unique_ptr<weld::Label> m_xSeparator1;
+ std::unique_ptr<weld::Label> m_xSeparator2;
+ std::unique_ptr<weld::Label> m_xUserNameLabel;
+ std::unique_ptr<weld::Entry> m_xUserName;
+ std::unique_ptr<weld::CheckButton> m_xPasswordRequired;
+
+ protected:
+ virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override;
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ };
+
+ // OOdbcDetailsPage
+ class OLDAPDetailsPage : public OCommonBehaviourTabPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+
+ OLDAPDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ virtual ~OLDAPDetailsPage() override;
+ protected:
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ private:
+ sal_Int32 m_iSSLPort;
+ sal_Int32 m_iNormalPort;
+
+ std::unique_ptr<weld::Entry> m_xETBaseDN;
+ std::unique_ptr<weld::CheckButton> m_xCBUseSSL;
+ std::unique_ptr<weld::SpinButton> m_xNFPortNumber;
+ std::unique_ptr<weld::SpinButton> m_xNFRowCount;
+
+ DECL_LINK(OnCheckBoxClick, weld::Toggleable&, void);
+ };
+
+ // OTextDetailsPage
+ class OTextDetailsPage : public OCommonBehaviourTabPage
+ {
+ public:
+ virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override;
+
+ OTextDetailsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ virtual ~OTextDetailsPage() override;
+
+ protected:
+ virtual bool prepareLeave() override;
+
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ private:
+ std::unique_ptr<OTextConnectionHelper> m_xTextConnectionHelper;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/directsql.cxx b/dbaccess/source/ui/dlg/directsql.cxx
new file mode 100644
index 000000000..ba5d9d3be
--- /dev/null
+++ b/dbaccess/source/ui/dlg/directsql.cxx
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <directsql.hxx>
+#include <sqledit.hxx>
+#include <strings.hxx>
+#include <strings.hrc>
+#include <comphelper/types.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::lang;
+
+ constexpr sal_Int32 g_nHistoryLimit = 20;
+
+ // DirectSQLDialog
+ DirectSQLDialog::DirectSQLDialog(weld::Window* _pParent, const Reference< XConnection >& _rxConn)
+ : GenericDialogController(_pParent, "dbaccess/ui/directsqldialog.ui", "DirectSQLDialog")
+ , m_xExecute(m_xBuilder->weld_button("execute"))
+ , m_xSQLHistory(m_xBuilder->weld_combo_box("sqlhistory"))
+ , m_xStatus(m_xBuilder->weld_text_view("status"))
+ , m_xDirectSQL(m_xBuilder->weld_check_button("directsql"))
+ , m_xShowOutput(m_xBuilder->weld_check_button("showoutput"))
+ , m_xOutput(m_xBuilder->weld_text_view("output"))
+ , m_xClose(m_xBuilder->weld_button("close"))
+ , m_xSQL(new SQLEditView(m_xBuilder->weld_scrolled_window("scrolledwindow", true)))
+ , m_xSQLEd(new weld::CustomWeld(*m_xBuilder, "sql", *m_xSQL))
+ , m_nStatusCount(1)
+ , m_xConnection(_rxConn)
+ , m_pClosingEvent(nullptr)
+ {
+ int nWidth = m_xStatus->get_approximate_digit_width() * 60;
+ int nHeight = m_xStatus->get_height_rows(7);
+
+ m_xSQLEd->set_size_request(nWidth, nHeight);
+ m_xStatus->set_size_request(-1, nHeight);
+ m_xOutput->set_size_request(-1, nHeight);
+
+ m_xSQL->GrabFocus();
+
+ m_xExecute->connect_clicked(LINK(this, DirectSQLDialog, OnExecute));
+ m_xClose->connect_clicked(LINK(this, DirectSQLDialog, OnCloseClick));
+ m_xSQLHistory->connect_changed(LINK(this, DirectSQLDialog, OnListEntrySelected));
+
+ // add a dispose listener to the connection
+ Reference< XComponent > xConnComp(m_xConnection, UNO_QUERY);
+ OSL_ENSURE(xConnComp.is(), "DirectSQLDialog::DirectSQLDialog: invalid connection!");
+ if (xConnComp.is())
+ startComponentListening(xConnComp);
+
+ m_xSQL->SetModifyHdl(LINK(this, DirectSQLDialog, OnStatementModified));
+ OnStatementModified(nullptr);
+ }
+
+ DirectSQLDialog::~DirectSQLDialog()
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (m_pClosingEvent)
+ Application::RemoveUserEvent(m_pClosingEvent);
+ stopAllComponentListening();
+ }
+
+ void DirectSQLDialog::_disposing( const EventObject& _rSource )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ assert(!m_pClosingEvent);
+
+ OSL_ENSURE(Reference< XConnection >(_rSource.Source, UNO_QUERY).get() == m_xConnection.get(),
+ "DirectSQLDialog::_disposing: where does this come from?");
+
+ {
+ OUString sMessage(DBA_RES(STR_DIRECTSQL_CONNECTIONLOST));
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sMessage));
+ xError->run();
+ }
+
+ m_pClosingEvent = Application::PostUserEvent(LINK(this, DirectSQLDialog, OnClose));
+ }
+
+ sal_Int32 DirectSQLDialog::getHistorySize() const
+ {
+ #ifdef DBG_UTIL
+ {
+ const char* pError = impl_CheckInvariants();
+ if (pError)
+ SAL_WARN("dbaccess.ui", "DirectSQLDialog::getHistorySize: " << pError);
+ }
+ #endif
+ return m_aStatementHistory.size();
+ }
+
+ void DirectSQLDialog::implEnsureHistoryLimit()
+ {
+ #ifdef DBG_UTIL
+ {
+ const char* pError = impl_CheckInvariants();
+ if (pError)
+ SAL_WARN("dbaccess.ui", "DirectSQLDialog::implEnsureHistoryLimit: " << pError);
+ }
+ #endif
+
+ if (getHistorySize() <= g_nHistoryLimit)
+ // nothing to do
+ return;
+
+ sal_Int32 nRemoveEntries = getHistorySize() - g_nHistoryLimit;
+ while (nRemoveEntries--)
+ {
+ m_aStatementHistory.pop_front();
+ m_aNormalizedHistory.pop_front();
+ m_xSQLHistory->remove(0);
+ }
+ }
+
+ void DirectSQLDialog::implAddToStatementHistory(const OUString& _rStatement)
+ {
+ #ifdef DBG_UTIL
+ {
+ const char* pError = impl_CheckInvariants();
+ if (pError)
+ SAL_WARN("dbaccess.ui", "DirectSQLDialog::implAddToStatementHistor: " << pError);
+ }
+ #endif
+
+ // add the statement to the history
+ m_aStatementHistory.push_back(_rStatement);
+
+ // normalize the statement, and remember the normalized form, too
+ OUString sNormalized = _rStatement.replaceAll("\n", " ");
+ m_aNormalizedHistory.push_back(sNormalized);
+
+ // add the normalized version to the list box
+ m_xSQLHistory->append_text(sNormalized);
+
+ // ensure that we don't exceed the history limit
+ implEnsureHistoryLimit();
+ }
+
+#ifdef DBG_UTIL
+ const char* DirectSQLDialog::impl_CheckInvariants() const
+ {
+ if (m_aStatementHistory.size() != m_aNormalizedHistory.size())
+ return "statement history is inconsistent!";
+
+ if (!m_xSQLHistory)
+ return "invalid listbox!";
+
+ if (m_aStatementHistory.size() != static_cast<size_t>(m_xSQLHistory->get_count()))
+ return "invalid listbox entry count!";
+
+ if (!m_xConnection.is())
+ return "have no connection!";
+
+ return nullptr;
+ }
+#endif
+
+ void DirectSQLDialog::implExecuteStatement(const OUString& _rStatement)
+ {
+ #ifdef DBG_UTIL
+ {
+ const char* pError = impl_CheckInvariants();
+ if (pError)
+ SAL_WARN("dbaccess.ui", "DirectSQLDialog::implExecuteStatement: " << pError);
+ }
+ #endif
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OUString sStatus;
+
+ // clear the output box
+ m_xOutput->set_text(OUString());
+ try
+ {
+ // create a statement
+ Reference< XStatement > xStatement = m_xConnection->createStatement();
+
+ if (m_xDirectSQL->get_active())
+ {
+ Reference< com::sun::star::beans::XPropertySet > xStatementProps(xStatement, UNO_QUERY_THROW);
+ try
+ {
+ xStatementProps->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, Any(false));
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ css::uno::Reference< css::sdbc::XMultipleResults > xMR ( xStatement, UNO_QUERY );
+
+ if (xMeta.is() && xMeta->supportsMultipleResultSets() && xMR.is())
+ {
+ bool hasRS = xStatement->execute(_rStatement);
+ if(hasRS)
+ {
+ css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet());
+ if (m_xShowOutput->get_active())
+ display(xRS);
+ }
+ else
+ addOutputText(
+ OUStringConcatenation(OUString::number(xMR->getUpdateCount()) + " rows updated\n"));
+ for (;;)
+ {
+ hasRS = xMR->getMoreResults();
+ if (!hasRS && xMR->getUpdateCount() == -1)
+ break;
+ if(hasRS)
+ {
+ css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet());
+ if (m_xShowOutput->get_active())
+ display(xRS);
+ }
+ }
+ }
+ else
+ {
+ const OUString upperStatement = _rStatement.toAsciiUpperCase();
+ if (upperStatement.startsWith("UPDATE"))
+ {
+ sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
+ addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows updated\n"));
+ }
+ else if (upperStatement.startsWith("INSERT"))
+ {
+ sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
+ addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows inserted\n"));
+ }
+ else if (upperStatement.startsWith("DELETE"))
+ {
+ sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
+ addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows deleted\n"));
+ }
+ else if (upperStatement.startsWith("CREATE"))
+ {
+ xStatement->executeUpdate(_rStatement);
+ addOutputText(u"Command executed\n");
+ }
+ else if (upperStatement.startsWith("SELECT") || m_xShowOutput->get_active())
+ {
+ css::uno::Reference< css::sdbc::XResultSet > xRS = xStatement->executeQuery(_rStatement);
+ if (m_xShowOutput->get_active())
+ display(xRS);
+ }
+ else
+ {
+ sal_Int32 resultCount = xStatement->executeUpdate(_rStatement);
+ addOutputText(OUStringConcatenation(OUString::number(resultCount) + " rows updated\n"));
+ }
+ }
+ // successful
+ sStatus = DBA_RES(STR_COMMAND_EXECUTED_SUCCESSFULLY);
+
+ // dispose the statement
+ ::comphelper::disposeComponent(xStatement);
+ }
+ catch(const SQLException& e)
+ {
+ sStatus = e.Message;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // add the status text
+ addStatusText(sStatus);
+ }
+
+ void DirectSQLDialog::display(const css::uno::Reference< css::sdbc::XResultSet >& xRS)
+ {
+ // get a handle for the rows
+ css::uno::Reference< css::sdbc::XRow > xRow( xRS, css::uno::UNO_QUERY );
+ // work through each of the rows
+ while (xRS->next())
+ {
+ // initialise the output line for each row
+ OUStringBuffer out;
+ // work along the columns until that are none left
+ try
+ {
+ int i = 1;
+ for (;;)
+ {
+ // be dumb, treat everything as a string
+ out.append(xRow->getString(i) + ",");
+ i++;
+ }
+ }
+ // trap for when we fall off the end of the row
+ catch (const SQLException&)
+ {
+ }
+ // report the output
+ addOutputText(out);
+ }
+ }
+
+ void DirectSQLDialog::addStatusText(std::u16string_view _rMessage)
+ {
+ OUString sAppendMessage = OUString::number(m_nStatusCount++) + ": " + _rMessage + "\n\n";
+
+ OUString sCompleteMessage = m_xStatus->get_text() + sAppendMessage;
+ m_xStatus->set_text(sCompleteMessage);
+
+ m_xStatus->select_region(sCompleteMessage.getLength(), sCompleteMessage.getLength());
+ }
+
+ void DirectSQLDialog::addOutputText(std::u16string_view _rMessage)
+ {
+ OUString sAppendMessage = OUString::Concat(_rMessage) + "\n";
+
+ OUString sCompleteMessage = m_xOutput->get_text() + sAppendMessage;
+ m_xOutput->set_text(sCompleteMessage);
+ }
+
+ void DirectSQLDialog::executeCurrent()
+ {
+ #ifdef DBG_UTIL
+ {
+ const char* pError = impl_CheckInvariants();
+ if (pError)
+ SAL_WARN("dbaccess.ui", "DirectSQLDialog::executeCurrent: " << pError);
+ }
+ #endif
+
+ OUString sStatement = m_xSQL->GetText();
+
+ // execute
+ implExecuteStatement(sStatement);
+
+ // add the statement to the history
+ implAddToStatementHistory(sStatement);
+
+ m_xSQL->GrabFocus();
+ }
+
+ void DirectSQLDialog::switchToHistory(sal_Int32 _nHistoryPos)
+ {
+ #ifdef DBG_UTIL
+ {
+ const char* pError = impl_CheckInvariants();
+ if (pError)
+ SAL_WARN("dbaccess.ui", "DirectSQLDialog::switchToHistory: " << pError);
+ }
+ #endif
+
+ if ((_nHistoryPos >= 0) && (_nHistoryPos < getHistorySize()))
+ {
+ // set the text in the statement editor
+ OUString sStatement = m_aStatementHistory[_nHistoryPos];
+ m_xSQL->SetTextAndUpdate(sStatement);
+ OnStatementModified(nullptr);
+
+ m_xSQL->GrabFocus();
+ }
+ else
+ OSL_FAIL("DirectSQLDialog::switchToHistory: invalid position!");
+ }
+
+ IMPL_LINK_NOARG( DirectSQLDialog, OnStatementModified, LinkParamNone*, void )
+ {
+ m_xExecute->set_sensitive(!m_xSQL->GetText().isEmpty());
+ }
+
+ IMPL_LINK_NOARG( DirectSQLDialog, OnCloseClick, weld::Button&, void )
+ {
+ m_xDialog->response(RET_OK);
+ }
+
+ IMPL_LINK_NOARG( DirectSQLDialog, OnClose, void*, void )
+ {
+ assert(m_pClosingEvent);
+ Application::RemoveUserEvent(m_pClosingEvent);
+ m_pClosingEvent = nullptr;
+
+ m_xDialog->response(RET_OK);
+ }
+
+ IMPL_LINK_NOARG( DirectSQLDialog, OnExecute, weld::Button&, void )
+ {
+ executeCurrent();
+ }
+
+ IMPL_LINK_NOARG( DirectSQLDialog, OnListEntrySelected, weld::ComboBox&, void )
+ {
+ const sal_Int32 nSelected = m_xSQLHistory->get_active();
+ if (nSelected != -1)
+ switchToHistory(nSelected);
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dlgattr.cxx b/dbaccess/source/ui/dlg/dlgattr.cxx
new file mode 100644
index 000000000..1df2acc20
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dlgattr.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dlgattr.hxx>
+
+#include <sfx2/tabdlg.hxx>
+
+#include <svx/numinf.hxx>
+
+#include <svx/dialogs.hrc>
+#include <svl/itemset.hxx>
+#include <svx/svxids.hrc>
+
+using namespace dbaui;
+
+
+SbaSbAttrDlg::SbaSbAttrDlg(weld::Widget* pParent, const SfxItemSet* pCellAttrs,
+ SvNumberFormatter* pFormatter, bool bHasFormat)
+ : SfxTabDialogController(pParent, "dbaccess/ui/fielddialog.ui", "FieldDialog", pCellAttrs)
+{
+ pNumberInfoItem.reset( new SvxNumberInfoItem( pFormatter, SID_ATTR_NUMBERFORMAT_INFO ) );
+
+ if (bHasFormat)
+ AddTabPage("format", RID_SVXPAGE_NUMBERFORMAT);
+ else
+ RemoveTabPage("format");
+ AddTabPage("alignment", RID_SVXPAGE_ALIGNMENT);
+}
+
+SbaSbAttrDlg::~SbaSbAttrDlg()
+{
+}
+
+void SbaSbAttrDlg::PageCreated(const OString& rPageId, SfxTabPage& rTabPage)
+{
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rPageId == "format")
+ {
+ aSet.Put (SvxNumberInfoItem( pNumberInfoItem->GetNumberFormatter(), SID_ATTR_NUMBERFORMAT_INFO));
+ rTabPage.PageCreated(aSet);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dlgsave.cxx b/dbaccess/source/ui/dlg/dlgsave.cxx
new file mode 100644
index 000000000..ce5d16881
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dlgsave.cxx
@@ -0,0 +1,351 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dlgsave.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <connectivity/dbtools.hxx>
+#include <UITools.hxx>
+#include <SqlNameEdit.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <objectnamecheck.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace dbaui;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+namespace dbaui
+{
+
+class OSaveAsDlgImpl
+{
+public:
+ OUString m_aQryLabel;
+ OUString m_sTblLabel;
+ OUString m_aName;
+ const IObjectNameCheck& m_rObjectNameCheck;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xMetaData;
+ sal_Int32 m_nType;
+ SADFlags m_nFlags;
+
+ OSQLNameChecker m_aChecker;
+
+ std::unique_ptr<weld::Label> m_xDescription;
+ std::unique_ptr<weld::Label> m_xCatalogLbl;
+ std::unique_ptr<weld::ComboBox> m_xCatalog;
+ std::unique_ptr<weld::Label> m_xSchemaLbl;
+ std::unique_ptr<weld::ComboBox> m_xSchema;
+ std::unique_ptr<weld::Label> m_xLabel;
+ std::unique_ptr<weld::Entry> m_xTitle;
+ std::unique_ptr<weld::Button> m_xPB_OK;
+
+ DECL_LINK(TextFilterHdl, OUString&, bool);
+
+ OSaveAsDlgImpl( weld::Builder* pParent, sal_Int32 _rType,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const OUString& rDefault,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags);
+ OSaveAsDlgImpl( weld::Builder* pParent,
+ const OUString& rDefault,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags);
+};
+
+} // dbaui
+
+IMPL_LINK(OSaveAsDlgImpl, TextFilterHdl, OUString&, rTest, bool)
+{
+ OUString sCorrected;
+ if (m_aChecker.checkString(rTest, sCorrected))
+ rTest = sCorrected;
+ return true;
+}
+
+OSaveAsDlgImpl::OSaveAsDlgImpl(weld::Builder* pBuilder,
+ sal_Int32 _rType,
+ const Reference< XConnection>& _xConnection,
+ const OUString& rDefault,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags)
+ : m_aQryLabel(DBA_RES(STR_QRY_LABEL))
+ , m_sTblLabel(DBA_RES(STR_TBL_LABEL))
+ , m_aName(rDefault)
+ , m_rObjectNameCheck( _rObjectNameCheck )
+ , m_nType(_rType)
+ , m_nFlags(_nFlags)
+ , m_aChecker(OUString())
+ , m_xDescription(pBuilder->weld_label("descriptionft"))
+ , m_xCatalogLbl(pBuilder->weld_label("catalogft"))
+ , m_xCatalog(pBuilder->weld_combo_box("catalog"))
+ , m_xSchemaLbl(pBuilder->weld_label("schemaft"))
+ , m_xSchema(pBuilder->weld_combo_box("schema"))
+ , m_xLabel(pBuilder->weld_label("titleft"))
+ , m_xTitle(pBuilder->weld_entry("title"))
+ , m_xPB_OK(pBuilder->weld_button("ok"))
+{
+ if ( _xConnection.is() )
+ m_xMetaData = _xConnection->getMetaData();
+
+ if (m_xMetaData.is())
+ {
+ OUString sExtraNameChars(m_xMetaData->getExtraNameCharacters());
+ m_aChecker.setAllowedChars(sExtraNameChars);
+ }
+
+ m_xTitle->connect_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl));
+ m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl));
+ m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl));
+}
+
+OSaveAsDlgImpl::OSaveAsDlgImpl(weld::Builder* pBuilder,
+ const OUString& rDefault,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags)
+ : m_aQryLabel(DBA_RES(STR_QRY_LABEL))
+ , m_sTblLabel(DBA_RES(STR_TBL_LABEL))
+ , m_aName(rDefault)
+ , m_rObjectNameCheck( _rObjectNameCheck )
+ , m_nType(CommandType::COMMAND)
+ , m_nFlags(_nFlags)
+ , m_aChecker(OUString())
+ , m_xDescription(pBuilder->weld_label("descriptionft"))
+ , m_xCatalogLbl(pBuilder->weld_label("catalogft"))
+ , m_xCatalog(pBuilder->weld_combo_box("catalog"))
+ , m_xSchemaLbl(pBuilder->weld_label("schemaft"))
+ , m_xSchema(pBuilder->weld_combo_box("schema"))
+ , m_xLabel(pBuilder->weld_label("titleft"))
+ , m_xTitle(pBuilder->weld_entry("title"))
+ , m_xPB_OK(pBuilder->weld_button("ok"))
+{
+ m_xTitle->connect_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl));
+ m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl));
+ m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl));
+}
+
+using namespace ::com::sun::star::lang;
+
+namespace
+{
+typedef Reference< XResultSet > (SAL_CALL XDatabaseMetaData::*FGetMetaStrings)();
+
+void lcl_fillComboList( weld::ComboBox& _rList, const Reference< XConnection >& _rxConnection,
+ FGetMetaStrings GetAll, const OUString& _rCurrent )
+{
+ try {
+ Reference< XDatabaseMetaData > xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW );
+
+ Reference< XResultSet > xRes = (xMetaData.get()->*GetAll)();
+ Reference< XRow > xRow( xRes, UNO_QUERY_THROW );
+ OUString sValue;
+ while ( xRes->next() ) {
+ sValue = xRow->getString( 1 );
+ if ( !xRow->wasNull() )
+ _rList.append_text( sValue );
+ }
+
+ int nPos = _rList.find_text( _rCurrent );
+ if (nPos != -1)
+ _rList.set_active( nPos );
+ else
+ _rList.set_active( 0 );
+ } catch( const Exception& ) {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+}
+
+OSaveAsDlg::OSaveAsDlg( weld::Window * pParent,
+ sal_Int32 _rType,
+ const Reference< XComponentContext >& _rxContext,
+ const Reference< XConnection>& _xConnection,
+ const OUString& rDefault,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags)
+ : GenericDialogController(pParent, "dbaccess/ui/savedialog.ui", "SaveDialog")
+ , m_xContext( _rxContext )
+{
+ m_pImpl.reset( new OSaveAsDlgImpl(m_xBuilder.get(),_rType,_xConnection,rDefault,_rObjectNameCheck,_nFlags) );
+
+ switch (_rType) {
+ case CommandType::QUERY:
+ implInitOnlyTitle(m_pImpl->m_aQryLabel);
+ break;
+
+ case CommandType::TABLE:
+ OSL_ENSURE( m_pImpl->m_xMetaData.is(), "OSaveAsDlg::OSaveAsDlg: no meta data for entering table names: this will crash!" );
+ {
+ m_pImpl->m_xLabel->set_label(m_pImpl->m_sTblLabel);
+ if(m_pImpl->m_xMetaData.is() && !m_pImpl->m_xMetaData->supportsCatalogsInTableDefinitions()) {
+ m_pImpl->m_xCatalogLbl->hide();
+ m_pImpl->m_xCatalog->hide();
+ } else {
+ // now fill the catalogs
+ lcl_fillComboList( *m_pImpl->m_xCatalog, _xConnection,
+ &XDatabaseMetaData::getCatalogs, _xConnection->getCatalog() );
+ }
+
+ if ( !m_pImpl->m_xMetaData->supportsSchemasInTableDefinitions()) {
+ m_pImpl->m_xSchemaLbl->hide();
+ m_pImpl->m_xSchema->hide();
+ } else {
+ lcl_fillComboList( *m_pImpl->m_xSchema, _xConnection,
+ &XDatabaseMetaData::getSchemas, m_pImpl->m_xMetaData->getUserName() );
+ }
+
+ OSL_ENSURE(m_pImpl->m_xMetaData.is(),"The metadata can not be null!");
+ if(m_pImpl->m_aName.indexOf('.') != -1) {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_pImpl->m_xMetaData,
+ m_pImpl->m_aName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ int nPos = m_pImpl->m_xCatalog->find_text(sCatalog);
+ if (nPos != -1)
+ m_pImpl->m_xCatalog->set_active(nPos);
+
+ if ( !sSchema.isEmpty() ) {
+ nPos = m_pImpl->m_xSchema->find_text(sSchema);
+ if (nPos != -1)
+ m_pImpl->m_xSchema->set_active(nPos);
+ }
+ m_pImpl->m_xTitle->set_text(sTable);
+ } else
+ m_pImpl->m_xTitle->set_text(m_pImpl->m_aName);
+ m_pImpl->m_xTitle->select_region(0, -1);
+
+ sal_Int32 nLength = m_pImpl->m_xMetaData.is() ? m_pImpl->m_xMetaData->getMaxTableNameLength() : 0;
+ if (nLength)
+ {
+ m_pImpl->m_xTitle->set_max_length(nLength);
+ m_pImpl->m_xSchema->set_entry_max_length(nLength);
+ m_pImpl->m_xCatalog->set_entry_max_length(nLength);
+ }
+
+ bool bCheck = _xConnection.is() && isSQL92CheckEnabled(_xConnection);
+ m_pImpl->m_aChecker.setCheck(bCheck); // enable non valid sql chars as well
+ }
+ break;
+
+ default:
+ OSL_FAIL( "OSaveAsDlg::OSaveAsDlg: Type not supported yet!" );
+ }
+
+ implInit();
+}
+
+OSaveAsDlg::OSaveAsDlg(weld::Window * pParent,
+ const Reference< XComponentContext >& _rxContext,
+ const OUString& rDefault,
+ const OUString& _sLabel,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags)
+ : GenericDialogController(pParent, "dbaccess/ui/savedialog.ui", "SaveDialog")
+ , m_xContext( _rxContext )
+{
+ m_pImpl.reset( new OSaveAsDlgImpl(m_xBuilder.get(),rDefault,_rObjectNameCheck,_nFlags) );
+ implInitOnlyTitle(_sLabel);
+ implInit();
+}
+
+OSaveAsDlg::~OSaveAsDlg()
+{
+}
+
+IMPL_LINK_NOARG(OSaveAsDlg, ButtonClickHdl, weld::Button&, void)
+{
+ m_pImpl->m_aName = m_pImpl->m_xTitle->get_text();
+
+ OUString sNameToCheck( m_pImpl->m_aName );
+
+ if ( m_pImpl->m_nType == CommandType::TABLE ) {
+ sNameToCheck = ::dbtools::composeTableName(
+ m_pImpl->m_xMetaData,
+ getCatalog(),
+ getSchema(),
+ sNameToCheck,
+ false, // no quoting
+ ::dbtools::EComposeRule::InDataManipulation
+ );
+ }
+
+ SQLExceptionInfo aNameError;
+ if ( m_pImpl->m_rObjectNameCheck.isNameValid( sNameToCheck, aNameError ) )
+ m_xDialog->response(RET_OK);
+
+ showError(aNameError, m_xDialog->GetXWindow(), m_xContext);
+ m_pImpl->m_xTitle->grab_focus();
+}
+
+IMPL_LINK_NOARG(OSaveAsDlg, EditModifyHdl, weld::Entry&, void)
+{
+ m_pImpl->m_xPB_OK->set_sensitive(!m_pImpl->m_xTitle->get_text().isEmpty());
+}
+
+void OSaveAsDlg::implInitOnlyTitle(const OUString& _rLabel)
+{
+ m_pImpl->m_xLabel->set_label(_rLabel);
+ m_pImpl->m_xCatalogLbl->hide();
+ m_pImpl->m_xCatalog->hide();
+ m_pImpl->m_xSchemaLbl->hide();
+ m_pImpl->m_xSchema->hide();
+
+ m_pImpl->m_xTitle->set_text(m_pImpl->m_aName);
+ m_pImpl->m_aChecker.setCheck(false); // enable non valid sql chars as well
+}
+
+void OSaveAsDlg::implInit()
+{
+ if ( !( m_pImpl->m_nFlags & SADFlags::AdditionalDescription ) ) {
+ // hide the description window
+ m_pImpl->m_xDescription->hide();
+ }
+
+ if ( SADFlags::TitlePasteAs == ( m_pImpl->m_nFlags & SADFlags::TitlePasteAs ) )
+ m_xDialog->set_title( DBA_RES( STR_TITLE_PASTE_AS ) );
+ else if ( SADFlags::TitleRename == ( m_pImpl->m_nFlags & SADFlags::TitleRename ) )
+ m_xDialog->set_title( DBA_RES( STR_TITLE_RENAME ) );
+
+ m_pImpl->m_xPB_OK->connect_clicked(LINK(this,OSaveAsDlg,ButtonClickHdl));
+ m_pImpl->m_xTitle->connect_changed(LINK(this,OSaveAsDlg,EditModifyHdl));
+ m_pImpl->m_xTitle->grab_focus();
+}
+
+const OUString& OSaveAsDlg::getName() const
+{
+ return m_pImpl->m_aName;
+}
+OUString OSaveAsDlg::getCatalog() const
+{
+ return m_pImpl->m_xCatalog->get_visible() ? m_pImpl->m_xCatalog->get_active_text() : OUString();
+}
+OUString OSaveAsDlg::getSchema() const
+{
+ return m_pImpl->m_xSchema->get_visible() ? m_pImpl->m_xSchema->get_active_text() : OUString();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dlgsize.cxx b/dbaccess/source/ui/dlg/dlgsize.cxx
new file mode 100644
index 000000000..544d9577f
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dlgsize.cxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dlgsize.hxx>
+
+namespace dbaui
+{
+
+#define DEF_ROW_HEIGHT 45
+#define DEF_COL_WIDTH 227
+
+DlgSize::DlgSize(weld::Window* pParent, sal_Int32 nVal, bool bRow, sal_Int32 _nAlternativeStandard )
+ : GenericDialogController(pParent, bRow ? OUString("dbaccess/ui/rowheightdialog.ui") : OUString("dbaccess/ui/colwidthdialog.ui"),
+ bRow ? OString("RowHeightDialog") : OString("ColWidthDialog"))
+ , m_nPrevValue(nVal)
+ , m_xMF_VALUE(m_xBuilder->weld_metric_spin_button("value", FieldUnit::CM))
+ , m_xCB_STANDARD(m_xBuilder->weld_check_button("automatic"))
+{
+ sal_Int32 nStandard(bRow ? DEF_ROW_HEIGHT : DEF_COL_WIDTH);
+ if ( _nAlternativeStandard > 0 )
+ nStandard = _nAlternativeStandard;
+ m_xCB_STANDARD->connect_toggled(LINK(this,DlgSize,CbClickHdl));
+
+ bool bDefault = -1 == nVal;
+ m_xCB_STANDARD->set_active(bDefault);
+ if (bDefault)
+ {
+ SetValue(nStandard);
+ m_nPrevValue = nStandard;
+ }
+ CbClickHdl(*m_xCB_STANDARD);
+}
+
+DlgSize::~DlgSize()
+{
+}
+
+void DlgSize::SetValue( sal_Int32 nVal )
+{
+ m_xMF_VALUE->set_value(nVal, FieldUnit::CM );
+}
+
+sal_Int32 DlgSize::GetValue() const
+{
+ if (m_xCB_STANDARD->get_active())
+ return -1;
+ return static_cast<sal_Int32>(m_xMF_VALUE->get_value( FieldUnit::CM ));
+}
+
+IMPL_LINK_NOARG(DlgSize, CbClickHdl, weld::Toggleable&, void)
+{
+ m_xMF_VALUE->set_sensitive(!m_xCB_STANDARD->get_active());
+ if (m_xCB_STANDARD->get_active())
+ {
+ // don't use getValue as this will use m_xCB_STANDARD->to determine if we're standard
+ m_nPrevValue = static_cast<sal_Int32>(m_xMF_VALUE->get_value(FieldUnit::CM));
+ m_xMF_VALUE->set_text("");
+ }
+ else
+ {
+ SetValue(m_nPrevValue);
+ }
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dsnItem.hxx b/dbaccess/source/ui/dlg/dsnItem.hxx
new file mode 100644
index 000000000..4ae414881
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dsnItem.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/poolitem.hxx>
+
+namespace dbaccess
+{
+ class ODsnTypeCollection;
+}
+namespace dbaui
+{
+ // DbuTypeCollectionItem
+ /** allows an ODsnTypeCollection to be transported in an SfxItemSet
+ */
+ class DbuTypeCollectionItem : public SfxPoolItem
+ {
+ ::dbaccess::ODsnTypeCollection* m_pCollection;
+
+ public:
+ DbuTypeCollectionItem(sal_Int16 nWhich, ::dbaccess::ODsnTypeCollection* _pCollection);
+ DbuTypeCollectionItem(const DbuTypeCollectionItem& _rSource);
+
+ virtual bool operator==(const SfxPoolItem& _rItem) const override;
+ virtual DbuTypeCollectionItem* Clone(SfxItemPool* _pPool = nullptr) const override;
+
+ ::dbaccess::ODsnTypeCollection* getCollection() const { return m_pCollection; }
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dsselect.cxx b/dbaccess/source/ui/dlg/dsselect.cxx
new file mode 100644
index 000000000..4c0b9a836
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dsselect.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "dsselect.hxx"
+
+#include <com/sun/star/sdbcx/XCreateCatalog.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+
+namespace dbaui
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::ui::dialogs;
+
+ODatasourceSelectDialog::ODatasourceSelectDialog(weld::Window* _pParent, const std::set<OUString>& _rDatasources)
+ : GenericDialogController(_pParent, "dbaccess/ui/choosedatasourcedialog.ui", "ChooseDataSourceDialog")
+ , m_xDatasource(m_xBuilder->weld_tree_view("treeview"))
+ , m_xOk(m_xBuilder->weld_button("ok"))
+ , m_xCancel(m_xBuilder->weld_button("cancel"))
+ , m_xManageDatasources(m_xBuilder->weld_button("organize"))
+{
+ m_xDatasource->set_size_request(-1, m_xDatasource->get_height_rows(6));
+
+ fillListBox(_rDatasources);
+#ifdef HAVE_ODBC_ADMINISTRATION
+ // allow ODBC datasource management
+ m_xManageDatasources->show();
+ m_xManageDatasources->set_sensitive(true);
+ m_xManageDatasources->connect_clicked(LINK(this,ODatasourceSelectDialog,ManageClickHdl));
+#endif
+ m_xDatasource->connect_row_activated(LINK(this,ODatasourceSelectDialog,ListDblClickHdl));
+}
+
+ODatasourceSelectDialog::~ODatasourceSelectDialog()
+{
+}
+
+IMPL_LINK(ODatasourceSelectDialog, ListDblClickHdl, weld::TreeView&, rListBox, bool)
+{
+ if (rListBox.n_children())
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+short ODatasourceSelectDialog::run()
+{
+ short nRet = GenericDialogController::run();
+#ifdef HAVE_ODBC_ADMINISTRATION
+ if (m_xODBCManagement.get())
+ m_xODBCManagement->disableCallback();
+#endif
+ return nRet;
+}
+
+#ifdef HAVE_ODBC_ADMINISTRATION
+IMPL_LINK_NOARG(ODatasourceSelectDialog, ManageClickHdl, weld::Button&, void)
+{
+ if ( !m_xODBCManagement.get() )
+ m_xODBCManagement.reset( new OOdbcManagement( LINK( this, ODatasourceSelectDialog, ManageProcessFinished ) ) );
+
+ if ( !m_xODBCManagement->manageDataSources_async() )
+ {
+ // TODO: error message
+ m_xDatasource->grab_focus();
+ m_xManageDatasources->set_sensitive(false);
+ return;
+ }
+
+ m_xDatasource->set_sensitive(false);
+ m_xOk->set_sensitive(false);
+ m_xCancel->set_sensitive(false);
+ m_xManageDatasources->set_sensitive(false);
+
+ SAL_WARN_IF( !m_xODBCManagement->isRunning(), "dbaccess.ui", "ODatasourceSelectDialog::ManageClickHdl: success, but not running - you were *fast*!" );
+}
+
+IMPL_LINK_NOARG( ODatasourceSelectDialog, ManageProcessFinished, void*, void )
+{
+ m_xODBCManagement->receivedCallback();
+
+ std::set<OUString> aOdbcDatasources;
+ OOdbcEnumeration aEnumeration;
+ aEnumeration.getDatasourceNames( aOdbcDatasources );
+ fillListBox( aOdbcDatasources );
+
+ m_xDatasource->set_sensitive(true);
+ m_xOk->set_sensitive(true);
+ m_xCancel->set_sensitive(true);
+ m_xManageDatasources->set_sensitive(true);
+}
+
+#endif
+void ODatasourceSelectDialog::fillListBox(const std::set<OUString>& _rDatasources)
+{
+ OUString sSelected;
+ if (m_xDatasource->n_children())
+ sSelected = m_xDatasource->get_selected_text();
+ m_xDatasource->clear();
+ // fill the list
+ for (auto const& datasource : _rDatasources)
+ {
+ m_xDatasource->append_text(datasource);
+ }
+
+ if (m_xDatasource->n_children())
+ {
+ if (!sSelected.isEmpty())
+ m_xDatasource->select_text(sSelected);
+ else // select the first entry
+ m_xDatasource->select(0);
+ }
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/dsselect.hxx b/dbaccess/source/ui/dlg/dsselect.hxx
new file mode 100644
index 000000000..87cdef17c
--- /dev/null
+++ b/dbaccess/source/ui/dlg/dsselect.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+#include <set>
+
+class SfxItemSet;
+namespace dbaui
+{
+// ODatasourceSelector
+class ODatasourceSelectDialog final : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::TreeView> m_xDatasource;
+ std::unique_ptr<weld::Button> m_xOk;
+ std::unique_ptr<weld::Button> m_xCancel;
+ std::unique_ptr<weld::Button> m_xManageDatasources;
+#ifdef HAVE_ODBC_ADMINISTRATION
+ std::unique_ptr<OOdbcManagement> m_xODBCManagement;
+#endif
+
+public:
+ ODatasourceSelectDialog(weld::Window* pParent, const std::set<OUString>& rDatasources);
+ virtual ~ODatasourceSelectDialog() override;
+ OUString GetSelected() const { return m_xDatasource->get_selected_text(); }
+ void Select(const OUString& _rEntry) { m_xDatasource->select_text(_rEntry); }
+
+ virtual short run() override;
+
+private:
+ DECL_LINK(ListDblClickHdl, weld::TreeView&, bool);
+#ifdef HAVE_ODBC_ADMINISTRATION
+ DECL_LINK(ManageClickHdl, weld::Button&, void);
+ DECL_LINK(ManageProcessFinished, void*, void);
+#endif
+ void fillListBox(const std::set<OUString>& _rDatasources);
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/finteraction.cxx b/dbaccess/source/ui/dlg/finteraction.cxx
new file mode 100644
index 000000000..611119a0c
--- /dev/null
+++ b/dbaccess/source/ui/dlg/finteraction.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "finteraction.hxx"
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::ucb;
+
+ // OFilePickerInteractionHandler
+ OFilePickerInteractionHandler::OFilePickerInteractionHandler( const Reference< XInteractionHandler >& _rxMaster )
+ :m_xMaster( _rxMaster )
+ ,m_bDoesNotExist(false)
+ {
+ assert(m_xMaster.is());
+ }
+
+ OFilePickerInteractionHandler::~OFilePickerInteractionHandler( )
+ {
+ }
+
+ void SAL_CALL OFilePickerInteractionHandler::handle( const Reference< XInteractionRequest >& _rxRequest )
+ {
+ InteractiveIOException aIoException;
+ if ( _rxRequest->getRequest() >>= aIoException )
+ {
+ if ( IOErrorCode_NOT_EXISTING == aIoException.Code )
+ {
+ m_bDoesNotExist = true;
+ return;
+ }
+ }
+
+ if ( m_xMaster.is() )
+ m_xMaster->handle( _rxRequest );
+ }
+
+} // namespace svt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/finteraction.hxx b/dbaccess/source/ui/dlg/finteraction.hxx
new file mode 100644
index 000000000..a487392a5
--- /dev/null
+++ b/dbaccess/source/ui/dlg/finteraction.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+namespace dbaui
+{
+
+ // OFilePickerInteractionHandler
+ typedef ::cppu::WeakImplHelper< css::task::XInteractionHandler
+ > OFilePickerInteractionHandler_Base;
+
+ /** an InteractionHandler implementation which extends another handler with some customizability
+ */
+ class OFilePickerInteractionHandler final : public OFilePickerInteractionHandler_Base
+ {
+ css::uno::Reference< css::task::XInteractionHandler >
+ m_xMaster; // our master handler
+ bool m_bDoesNotExist;
+
+ public:
+ explicit OFilePickerInteractionHandler( const css::uno::Reference< css::task::XInteractionHandler >& _rxMaster );
+
+ bool isDoesNotExist() const { return m_bDoesNotExist; }
+
+ private:
+ // XInteractionHandler
+ virtual void SAL_CALL handle( const css::uno::Reference< css::task::XInteractionRequest >& _rxRequest ) override;
+
+ virtual ~OFilePickerInteractionHandler() override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/generalpage.cxx b/dbaccess/source/ui/dlg/generalpage.cxx
new file mode 100644
index 000000000..f7017187b
--- /dev/null
+++ b/dbaccess/source/ui/dlg/generalpage.cxx
@@ -0,0 +1,700 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+#include <core_resource.hxx>
+#include "dsnItem.hxx"
+#include "generalpage.hxx"
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <dsitems.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/docfilt.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svl/stritem.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <UITools.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/confignode.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <dbwizsetup.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+
+ // OGeneralPage
+ OGeneralPage::OGeneralPage(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const SfxItemSet& _rItems)
+ : OGenericAdministrationPage(pPage, pController, _rUIXMLDescription, "PageGeneral", _rItems)
+ , m_xSpecialMessage(m_xBuilder->weld_label("specialMessage"))
+ , m_eLastMessage(smNone)
+ , m_bInitTypeList(true)
+ , m_xDatasourceType(m_xBuilder->weld_combo_box("datasourceType"))
+ , m_pCollection(nullptr)
+ {
+ // extract the datasource type collection from the item set
+ const DbuTypeCollectionItem* pCollectionItem = dynamic_cast<const DbuTypeCollectionItem*>( _rItems.GetItem(DSID_TYPECOLLECTION) );
+ if (pCollectionItem)
+ m_pCollection = pCollectionItem->getCollection();
+ SAL_WARN_IF(!m_pCollection, "dbaccess.ui.generalpage", "OGeneralPage::OGeneralPage : really need a DSN type collection !");
+
+ // do some knittings
+ m_xDatasourceType->connect_changed(LINK(this, OGeneralPage, OnDatasourceTypeSelected));
+ }
+
+ OGeneralPage::~OGeneralPage()
+ {
+ }
+
+ namespace
+ {
+ struct DisplayedType
+ {
+ OUString eType;
+ OUString sDisplayName;
+
+ DisplayedType( const OUString& _eType, const OUString& _rDisplayName ) : eType( _eType ), sDisplayName( _rDisplayName ) { }
+ };
+ typedef std::vector< DisplayedType > DisplayedTypes;
+
+ struct DisplayedTypeLess
+ {
+ bool operator() ( const DisplayedType& _rLHS, const DisplayedType& _rRHS )
+ {
+ return _rLHS.eType < _rRHS.eType;
+ }
+ };
+ }
+
+ void OGeneralPage::initializeTypeList()
+ {
+ if ( !m_bInitTypeList )
+ return;
+
+ m_bInitTypeList = false;
+ m_xDatasourceType->clear();
+
+ if ( !m_pCollection )
+ return;
+
+ DisplayedTypes aDisplayedTypes;
+
+ ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end();
+ for ( ::dbaccess::ODsnTypeCollection::TypeIterator aTypeLoop = m_pCollection->begin();
+ aTypeLoop != aEnd;
+ ++aTypeLoop
+ )
+ {
+ const OUString& sURLPrefix = aTypeLoop.getURLPrefix();
+ if ( !sURLPrefix.isEmpty() )
+ {
+ // skip mysql connection variations. It is handled in another window.
+ if(sURLPrefix.startsWith("sdbc:mysql:") && !sURLPrefix.startsWith("sdbc:mysql:jdbc:"))
+ continue;
+
+ OUString sDisplayName = aTypeLoop.getDisplayName();
+ if (m_xDatasourceType->find_text(sDisplayName) == -1 &&
+ approveDatasourceType(sURLPrefix, sDisplayName))
+ {
+ aDisplayedTypes.emplace_back( sURLPrefix, sDisplayName );
+ }
+ }
+ }
+ std::sort( aDisplayedTypes.begin(), aDisplayedTypes.end(), DisplayedTypeLess() );
+ for ( const auto& rDisplayedType : aDisplayedTypes )
+ insertDatasourceTypeEntryData( rDisplayedType.eType, rDisplayedType.sDisplayName );
+ }
+
+ void OGeneralPageWizard::initializeEmbeddedDBList()
+ {
+ if ( !m_bInitEmbeddedDBList )
+ return;
+
+ m_bInitEmbeddedDBList = false;
+ m_xEmbeddedDBType->clear();
+
+ if ( !m_pCollection )
+ return;
+
+ DisplayedTypes aDisplayedTypes;
+
+ ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end();
+ for ( ::dbaccess::ODsnTypeCollection::TypeIterator aTypeLoop = m_pCollection->begin();
+ aTypeLoop != aEnd;
+ ++aTypeLoop
+ )
+ {
+ const OUString& sURLPrefix = aTypeLoop.getURLPrefix();
+ if ( !sURLPrefix.isEmpty() )
+ {
+ OUString sDisplayName = aTypeLoop.getDisplayName();
+ if (m_xEmbeddedDBType->find_text(sDisplayName) == -1 &&
+ dbaccess::ODsnTypeCollection::isEmbeddedDatabase(sURLPrefix))
+ {
+#if !HAVE_FEATURE_MACOSX_SANDBOX
+ if( !officecfg::Office::Common::Misc::ExperimentalMode::get()
+ && sURLPrefix.startsWith("sdbc:embedded:firebird") )
+ continue;
+#endif
+ aDisplayedTypes.emplace_back( sURLPrefix, sDisplayName );
+ m_bIsDisplayedTypesEmpty = false;
+ }
+ }
+ }
+ std::sort( aDisplayedTypes.begin(), aDisplayedTypes.end(), DisplayedTypeLess() );
+ for (auto const& displayedType : aDisplayedTypes)
+ insertEmbeddedDBTypeEntryData( displayedType.eType, displayedType.sDisplayName );
+ }
+
+ void OGeneralPage::setParentTitle(const OUString&)
+ {
+ }
+
+ void OGeneralPage::switchMessage(std::u16string_view _sURLPrefix)
+ {
+ SPECIAL_MESSAGE eMessage = smNone;
+ if ( _sURLPrefix.empty()/*_eType == m_eNotSupportedKnownType*/ )
+ {
+ eMessage = smUnsupportedType;
+ }
+
+ if ( eMessage != m_eLastMessage )
+ {
+ TranslateId pResId;
+ if ( smUnsupportedType == eMessage )
+ pResId = STR_UNSUPPORTED_DATASOURCE_TYPE;
+ OUString sMessage;
+ if ( pResId )
+ sMessage = DBA_RES(pResId);
+
+ m_xSpecialMessage->set_label( sMessage );
+ m_eLastMessage = eMessage;
+ }
+ }
+
+ void OGeneralPage::onTypeSelected(const OUString& _sURLPrefix)
+ {
+ // the new URL text as indicated by the selection history
+ implSetCurrentType( _sURLPrefix );
+
+ switchMessage(_sURLPrefix);
+
+ m_aTypeSelectHandler.Call(*this);
+ }
+
+ void OGeneralPage::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue )
+ {
+ initializeTypeList();
+
+ m_xDatasourceType->set_active_text(getDatasourceName(_rSet));
+
+ // notify our listener that our type selection has changed (if so)
+ // FIXME: how to detect that it did not changed? (fdo#62937)
+ setParentTitle( m_eCurrentSelection );
+ onTypeSelected( m_eCurrentSelection );
+
+ // a special message for the current page state
+ switchMessage( m_eCurrentSelection );
+
+ OGenericAdministrationPage::implInitControls( _rSet, _bSaveValue );
+ }
+
+ OUString OGeneralPageWizard::getEmbeddedDBName( const SfxItemSet& _rSet )
+ {
+ // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags( _rSet, bValid, bReadonly );
+
+ // if the selection is invalid, disable everything
+
+ implSetCurrentType( OUString() );
+
+ // compare the DSN prefix with the registered ones
+ OUString sDisplayName;
+
+ if (m_pCollection && bValid)
+ {
+ implSetCurrentType( dbaccess::ODsnTypeCollection::getEmbeddedDatabase() );
+ sDisplayName = m_pCollection->getTypeDisplayName( m_eCurrentSelection );
+ onTypeSelected(m_eCurrentSelection);
+ }
+
+ // select the correct datasource type
+ if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase( m_eCurrentSelection )
+ && m_xEmbeddedDBType->find_text(sDisplayName) == -1 )
+ { // this indicates it's really a type which is known in general, but not supported on the current platform
+ // show a message saying so
+ // eSpecialMessage = smUnsupportedType;
+ insertEmbeddedDBTypeEntryData( m_eCurrentSelection, sDisplayName );
+ }
+
+ return sDisplayName;
+ }
+
+ OUString OGeneralPage::getDatasourceName( const SfxItemSet& _rSet )
+ {
+ // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags( _rSet, bValid, bReadonly );
+
+ // if the selection is invalid, disable everything
+ OUString sConnectURL;
+ if ( bValid )
+ {
+ // collect some items and some values
+ const SfxStringItem* pUrlItem = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL);
+ assert( pUrlItem );
+ sConnectURL = pUrlItem->GetValue();
+ }
+
+ implSetCurrentType( OUString() );
+
+ // compare the DSN prefix with the registered ones
+ OUString sDisplayName;
+
+ if (m_pCollection && bValid)
+ {
+ implSetCurrentType( m_pCollection->getPrefix( sConnectURL ) );
+ sDisplayName = m_pCollection->getTypeDisplayName( m_eCurrentSelection );
+ }
+
+ // select the correct datasource type
+ if ( approveDatasourceType( m_eCurrentSelection, sDisplayName )
+ && m_xDatasourceType->find_text(sDisplayName) == -1 )
+ { // this indicates it's really a type which is known in general, but not supported on the current platform
+ // show a message saying so
+ // eSpecialMessage = smUnsupportedType;
+ insertDatasourceTypeEntryData( m_eCurrentSelection, sDisplayName );
+ }
+
+ return sDisplayName;
+ }
+
+ // For the databaseWizard we only have one entry for the MySQL Database,
+ // because we have a separate tabpage to retrieve the respective datasource type
+ // ( ::dbaccess::DST_MYSQL_ODBC || ::dbaccess::DST_MYSQL_JDBC). Therefore we use ::dbaccess::DST_MYSQL_JDBC as a temporary
+ // representative for all MySQl databases)
+ // Also, embedded databases (embedded HSQL, at the moment), are not to appear in the list of
+ // databases to connect to.
+ bool OGeneralPage::approveDatasourceType( std::u16string_view _sURLPrefix, OUString& _inout_rDisplayName )
+ {
+ return approveDatasourceType( m_pCollection->determineType(_sURLPrefix), _inout_rDisplayName );
+ }
+
+ bool OGeneralPage::approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName )
+ {
+ if ( eType == ::dbaccess::DST_MYSQL_NATIVE_DIRECT )
+ {
+ // do not display the Connector/OOo driver itself, it is always wrapped via the MySQL-Driver, if
+ // this driver is installed
+ if ( m_pCollection->hasDriver( "sdbc:mysql:mysqlc:" ) )
+ _inout_rDisplayName.clear();
+ }
+
+ if ( eType == ::dbaccess::DST_EMBEDDED_HSQLDB
+ || eType == ::dbaccess::DST_EMBEDDED_FIREBIRD )
+ _inout_rDisplayName.clear();
+
+ return _inout_rDisplayName.getLength() > 0;
+ }
+
+ void OGeneralPage::insertDatasourceTypeEntryData(const OUString& _sType, const OUString& sDisplayName)
+ {
+ // insert a (temporary) entry
+ m_xDatasourceType->append_text(sDisplayName);
+ m_aURLPrefixes.push_back(_sType);
+ }
+
+ void OGeneralPageWizard::insertEmbeddedDBTypeEntryData(const OUString& _sType, const OUString& sDisplayName)
+ {
+ // insert a (temporary) entry
+ m_xEmbeddedDBType->append_text(sDisplayName);
+ m_aEmbeddedURLPrefixes.push_back(_sType);
+ }
+
+ void OGeneralPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xSpecialMessage.get()));
+ }
+
+ void OGeneralPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xDatasourceType.get()));
+ }
+
+ void OGeneralPage::implSetCurrentType( const OUString& _eType )
+ {
+ if ( _eType == m_eCurrentSelection )
+ return;
+
+ m_eCurrentSelection = _eType;
+ }
+
+ void OGeneralPage::Reset(const SfxItemSet* _rCoreAttrs)
+ {
+ // reset all locale data
+ implSetCurrentType( OUString() );
+ // this ensures that our type selection link will be called, even if the new one is the same as the
+ // current one
+ OGenericAdministrationPage::Reset(_rCoreAttrs);
+ }
+
+ IMPL_LINK( OGeneralPageWizard, OnEmbeddedDBTypeSelected, weld::ComboBox&, _rBox, void )
+ {
+ // get the type from the entry data
+ const sal_Int32 nSelected = _rBox.get_active();
+ if (o3tl::make_unsigned(nSelected) >= m_aEmbeddedURLPrefixes.size() )
+ {
+ SAL_WARN("dbaccess.ui.generalpage", "Got out-of-range value '" << nSelected << "' from the DatasourceType selection ListBox's GetSelectedEntryPos(): no corresponding URL prefix");
+ return;
+ }
+ const OUString sURLPrefix = m_aEmbeddedURLPrefixes[ nSelected ];
+
+ setParentTitle( sURLPrefix );
+ // let the impl method do all the stuff
+ onTypeSelected( sURLPrefix );
+ // tell the listener we were modified
+ callModifiedHdl();
+ }
+
+ IMPL_LINK( OGeneralPage, OnDatasourceTypeSelected, weld::ComboBox&, _rBox, void )
+ {
+ // get the type from the entry data
+ const sal_Int32 nSelected = _rBox.get_active();
+ if (nSelected == -1)
+ return;
+ if (o3tl::make_unsigned(nSelected) >= m_aURLPrefixes.size() )
+ {
+ SAL_WARN("dbaccess.ui.generalpage", "Got out-of-range value '" << nSelected << "' from the DatasourceType selection ListBox's GetSelectedEntryPos(): no corresponding URL prefix");
+ return;
+ }
+ const OUString sURLPrefix = m_aURLPrefixes[ nSelected ];
+
+ setParentTitle( sURLPrefix );
+ // let the impl method do all the stuff
+ onTypeSelected( sURLPrefix );
+ // tell the listener we were modified
+ callModifiedHdl();
+ }
+
+ // OGeneralPageDialog
+ OGeneralPageDialog::OGeneralPageDialog(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rItems)
+ : OGeneralPage(pPage, pController, "dbaccess/ui/generalpagedialog.ui", _rItems)
+ {
+ }
+
+ void OGeneralPageDialog::setParentTitle( const OUString& _sURLPrefix )
+ {
+ const OUString sName = m_pCollection->getTypeDisplayName( _sURLPrefix );
+ if ( m_pAdminDialog )
+ {
+ OUString sMessage = DBA_RES(STR_PARENTTITLE_GENERAL);
+ m_pAdminDialog->setTitle( sMessage.replaceAll( "#", sName ) );
+ }
+ }
+
+ void OGeneralPageDialog::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue )
+ {
+ OGeneralPage::implInitControls( _rSet, _bSaveValue );
+
+ // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly );
+
+ m_xDatasourceType->set_sensitive( bValid );
+ }
+
+ bool OGeneralPageDialog::FillItemSet( SfxItemSet* _rCoreAttrs )
+ {
+ bool bChangedSomething = false;
+
+ const sal_Int32 nEntry = m_xDatasourceType->get_active();
+ OUString sURLPrefix = m_aURLPrefixes[ nEntry ];
+
+ if (m_xDatasourceType->get_value_changed_from_saved())
+ {
+ _rCoreAttrs->Put( SfxStringItem( DSID_CONNECTURL, sURLPrefix ) );
+ bChangedSomething = true;
+ }
+
+ return bChangedSomething;
+ }
+
+ // OGeneralPageWizard
+ OGeneralPageWizard::OGeneralPageWizard(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rItems)
+ : OGeneralPage( pPage, pController, "dbaccess/ui/generalpagewizard.ui", _rItems )
+ , m_xRB_CreateDatabase(m_xBuilder->weld_radio_button("createDatabase"))
+ , m_xRB_OpenExistingDatabase(m_xBuilder->weld_radio_button("openExistingDatabase"))
+ , m_xRB_ConnectDatabase(m_xBuilder->weld_radio_button("connectDatabase"))
+ , m_xFT_EmbeddedDBLabel(m_xBuilder->weld_label("embeddeddbLabel"))
+ , m_xEmbeddedDBType(m_xBuilder->weld_combo_box("embeddeddbList"))
+ , m_xFT_DocListLabel(m_xBuilder->weld_label("docListLabel"))
+ , m_xFT_HelpText(m_xBuilder->weld_label("helpText"))
+ , m_xLB_DocumentList(new OpenDocumentListBox(m_xBuilder->weld_combo_box("documentList"), "com.sun.star.sdb.OfficeDatabaseDocument"))
+ , m_xPB_OpenDatabase(new OpenDocumentButton(m_xBuilder->weld_button("openDatabase"), "com.sun.star.sdb.OfficeDatabaseDocument"))
+ , m_xFT_NoEmbeddedDBLabel(m_xBuilder->weld_label("noembeddeddbLabel"))
+ , m_eOriginalCreationMode(eCreateNew)
+ , m_bInitEmbeddedDBList(true)
+ , m_bIsDisplayedTypesEmpty(true)
+ {
+ // If no driver for embedded DBs is installed, and no dBase driver, then hide the "Create new database" option
+ sal_Int32 nCreateNewDBIndex = m_pCollection->getIndexOf( dbaccess::ODsnTypeCollection::getEmbeddedDatabase() );
+ if ( nCreateNewDBIndex == -1 )
+ nCreateNewDBIndex = m_pCollection->getIndexOf( u"sdbc:dbase:" );
+ bool bHideCreateNew = ( nCreateNewDBIndex == -1 );
+
+ // also, if our application policies tell us to hide the option, do it
+ ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ ::comphelper::getProcessComponentContext(),
+ "/org.openoffice.Office.DataAccess/Policies/Features/Base"
+ ) );
+ bool bAllowCreateLocalDatabase( true );
+ OSL_VERIFY( aConfig.getNodeValue( "CreateLocalDatabase" ) >>= bAllowCreateLocalDatabase );
+ if ( !bAllowCreateLocalDatabase )
+ bHideCreateNew = true;
+
+ if ( bHideCreateNew )
+ {
+ m_xRB_CreateDatabase->hide();
+ m_xRB_ConnectDatabase->set_active(true);
+ }
+ else
+ m_xRB_CreateDatabase->set_active(true);
+
+ // do some knittings
+ m_xEmbeddedDBType->connect_changed(LINK(this, OGeneralPageWizard, OnEmbeddedDBTypeSelected));
+ m_xRB_CreateDatabase->connect_toggled( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) );
+ m_xRB_ConnectDatabase->connect_toggled( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) );
+ m_xRB_OpenExistingDatabase->connect_toggled( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) );
+ m_xLB_DocumentList->connect_changed( LINK( this, OGeneralPageWizard, OnDocumentSelected ) );
+ m_xPB_OpenDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnOpenDocument ) );
+ m_xFT_NoEmbeddedDBLabel->hide();
+
+ pController->SetGeneralPage(this);
+ }
+
+ OGeneralPageWizard::~OGeneralPageWizard()
+ {
+ }
+
+ OGeneralPageWizard::CreationMode OGeneralPageWizard::GetDatabaseCreationMode() const
+ {
+ if ( m_xRB_CreateDatabase->get_active() )
+ return eCreateNew;
+ if ( m_xRB_ConnectDatabase->get_active() )
+ return eConnectExternal;
+ return eOpenExisting;
+ }
+
+ void OGeneralPageWizard::implInitControls( const SfxItemSet& _rSet, bool _bSaveValue )
+ {
+ OGeneralPage::implInitControls( _rSet, _bSaveValue );
+
+ initializeEmbeddedDBList();
+ m_xEmbeddedDBType->set_active_text(getEmbeddedDBName(_rSet));
+
+ if(m_bIsDisplayedTypesEmpty)
+ {
+ m_xRB_CreateDatabase->set_sensitive(false);
+ m_xFT_EmbeddedDBLabel->hide();
+ m_xEmbeddedDBType->hide();
+ m_xFT_NoEmbeddedDBLabel->show();
+ m_xRB_OpenExistingDatabase->set_active(true);
+ }
+
+ // first check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags( _rSet, bValid, bReadonly );
+
+ SetPageTitle(OUString());
+
+ if ( !bValid || bReadonly )
+ {
+ m_xFT_EmbeddedDBLabel->set_sensitive( false );
+ m_xDatasourceType->set_sensitive( false );
+ m_xPB_OpenDatabase->set_sensitive( false );
+ m_xFT_DocListLabel->set_sensitive( false );
+ m_xLB_DocumentList->set_sensitive( false );
+ }
+
+ if (m_xLB_DocumentList->get_count())
+ m_xLB_DocumentList->set_active(0);
+
+ m_eOriginalCreationMode = GetDatabaseCreationMode();
+
+ SetupModeSelected();
+ }
+
+ OUString OGeneralPageWizard::getDatasourceName(const SfxItemSet& _rSet)
+ {
+ // Sets the default selected database on startup.
+ if (m_xRB_CreateDatabase->get_active() )
+ {
+ return m_pCollection->getTypeDisplayName( u"sdbc:firebird:" );
+ }
+
+ return OGeneralPage::getDatasourceName( _rSet );
+ }
+
+ bool OGeneralPageWizard::approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName )
+ {
+ switch ( eType )
+ {
+ case ::dbaccess::DST_MYSQL_JDBC:
+ case ::dbaccess::DST_MYSQL_ODBC:
+ case ::dbaccess::DST_MYSQL_NATIVE:
+ _inout_rDisplayName = "MySQL/MariaDB";
+ break;
+ default:
+ break;
+ }
+
+ return OGeneralPage::approveDatasourceType( eType, _inout_rDisplayName );
+ }
+
+ bool OGeneralPageWizard::FillItemSet(SfxItemSet* _rCoreAttrs)
+ {
+ bool bChangedSomething = false;
+
+ bool bCommitTypeSelection = true;
+
+ if ( m_xRB_CreateDatabase->get_active() )
+ {
+ _rCoreAttrs->Put( SfxStringItem( DSID_CONNECTURL, "sdbc:dbase:" ) );
+ bChangedSomething = true;
+ bCommitTypeSelection = false;
+ }
+ else if ( m_xRB_OpenExistingDatabase->get_active() )
+ {
+ if ( m_xRB_OpenExistingDatabase->get_state_changed_from_saved() )
+ bChangedSomething = true;
+
+ // TODO
+ bCommitTypeSelection = false;
+ }
+
+ if ( bCommitTypeSelection )
+ {
+ const sal_Int32 nEntry = m_xDatasourceType->get_active();
+ OUString sURLPrefix = m_aURLPrefixes[nEntry];
+
+ if ( m_xDatasourceType->get_value_changed_from_saved()
+ || ( GetDatabaseCreationMode() != m_eOriginalCreationMode )
+ )
+ {
+ _rCoreAttrs->Put( SfxStringItem( DSID_CONNECTURL,sURLPrefix ) );
+ bChangedSomething = true;
+ }
+ else
+ implSetCurrentType( sURLPrefix );
+ }
+ return bChangedSomething;
+ }
+
+ OUString OGeneralPageWizard::GetSelectedDocumentURL() const
+ {
+ if ( !m_aBrowsedDocumentURL.isEmpty() )
+ return m_aBrowsedDocumentURL;
+ else
+ return m_xLB_DocumentList->GetSelectedDocumentURL();
+ }
+
+ void OGeneralPageWizard::EnableControls()
+ {
+ bool bValid, bReadonly;
+ getFlags( GetItemSet(), bValid, bReadonly );
+ if ( bValid && !bReadonly )
+ {
+ m_xEmbeddedDBType->set_sensitive(m_xRB_CreateDatabase->get_active());
+ m_xFT_EmbeddedDBLabel->set_sensitive(m_xRB_CreateDatabase->get_active());
+ m_xDatasourceType->set_sensitive(m_xRB_ConnectDatabase->get_active());
+ m_xPB_OpenDatabase->set_sensitive(m_xRB_OpenExistingDatabase->get_active());
+ m_xFT_DocListLabel->set_sensitive(m_xRB_OpenExistingDatabase->get_active());
+ m_xLB_DocumentList->set_sensitive(m_xRB_OpenExistingDatabase->get_active());
+ }
+ }
+
+ void OGeneralPageWizard::SetupModeSelected()
+ {
+ m_aCreationModeHandler.Call( *this );
+
+ if (m_xRB_CreateDatabase->get_active())
+ OnEmbeddedDBTypeSelected(*m_xEmbeddedDBType);
+ else
+ OnDatasourceTypeSelected(*m_xDatasourceType);
+
+ EnableControls();
+ }
+
+ IMPL_LINK(OGeneralPageWizard, OnSetupModeSelected, weld::Toggleable&, rButton, void)
+ {
+ if (!rButton.get_active())
+ return;
+ SetupModeSelected();
+ }
+
+ IMPL_LINK_NOARG( OGeneralPageWizard, OnDocumentSelected, weld::ComboBox&, void )
+ {
+ m_aDocumentSelectionHandler.Call( *this );
+ }
+
+ IMPL_LINK_NOARG( OGeneralPageWizard, OnOpenDocument, weld::Button&, void )
+ {
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::NONE, "sdatabase", SfxFilterFlags::NONE, SfxFilterFlags::NONE, GetFrameWeld());
+ aFileDlg.SetContext(sfx2::FileDialogHelper::BaseDataSource);
+ std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter();
+ if ( pFilter )
+ {
+ aFileDlg.SetCurrentFilter(pFilter->GetUIName());
+ }
+ if ( aFileDlg.Execute() != ERRCODE_NONE )
+ return;
+
+ OUString sPath = aFileDlg.GetPath();
+ // check for aFileDlg.GetCurrentFilter used to be here but current fpicker filter
+ // can be set to anything, see tdf#125267 how this breaks if other value
+ // than 'ODF Database' is selected. Let's therefore check only if wildcard matches
+ if ( !pFilter->GetWildcard().Matches(sPath) )
+ {
+ OUString sMessage(DBA_RES(STR_ERR_USE_CONNECT_TO));
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ sMessage));
+ xInfoBox->run();
+ m_xRB_ConnectDatabase->set_active(true);
+ OnSetupModeSelected( *m_xRB_ConnectDatabase );
+ return;
+ }
+ m_aBrowsedDocumentURL = sPath;
+ m_aChooseDocumentHandler.Call( *this );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/generalpage.hxx b/dbaccess/source/ui/dlg/generalpage.hxx
new file mode 100644
index 000000000..1abda980e
--- /dev/null
+++ b/dbaccess/source/ui/dlg/generalpage.hxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "adminpages.hxx"
+#include <opendoccontrols.hxx>
+
+namespace dbaui
+{
+ class ODbTypeWizDialogSetup;
+
+ // OGeneralPage
+ class OGeneralPage : public OGenericAdministrationPage
+ {
+ protected:
+ OGeneralPage(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const SfxItemSet& _rItems);
+
+ OUString m_eCurrentSelection; /// currently selected type
+
+ private:
+ std::unique_ptr<weld::Label> m_xSpecialMessage;
+
+ enum SPECIAL_MESSAGE
+ {
+ smNone,
+ smUnsupportedType
+ };
+ SPECIAL_MESSAGE m_eLastMessage;
+
+ Link<OGeneralPage&,void> m_aTypeSelectHandler; /// to be called if a new type is selected
+ bool m_bInitTypeList : 1;
+ bool approveDatasourceType( std::u16string_view _sURLPrefix, OUString& _inout_rDisplayName );
+ void insertDatasourceTypeEntryData( const OUString& _sType, const OUString& sDisplayName );
+
+ protected:
+ std::unique_ptr<weld::ComboBox> m_xDatasourceType;
+
+ ::dbaccess::ODsnTypeCollection*
+ m_pCollection; /// the DSN type collection instance
+
+ std::vector< OUString>
+ m_aURLPrefixes;
+
+ public:
+ virtual ~OGeneralPage() override;
+
+ /// set a handler which gets called every time the user selects a new type
+ void SetTypeSelectHandler( const Link<OGeneralPage&,void>& _rHandler ) { m_aTypeSelectHandler = _rHandler; }
+
+ /// get the currently selected datasource type
+ const OUString& GetSelectedType() const { return m_eCurrentSelection; }
+
+ protected:
+ // SfxTabPage overridables
+ virtual void Reset( const SfxItemSet* _rCoreAttrs ) override;
+
+ virtual void implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) override;
+ virtual OUString getDatasourceName( const SfxItemSet& _rSet );
+ virtual bool approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName );
+
+ // <method>OGenericAdministrationPage::fillControls</method>
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ // <method>OGenericAdministrationPage::fillWindows</method>
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ void onTypeSelected(const OUString& _sURLPrefix);
+
+ /**
+ * Initializes the listbox, which contains entries each representing a
+ * connection to an existing database.
+ */
+ void initializeTypeList();
+
+ void implSetCurrentType( const OUString& _eType );
+
+ void switchMessage(std::u16string_view _sURLPrefix);
+
+ /// sets the title of the parent dialog
+ virtual void setParentTitle( const OUString& _sURLPrefix );
+
+ DECL_LINK(OnDatasourceTypeSelected, weld::ComboBox&, void);
+ };
+
+ // OGeneralPageDialog
+ class OGeneralPageDialog : public OGeneralPage
+ {
+ public:
+ OGeneralPageDialog(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rItems);
+
+ protected:
+ virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override;
+
+ virtual void implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) override;
+ virtual void setParentTitle( const OUString& _sURLPrefix ) override;
+ };
+
+ // OGeneralPageWizard
+ class OGeneralPageWizard final : public OGeneralPage
+ {
+ public:
+ OGeneralPageWizard( weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rItems );
+ virtual ~OGeneralPageWizard() override;
+
+ enum CreationMode
+ {
+ eCreateNew,
+ eConnectExternal,
+ eOpenExisting
+ };
+
+ private:
+ // dialog controls
+ std::unique_ptr<weld::RadioButton> m_xRB_CreateDatabase;
+ std::unique_ptr<weld::RadioButton> m_xRB_OpenExistingDatabase;
+ std::unique_ptr<weld::RadioButton> m_xRB_ConnectDatabase;
+
+ std::unique_ptr<weld::Label> m_xFT_EmbeddedDBLabel;
+ std::unique_ptr<weld::ComboBox> m_xEmbeddedDBType;
+
+ std::unique_ptr<weld::Label> m_xFT_DocListLabel;
+ std::unique_ptr<weld::Label> m_xFT_HelpText;
+ std::unique_ptr<OpenDocumentListBox> m_xLB_DocumentList;
+ std::unique_ptr<OpenDocumentButton> m_xPB_OpenDatabase;
+
+ std::unique_ptr<weld::Label> m_xFT_NoEmbeddedDBLabel;
+
+ // state
+ OUString m_aBrowsedDocumentURL;
+ CreationMode m_eOriginalCreationMode;
+
+ Link<OGeneralPageWizard&,void> m_aCreationModeHandler; /// to be called if a new type is selected
+ Link<OGeneralPageWizard&,void> m_aDocumentSelectionHandler; /// to be called when a document in the RecentDoc list is selected
+ Link<OGeneralPageWizard&,void> m_aChooseDocumentHandler; /// to be called when a recent document has been definitely chosen
+
+ bool m_bInitEmbeddedDBList : 1;
+ bool m_bIsDisplayedTypesEmpty : 1;
+ void insertEmbeddedDBTypeEntryData( const OUString& _sType, const OUString& sDisplayName );
+
+ void EnableControls();
+
+ public:
+ void SetCreationModeHandler( const Link<OGeneralPageWizard&,void>& _rHandler ) { m_aCreationModeHandler = _rHandler; }
+ CreationMode GetDatabaseCreationMode() const;
+
+ void SetDocumentSelectionHandler( const Link<OGeneralPageWizard&,void>& _rHandler) { m_aDocumentSelectionHandler = _rHandler; }
+ void SetChooseDocumentHandler( const Link<OGeneralPageWizard&,void>& _rHandler) { m_aChooseDocumentHandler = _rHandler; }
+ OUString GetSelectedDocumentURL() const;
+
+ private:
+ virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override;
+
+ virtual void implInitControls( const SfxItemSet& _rSet, bool _bSaveValue ) override;
+ virtual OUString getDatasourceName( const SfxItemSet& _rSet ) override;
+ virtual bool approveDatasourceType( ::dbaccess::DATASOURCE_TYPE eType, OUString& _inout_rDisplayName ) override;
+
+ std::vector< OUString>
+ m_aEmbeddedURLPrefixes;
+
+ OUString getEmbeddedDBName( const SfxItemSet& _rSet );
+ void initializeEmbeddedDBList();
+
+ void SetupModeSelected();
+
+ DECL_LINK( OnEmbeddedDBTypeSelected, weld::ComboBox&, void );
+ DECL_LINK( OnSetupModeSelected, weld::Toggleable&, void );
+ DECL_LINK( OnDocumentSelected, weld::ComboBox&, void );
+ DECL_LINK( OnOpenDocument, weld::Button&, void );
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/indexdialog.cxx b/dbaccess/source/ui/dlg/indexdialog.cxx
new file mode 100644
index 000000000..4c9312848
--- /dev/null
+++ b/dbaccess/source/ui/dlg/indexdialog.cxx
@@ -0,0 +1,707 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <set>
+
+#include <core_resource.hxx>
+#include <indexdialog.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <indexfieldscontrol.hxx>
+#include <indexcollection.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <connectivity/dbtools.hxx>
+#include <osl/diagnose.h>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::lang;
+ using namespace ::dbtools;
+
+ // helper
+ static bool operator ==(const OIndexField& _rLHS, const OIndexField& _rRHS)
+ {
+ return (_rLHS.sFieldName == _rRHS.sFieldName)
+ && (_rLHS.bSortAscending == _rRHS.bSortAscending);
+ }
+
+ static bool operator ==(const IndexFields& _rLHS, const IndexFields& _rRHS)
+ {
+ return std::equal(_rLHS.begin(), _rLHS.end(), _rRHS.begin(), _rRHS.end());
+ }
+
+ static bool operator !=(const IndexFields& _rLHS, const IndexFields& _rRHS)
+ {
+ return !(_rLHS == _rRHS);
+ }
+
+ // DbaIndexDialog
+ DbaIndexDialog::DbaIndexDialog(weld::Window* pParent, const Sequence< OUString >& _rFieldNames,
+ const Reference< XNameAccess >& _rxIndexes,
+ const Reference< XConnection >& _rxConnection,
+ const Reference< XComponentContext >& _rxContext)
+ : GenericDialogController(pParent, "dbaccess/ui/indexdesigndialog.ui", "IndexDesignDialog")
+ , m_xConnection(_rxConnection)
+ , m_bEditingActive(false)
+ , m_bEditAgain(false)
+ , m_bNoHandlerCall(false)
+ , m_xContext(_rxContext)
+ , m_xActions(m_xBuilder->weld_toolbar("ACTIONS"))
+ , m_xIndexList(m_xBuilder->weld_tree_view("INDEX_LIST"))
+ , m_xIndexDetails(m_xBuilder->weld_label("INDEX_DETAILS"))
+ , m_xDescriptionLabel(m_xBuilder->weld_label("DESC_LABEL"))
+ , m_xDescription(m_xBuilder->weld_label("DESCRIPTION"))
+ , m_xUnique(m_xBuilder->weld_check_button("UNIQUE"))
+ , m_xFieldsLabel(m_xBuilder->weld_label("FIELDS_LABEL"))
+ , m_xClose(m_xBuilder->weld_button("close"))
+ , m_xTable(m_xBuilder->weld_container("FIELDS"))
+ , m_xTableCtrlParent(m_xTable->CreateChildFrame())
+ , m_xFields(VclPtr<IndexFieldsControl>::Create(m_xTableCtrlParent))
+ {
+ m_xIndexList->set_size_request(m_xIndexList->get_approximate_digit_width() * 17,
+ m_xIndexList->get_height_rows(12));
+
+ int nWidth = m_xIndexList->get_approximate_digit_width() * 60;
+ int nHeight = m_xIndexList->get_height_rows(8);
+ m_xTable->set_size_request(nWidth, nHeight);
+
+ m_xActions->connect_clicked(LINK(this, DbaIndexDialog, OnIndexAction));
+
+ m_xIndexList->connect_changed(LINK(this, DbaIndexDialog, OnIndexSelected));
+ m_xIndexList->connect_editing(LINK(this, DbaIndexDialog, OnEntryEditing),
+ LINK(this, DbaIndexDialog, OnEntryEdited));
+
+ m_xFields->SetSizePixel(Size(nWidth, 100));
+ m_xFields->Init(_rFieldNames, ::dbtools::getBooleanDataSourceSetting( m_xConnection, "AddIndexAppendix" ));
+ m_xFields->Show();
+
+ m_xIndexes.reset(new OIndexCollection());
+ try
+ {
+ m_xIndexes->attach(_rxIndexes);
+ }
+ catch(SQLException& e)
+ {
+ ::dbtools::showError(SQLExceptionInfo(e), pParent->GetXWindow(), _rxContext);
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("DbaIndexDialog::DbaIndexDialog: could not retrieve basic information from the UNO collection!");
+ }
+
+ fillIndexList();
+
+ m_xUnique->connect_toggled(LINK(this, DbaIndexDialog, OnModifiedClick));
+ m_xFields->SetModifyHdl(LINK(this, DbaIndexDialog, OnModified));
+
+ m_xClose->connect_clicked(LINK(this, DbaIndexDialog, OnCloseDialog));
+
+ // if all of the indexes have an empty description, we're not interested in displaying it
+ bool bFound = false;
+ for (auto const& check : *m_xIndexes)
+ {
+ if (!check.sDescription.isEmpty())
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if (!bFound)
+ {
+ // hide the controls which are necessary for the description
+ m_xDescription->hide();
+ m_xDescriptionLabel->hide();
+ }
+ }
+
+ void DbaIndexDialog::updateToolbox()
+ {
+ m_xActions->set_item_sensitive("ID_INDEX_NEW", !m_bEditingActive);
+
+ int nSelected = m_xIndexList->get_selected_index();
+ bool bSelectedAnything = nSelected != -1;
+ if (bSelectedAnything)
+ {
+ // is the current entry modified?
+ Indexes::const_iterator aSelectedPos = m_xIndexes->begin() + m_xIndexList->get_id(nSelected).toUInt32();
+ m_xActions->set_item_sensitive("ID_INDEX_SAVE", aSelectedPos->isModified() || aSelectedPos->isNew());
+ m_xActions->set_item_sensitive("ID_INDEX_RESET", aSelectedPos->isModified() || aSelectedPos->isNew());
+ bSelectedAnything = !aSelectedPos->bPrimaryKey;
+ }
+ else
+ {
+ m_xActions->set_item_sensitive("ID_INDEX_SAVE", false);
+ m_xActions->set_item_sensitive("ID_INDEX_RESET", false);
+ }
+ m_xActions->set_item_sensitive("ID_INDEX_DROP", bSelectedAnything);
+ m_xActions->set_item_sensitive("ID_INDEX_RENAME", bSelectedAnything);
+ }
+
+ void DbaIndexDialog::fillIndexList()
+ {
+ OUString aPKeyIcon(BMP_PKEYICON);
+ // fill the list with the index names
+ m_xIndexList->clear();
+ sal_uInt32 nPos = 0;
+ for (auto const& indexLoop : *m_xIndexes)
+ {
+ m_xIndexList->append(OUString::number(nPos), indexLoop.sName);
+ if (indexLoop.bPrimaryKey)
+ m_xIndexList->set_image(nPos, aPKeyIcon);
+ ++nPos;
+ }
+
+ if (nPos)
+ m_xIndexList->select(0);
+
+ IndexSelected();
+ }
+
+ DbaIndexDialog::~DbaIndexDialog( )
+ {
+ m_xIndexes.reset();
+ m_xFields.disposeAndClear();
+ m_xTableCtrlParent->dispose();
+ m_xTableCtrlParent.clear();
+ }
+
+ bool DbaIndexDialog::implCommit(const weld::TreeIter* pEntry)
+ {
+ assert(pEntry && "DbaIndexDialog::implCommit: invalid entry!");
+
+ Indexes::iterator aCommitPos = m_xIndexes->begin() + m_xIndexList->get_id(*pEntry).toUInt32();
+
+ // if it's not a new index, remove it
+ // (we can't modify indexes, only drop'n'insert)
+ if (!aCommitPos->isNew())
+ if (!implDropIndex(pEntry, false))
+ return false;
+
+ // create the new index
+ SQLExceptionInfo aExceptionInfo;
+ try
+ {
+ m_xIndexes->commitNewIndex(aCommitPos);
+ }
+ catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); }
+ catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); }
+ catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); }
+
+ // reflect the new selection in the toolbox
+ updateToolbox();
+
+ if (aExceptionInfo.isValid())
+ showError(aExceptionInfo, m_xDialog->GetXWindow(), m_xContext);
+ else
+ {
+ m_xUnique->save_state();
+ m_xFields->SaveValue();
+ }
+
+ return !aExceptionInfo.isValid();
+ }
+
+ void DbaIndexDialog::OnNewIndex()
+ {
+ // commit the current entry, if necessary
+ if (!implCommitPreviouslySelected())
+ return;
+
+ // get a new unique name for the new index
+ OUString sNewIndexName;
+ const OUString sNewIndexNameBase(DBA_RES(STR_LOGICAL_INDEX_NAME));
+ sal_Int32 i;
+
+ for ( i = 1; i < 0x7FFFFFFF; ++i )
+ {
+ sNewIndexName = sNewIndexNameBase + OUString::number(i);
+ if (m_xIndexes->end() == m_xIndexes->find(sNewIndexName))
+ break;
+ }
+ if (i == 0x7FFFFFFF)
+ {
+ OSL_FAIL("DbaIndexDialog::OnNewIndex: no free index name found!");
+ // can't do anything ... of course we try another base, but this could end with the same result ...
+ return;
+ }
+
+ std::unique_ptr<weld::TreeIter> xNewEntry(m_xIndexList->make_iterator());
+ m_xIndexList->insert(nullptr, -1, &sNewIndexName, nullptr, nullptr, nullptr, false, xNewEntry.get());
+ m_xIndexes->insert(sNewIndexName);
+
+ // update the user data on the entries in the list box:
+ // they're iterators of the index collection, and thus they have changed when removing the index
+ m_xIndexList->all_foreach([this](weld::TreeIter& rEntry){
+ Indexes::const_iterator aAfterInsertPos = m_xIndexes->find(m_xIndexList->get_text(rEntry));
+ OSL_ENSURE(aAfterInsertPos != m_xIndexes->end(), "DbaIndexDialog::OnNewIndex: problems with one of the entries!");
+ m_xIndexList->set_id(rEntry, OUString::number(aAfterInsertPos - m_xIndexes->begin()));
+ return false;
+ });
+
+ // select the entry and start in-place editing
+ m_bNoHandlerCall = true;
+ m_xIndexList->select(*xNewEntry);
+ m_bNoHandlerCall = false;
+ IndexSelected();
+ m_xIndexList->grab_focus();
+ m_xIndexList->start_editing(*xNewEntry);
+ updateToolbox();
+ }
+
+ void DbaIndexDialog::OnDropIndex(bool _bConfirm)
+ {
+ std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator());
+ // the selected index
+ if (!m_xIndexList->get_selected(xSelected.get()))
+ return;
+
+ // let the user confirm the drop
+ if (_bConfirm)
+ {
+ OUString sConfirm(DBA_RES(STR_CONFIRM_DROP_INDEX));
+ sConfirm = sConfirm.replaceFirst("$name$", m_xIndexList->get_text(*xSelected));
+ std::unique_ptr<weld::MessageDialog> xConfirm(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ sConfirm));
+ if (RET_YES != xConfirm->run())
+ return;
+ }
+
+ // do the drop
+ implDropIndex(xSelected.get(), true);
+
+ // reflect the new selection in the toolbox
+ updateToolbox();
+ }
+
+ bool DbaIndexDialog::implDropIndex(const weld::TreeIter* pEntry, bool _bRemoveFromCollection)
+ {
+ // do the drop
+ Indexes::iterator aDropPos = m_xIndexes->begin() + m_xIndexList->get_id(*pEntry).toUInt32();
+ OSL_ENSURE(aDropPos != m_xIndexes->end(), "DbaIndexDialog::OnDropIndex: did not find the index in my collection!");
+
+ SQLExceptionInfo aExceptionInfo;
+ bool bSuccess = false;
+ try
+ {
+ if (_bRemoveFromCollection)
+ bSuccess = m_xIndexes->drop(aDropPos);
+ else
+ bSuccess = m_xIndexes->dropNoRemove(aDropPos);
+ }
+ catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); }
+ catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); }
+ catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); }
+
+ if (aExceptionInfo.isValid())
+ showError(aExceptionInfo, m_xDialog->GetXWindow(), m_xContext);
+ else if (bSuccess && _bRemoveFromCollection)
+ {
+ m_bNoHandlerCall = true;
+
+ // if the entry to remove is the selected on...
+ if (m_xPreviousSelection && m_xPreviousSelection->equal(*pEntry))
+ m_xPreviousSelection.reset();
+ m_xIndexList->remove(*pEntry);
+
+ m_bNoHandlerCall = false;
+
+ // update the user data on the entries in the list box:
+ // they're iterators of the index collection, and thus they have changed when removing the index
+ m_xIndexList->all_foreach([this](weld::TreeIter& rEntry){
+ Indexes::const_iterator aAfterDropPos = m_xIndexes->find(m_xIndexList->get_text(rEntry));
+ OSL_ENSURE(aAfterDropPos != m_xIndexes->end(), "DbaIndexDialog::OnDropIndex: problems with one of the remaining entries!");
+ m_xIndexList->set_id(rEntry, OUString::number(aAfterDropPos - m_xIndexes->begin()));
+ return false;
+ });
+
+ // the Remove automatically selected another entry (if possible), but we disabled the calling of the handler
+ // to prevent that we missed something... call the handler directly
+ IndexSelected();
+ }
+
+ return !aExceptionInfo.isValid();
+ }
+
+ void DbaIndexDialog::OnRenameIndex()
+ {
+ // the selected iterator
+ std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator());
+ if (!m_xIndexList->get_selected(xSelected.get()))
+ return;
+
+ // save the changes made 'til here
+ // Upon leaving the edit mode, the control will be re-initialized with the
+ // settings from the current entry
+ implSaveModified(false);
+
+ m_xIndexList->grab_focus();
+ m_xIndexList->start_editing(*xSelected);
+ updateToolbox();
+ }
+
+ void DbaIndexDialog::OnSaveIndex()
+ {
+ // the selected index
+ implCommitPreviouslySelected();
+ updateToolbox();
+ }
+
+ void DbaIndexDialog::OnResetIndex()
+ {
+ // the selected index
+ std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator());
+ // the selected index
+ if (!m_xIndexList->get_selected(xSelected.get()))
+ xSelected.reset();
+ OSL_ENSURE(xSelected, "DbaIndexDialog::OnResetIndex: invalid call!");
+ if (!xSelected)
+ return;
+
+ Indexes::iterator aResetPos = m_xIndexes->begin() + m_xIndexList->get_id(*xSelected).toUInt32();
+
+ if (aResetPos->isNew())
+ {
+ OnDropIndex(false);
+ return;
+ }
+
+ SQLExceptionInfo aExceptionInfo;
+ try
+ {
+ m_xIndexes->resetIndex(aResetPos);
+ }
+ catch(SQLContext& e) { aExceptionInfo = SQLExceptionInfo(e); }
+ catch(SQLWarning& e) { aExceptionInfo = SQLExceptionInfo(e); }
+ catch(SQLException& e) { aExceptionInfo = SQLExceptionInfo(e); }
+
+ if (aExceptionInfo.isValid())
+ showError(aExceptionInfo, m_xDialog->GetXWindow(), m_xContext);
+ else
+ m_xIndexList->set_text(*xSelected, aResetPos->sName);
+
+ updateControls(xSelected.get());
+ updateToolbox();
+ }
+
+ IMPL_LINK(DbaIndexDialog, OnIndexAction, const OString&, rClicked, void)
+ {
+ if (rClicked == "ID_INDEX_NEW")
+ OnNewIndex();
+ else if (rClicked == "ID_INDEX_DROP")
+ OnDropIndex();
+ else if (rClicked == "ID_INDEX_RENAME")
+ OnRenameIndex();
+ else if (rClicked == "ID_INDEX_SAVE")
+ OnSaveIndex();
+ else if (rClicked == "ID_INDEX_RESET")
+ OnResetIndex();
+ }
+
+ IMPL_LINK_NOARG(DbaIndexDialog, OnCloseDialog, weld::Button&, void)
+ {
+ if (m_bEditingActive)
+ {
+ OSL_ENSURE(!m_bEditAgain, "DbaIndexDialog::OnCloseDialog: somebody was faster than hell!");
+ // this means somebody entered a new name, which was invalid, which cause us to posted us an event,
+ // and before the event arrived the user clicked onto "close". VERY fast, this user...
+ m_xIndexList->end_editing();
+ if (m_bEditAgain)
+ // could not commit the new name (started a new - asynchronous - edit trial)
+ return;
+ }
+
+ // the currently selected entry
+ std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator());
+ // the selected index
+ if (!m_xIndexList->get_selected(xSelected.get()))
+ xSelected.reset();
+
+ OSL_ENSURE(xSelected && m_xPreviousSelection && xSelected->equal(*m_xPreviousSelection), "DbaIndexDialog::OnCloseDialog: inconsistence!");
+
+ sal_Int32 nResponse = RET_NO;
+ if (xSelected)
+ {
+ // the descriptor
+ Indexes::const_iterator aSelected = m_xIndexes->begin() + m_xIndexList->get_id(*xSelected).toUInt32();
+ if (aSelected->isModified() || aSelected->isNew())
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "dbaccess/ui/saveindexdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("SaveIndexDialog"));
+ nResponse = xQuery->run();
+ }
+ }
+
+ switch (nResponse)
+ {
+ case RET_YES:
+ if (!implCommitPreviouslySelected())
+ return;
+ break;
+ case RET_NO:
+ break;
+ default:
+ return;
+ }
+
+ m_xDialog->response(RET_OK);
+ }
+
+ IMPL_LINK(DbaIndexDialog, OnEditIndexAgain, void*, p, void)
+ {
+ weld::TreeIter* pEntry = static_cast<weld::TreeIter*>(p);
+ m_bEditAgain = false;
+ m_xIndexList->grab_focus();
+ m_xIndexList->start_editing(*pEntry);
+ delete pEntry;
+ }
+
+ IMPL_LINK_NOARG(DbaIndexDialog, OnEntryEditing, const weld::TreeIter&, bool)
+ {
+ m_bEditingActive = true;
+ return true;
+ }
+
+ IMPL_LINK(DbaIndexDialog, OnEntryEdited, const IterString&, rIterString, bool)
+ {
+ m_bEditingActive = false;
+
+ const weld::TreeIter& rEntry = rIterString.first;
+ OUString sNewName = rIterString.second;
+
+ Indexes::iterator aPosition = m_xIndexes->begin() + m_xIndexList->get_id(rEntry).toUInt32();
+
+ OSL_ENSURE(aPosition >= m_xIndexes->begin() && aPosition < m_xIndexes->end(),
+ "DbaIndexDialog::OnEntryEdited: invalid entry!");
+
+ Indexes::const_iterator aSameName = m_xIndexes->find(sNewName);
+ if (aSameName != aPosition && m_xIndexes->end() != aSameName)
+ {
+ OUString sError(DBA_RES(STR_INDEX_NAME_ALREADY_USED));
+ sError = sError.replaceFirst("$name$", sNewName);
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sError));
+ xError->run();
+
+ updateToolbox();
+ m_bEditAgain = true;
+ std::unique_ptr<weld::TreeIter> xEntry(m_xIndexList->make_iterator(&rEntry));
+ Application::PostUserEvent(LINK(this, DbaIndexDialog, OnEditIndexAgain), xEntry.release());
+ return false;
+ }
+
+ aPosition->sName = sNewName;
+
+ // rename can be done by a drop/insert combination only
+ if (aPosition->isNew())
+ {
+ updateToolbox();
+ // no commitment needed here...
+ return true;
+ }
+
+ if (aPosition->sName != aPosition->getOriginalName())
+ {
+ aPosition->setModified(true);
+ updateToolbox();
+ }
+
+ return true;
+ }
+
+ bool DbaIndexDialog::implSaveModified(bool _bPlausibility)
+ {
+ if (!m_xPreviousSelection)
+ return true;
+
+ // try to commit the previously selected index
+ if (m_xFields->IsModified() && !m_xFields->SaveModified())
+ return false;
+
+ Indexes::iterator aPreviouslySelected = m_xIndexes->begin() + m_xIndexList->get_id(*m_xPreviousSelection).toUInt32();
+
+ // the unique flag
+ aPreviouslySelected->bUnique = m_xUnique->get_active();
+ if (m_xUnique->get_state_changed_from_saved())
+ aPreviouslySelected->setModified(true);
+
+ // the fields
+ m_xFields->commitTo(aPreviouslySelected->aFields);
+ if (m_xFields->GetSavedValue() != aPreviouslySelected->aFields)
+ aPreviouslySelected->setModified(true);
+
+ // plausibility checks
+ if (_bPlausibility && !implCheckPlausibility(aPreviouslySelected))
+ return false;
+
+ return true;
+ }
+
+ bool DbaIndexDialog::implCheckPlausibility(const Indexes::const_iterator& _rPos)
+ {
+ // need at least one field
+ if (_rPos->aFields.empty())
+ {
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ DBA_RES(STR_NEED_INDEX_FIELDS)));
+ xError->run();
+ m_xFields->GrabFocus();
+ return false;
+ }
+
+ // no double fields
+ std::set< OUString > aExistentFields;
+ for (auto const& fieldCheck : _rPos->aFields)
+ {
+ if (aExistentFields.end() != aExistentFields.find(fieldCheck.sFieldName))
+ {
+ // a column is specified twice ... won't work anyway, so prevent this here and now
+ OUString sMessage(DBA_RES(STR_INDEXDESIGN_DOUBLE_COLUMN_NAME));
+ sMessage = sMessage.replaceFirst("$name$", fieldCheck.sFieldName);
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sMessage));
+ xError->run();
+ m_xFields->GrabFocus();
+ return false;
+ }
+ aExistentFields.insert(fieldCheck.sFieldName);
+ }
+
+ return true;
+ }
+
+ bool DbaIndexDialog::implCommitPreviouslySelected()
+ {
+ if (m_xPreviousSelection)
+ {
+ Indexes::const_iterator aPreviouslySelected = m_xIndexes->begin() + m_xIndexList->get_id(*m_xPreviousSelection).toUInt32();
+
+ if (!implSaveModified())
+ return false;
+
+ // commit the index (if necessary)
+ if (aPreviouslySelected->isModified() && !implCommit(m_xPreviousSelection.get()))
+ return false;
+ }
+
+ return true;
+ }
+
+ IMPL_LINK_NOARG(DbaIndexDialog, OnModifiedClick, weld::Toggleable&, void)
+ {
+ OnModified(*m_xFields);
+ }
+
+ IMPL_LINK_NOARG( DbaIndexDialog, OnModified, IndexFieldsControl&, void )
+ {
+ assert(m_xPreviousSelection && "DbaIndexDialog, OnModified: invalid call!");
+ Indexes::iterator aPosition = m_xIndexes->begin() + m_xIndexList->get_id(*m_xPreviousSelection).toUInt32();
+
+ aPosition->setModified(true);
+ updateToolbox();
+ }
+
+ void DbaIndexDialog::updateControls(const weld::TreeIter* pEntry)
+ {
+ if (pEntry)
+ {
+ // the descriptor of the selected index
+ Indexes::const_iterator aSelectedIndex = m_xIndexes->begin() + m_xIndexList->get_id(*pEntry).toUInt32();
+
+ // fill the controls
+ m_xUnique->set_active(aSelectedIndex->bUnique);
+ m_xUnique->set_sensitive(!aSelectedIndex->bPrimaryKey);
+ m_xUnique->save_state();
+
+ m_xFields->initializeFrom(std::vector(aSelectedIndex->aFields));
+ m_xFields->Enable(!aSelectedIndex->bPrimaryKey);
+ m_xFields->SaveValue();
+
+ m_xDescription->set_label(aSelectedIndex->sDescription);
+ m_xDescription->set_sensitive(!aSelectedIndex->bPrimaryKey);
+
+ m_xDescriptionLabel->set_sensitive(!aSelectedIndex->bPrimaryKey);
+ }
+ else
+ {
+ m_xUnique->set_active(false);
+ m_xFields->initializeFrom(IndexFields());
+ m_xDescription->set_label(OUString());
+ }
+ }
+
+ void DbaIndexDialog::IndexSelected()
+ {
+ if (m_bEditingActive)
+ m_xIndexList->end_editing();
+
+ std::unique_ptr<weld::TreeIter> xSelected(m_xIndexList->make_iterator());
+ if (!m_xIndexList->get_selected(xSelected.get()))
+ xSelected.reset();
+
+ // commit the old data
+ if (m_xPreviousSelection && (!xSelected || !m_xPreviousSelection->equal(*xSelected)))
+ {
+ // (this call may happen in case somebody ended an in-place edit with 'return', so we need to check this before committing)
+ if (!implCommitPreviouslySelected())
+ {
+ m_bNoHandlerCall = true;
+ m_xIndexList->select(*m_xPreviousSelection);
+ m_bNoHandlerCall = false;
+ return;
+ }
+ }
+
+ // disable/enable the detail controls
+ m_xIndexDetails->set_sensitive(xSelected != nullptr);
+ m_xUnique->set_sensitive(xSelected != nullptr);
+ m_xDescriptionLabel->set_sensitive(xSelected != nullptr);
+ m_xFieldsLabel->set_sensitive(xSelected != nullptr);
+ m_xFields->Enable(xSelected != nullptr);
+
+ updateControls(xSelected.get());
+ if (xSelected)
+ m_xIndexList->grab_focus();
+
+ m_xPreviousSelection = std::move(xSelected);
+
+ updateToolbox();
+ }
+
+ IMPL_LINK_NOARG(DbaIndexDialog, OnIndexSelected, weld::TreeView&, void)
+ {
+ if (m_bNoHandlerCall)
+ return;
+ IndexSelected();
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/indexfieldscontrol.cxx b/dbaccess/source/ui/dlg/indexfieldscontrol.cxx
new file mode 100644
index 000000000..35b0e3f02
--- /dev/null
+++ b/dbaccess/source/ui/dlg/indexfieldscontrol.cxx
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <indexfieldscontrol.hxx>
+#include <strings.hrc>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <helpids.h>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+namespace dbaui
+{
+
+constexpr auto BROWSER_STANDARD_FLAGS = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES |
+ BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT | BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL;
+
+#define COLUMN_ID_FIELDNAME 1
+#define COLUMN_ID_ORDER 2
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::svt;
+
+ // DbaMouseDownListBoxController
+ class DbaMouseDownListBoxController : public ListBoxCellController
+ {
+ protected:
+ Link<DbaMouseDownListBoxController&,void> m_aAdditionalModifyHdl;
+
+ public:
+ explicit DbaMouseDownListBoxController(ListBoxControl* _pParent)
+ :ListBoxCellController(_pParent)
+ {
+ }
+
+ void SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl);
+
+ protected:
+ virtual void callModifyHdl() override;
+ };
+
+ void DbaMouseDownListBoxController::SetAdditionalModifyHdl(const Link<DbaMouseDownListBoxController&,void>& _rHdl)
+ {
+ m_aAdditionalModifyHdl = _rHdl;
+ }
+
+ void DbaMouseDownListBoxController::callModifyHdl()
+ {
+ m_aAdditionalModifyHdl.Call(*this);
+ ListBoxCellController::callModifyHdl();
+ }
+
+ // IndexFieldsControl
+ IndexFieldsControl::IndexFieldsControl(const css::uno::Reference<css::awt::XWindow> &rParent)
+ : EditBrowseBox(VCLUnoHelper::GetWindow(rParent), EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN, WB_TABSTOP | WB_BORDER, BROWSER_STANDARD_FLAGS)
+ , m_aSeekRow(m_aFields.end())
+ , m_pSortingCell(nullptr)
+ , m_pFieldNameCell(nullptr)
+ , m_bAddIndexAppendix(false)
+ {
+ }
+
+ IndexFieldsControl::~IndexFieldsControl()
+ {
+ disposeOnce();
+ }
+
+ void IndexFieldsControl::dispose()
+ {
+ m_pSortingCell.disposeAndClear();
+ m_pFieldNameCell.disposeAndClear();
+ ::svt::EditBrowseBox::dispose();
+ }
+
+ bool IndexFieldsControl::SeekRow(sal_Int32 nRow)
+ {
+ if (!EditBrowseBox::SeekRow(nRow))
+ return false;
+
+ if (nRow < 0)
+ {
+ m_aSeekRow = m_aFields.end();
+ }
+ else
+ {
+ m_aSeekRow = m_aFields.begin() + nRow;
+ OSL_ENSURE(m_aSeekRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
+ }
+
+ return true;
+ }
+
+ void IndexFieldsControl::PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, sal_uInt16 _nColumnId ) const
+ {
+ Point aPos(_rRect.TopLeft());
+ aPos.AdjustX(1 );
+
+ OUString aText = GetRowCellText(m_aSeekRow,_nColumnId);
+ Size TxtSize(GetDataWindow().GetTextWidth(aText), GetDataWindow().GetTextHeight());
+
+ // clipping
+ if (aPos.X() < _rRect.Right() || aPos.X() + TxtSize.Width() > _rRect.Right() ||
+ aPos.Y() < _rRect.Top() || aPos.Y() + TxtSize.Height() > _rRect.Bottom())
+ _rDev.SetClipRegion(vcl::Region(_rRect));
+
+ // allow for a disabled control ...
+ bool bEnabled = IsEnabled();
+ Color aOriginalColor = _rDev.GetTextColor();
+ if (!bEnabled)
+ _rDev.SetTextColor(GetSettings().GetStyleSettings().GetDisableColor());
+
+ // draw the text
+ _rDev.DrawText(aPos, aText);
+
+ // reset the color (if necessary)
+ if (!bEnabled)
+ _rDev.SetTextColor(aOriginalColor);
+
+ if (_rDev.IsClipRegion())
+ _rDev.SetClipRegion();
+ }
+
+ void IndexFieldsControl::initializeFrom(IndexFields&& _rFields)
+ {
+ // copy the field descriptions
+ m_aFields = std::move(_rFields);
+ m_aSeekRow = m_aFields.end();
+
+ SetUpdateMode(false);
+ // remove all rows
+ RowRemoved(1, GetRowCount());
+ // insert rows for the fields
+ RowInserted(GetRowCount(), m_aFields.size(), false);
+ // insert an additional row for a new field for that index
+ RowInserted(GetRowCount(), 1, false);
+ SetUpdateMode(true);
+
+ GoToRowColumnId(0, COLUMN_ID_FIELDNAME);
+ }
+
+ void IndexFieldsControl::commitTo(IndexFields& _rFields)
+ {
+ // do not just copy the array, we may have empty field names (which should not be copied)
+ _rFields.resize(m_aFields.size());
+ IndexFields::iterator aDest = std::copy_if(m_aFields.begin(), m_aFields.end(), _rFields.begin(),
+ [](const OIndexField& source) { return !source.sFieldName.isEmpty(); });
+
+ _rFields.resize(aDest - _rFields.begin());
+ }
+
+ sal_uInt32 IndexFieldsControl::GetTotalCellWidth(sal_Int32 _nRow, sal_uInt16 _nColId)
+ {
+ if (COLUMN_ID_ORDER == _nColId)
+ {
+ sal_Int32 nWidthAsc = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
+ sal_Int32 nWidthDesc = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
+ // maximum plus some additional space
+ return std::max(nWidthAsc, nWidthDesc) + GetTextWidth(OUString('0')) * 2;
+ }
+ return EditBrowseBox::GetTotalCellWidth(_nRow, _nColId);
+ }
+
+ void IndexFieldsControl::Init(const Sequence< OUString >& _rAvailableFields, bool _bAddIndexAppendix)
+ {
+ m_bAddIndexAppendix = _bAddIndexAppendix;
+
+ RemoveColumns();
+
+ // for the width: both columns together should be somewhat smaller than the whole window (without the scrollbar)
+ sal_Int32 nFieldNameWidth = GetSizePixel().Width();
+
+ if ( m_bAddIndexAppendix )
+ {
+ m_sAscendingText = DBA_RES(STR_ORDER_ASCENDING);
+ m_sDescendingText = DBA_RES(STR_ORDER_DESCENDING);
+
+ // the "sort order" column
+ OUString sColumnName = DBA_RES(STR_TAB_INDEX_SORTORDER);
+ // the width of the order column is the maximum widths of the texts used
+ // (the title of the column)
+ sal_Int32 nSortOrderColumnWidth = GetTextWidth(sColumnName);
+ // ("ascending" + scrollbar width)
+ sal_Int32 nOther = GetTextWidth(m_sAscendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
+ nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther);
+ // ("descending" + scrollbar width)
+ nOther = GetTextWidth(m_sDescendingText) + GetSettings().GetStyleSettings().GetScrollBarSize();
+ nSortOrderColumnWidth = std::max(nSortOrderColumnWidth, nOther);
+ // (plus some additional space)
+ nSortOrderColumnWidth += GetTextWidth(OUString('0')) * 2;
+ InsertDataColumn(COLUMN_ID_ORDER, sColumnName, nSortOrderColumnWidth, HeaderBarItemBits::STDSTYLE, 1);
+
+ m_pSortingCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
+ weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
+ rSortingListBox.append_text(m_sAscendingText);
+ rSortingListBox.append_text(m_sDescendingText);
+ rSortingListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_SORTORDER);
+
+ nFieldNameWidth -= nSortOrderColumnWidth;
+ }
+ StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings();
+ nFieldNameWidth -= aSystemStyle.GetScrollBarSize();
+ nFieldNameWidth -= 8;
+ // the "field name" column
+ OUString sColumnName = DBA_RES(STR_TAB_INDEX_FIELD);
+ InsertDataColumn(COLUMN_ID_FIELDNAME, sColumnName, nFieldNameWidth, HeaderBarItemBits::STDSTYLE, 0);
+
+ // create the cell controllers
+ // for the field name cell
+ m_pFieldNameCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
+ weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
+ rNameListBox.append_text(OUString());
+ rNameListBox.set_help_id(HID_DLGINDEX_INDEXDETAILS_FIELD);
+ const OUString* pFields = _rAvailableFields.getConstArray();
+ const OUString* pFieldsEnd = pFields + _rAvailableFields.getLength();
+ for (;pFields < pFieldsEnd; ++pFields)
+ rNameListBox.append_text(*pFields);
+ }
+
+ CellController* IndexFieldsControl::GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId)
+ {
+ if (!IsEnabled())
+ return nullptr;
+
+ IndexFields::const_iterator aRow;
+ bool bNewField = !implGetFieldDesc(_nRow, aRow);
+
+ DbaMouseDownListBoxController* pReturn = nullptr;
+ switch (_nColumnId)
+ {
+ case COLUMN_ID_ORDER:
+ if (!bNewField && m_pSortingCell && !aRow->sFieldName.isEmpty())
+ pReturn = new DbaMouseDownListBoxController(m_pSortingCell);
+ break;
+
+ case COLUMN_ID_FIELDNAME:
+ pReturn = new DbaMouseDownListBoxController(m_pFieldNameCell);
+ break;
+
+ default:
+ OSL_FAIL("IndexFieldsControl::GetController: invalid column id!");
+ }
+
+ if (pReturn)
+ pReturn->SetAdditionalModifyHdl(LINK(this, IndexFieldsControl, OnListEntrySelected));
+
+ return pReturn;
+ }
+
+ bool IndexFieldsControl::implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator& _rPos)
+ {
+ _rPos = m_aFields.end();
+ if ((_nRow < 0) || (o3tl::make_unsigned(_nRow) >= m_aFields.size()))
+ return false;
+ _rPos = m_aFields.begin() + _nRow;
+ return true;
+ }
+
+ bool IndexFieldsControl::SaveModified()
+ {
+ if (!IsModified())
+ return true;
+
+ switch (GetCurColumnId())
+ {
+ case COLUMN_ID_FIELDNAME:
+ {
+ weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
+ OUString sFieldSelected = rNameListBox.get_active_text();
+ bool bEmptySelected = sFieldSelected.isEmpty();
+ if (isNewField())
+ {
+ if (!bEmptySelected)
+ {
+ // add a new field to the collection
+ OIndexField aNewField;
+ aNewField.sFieldName = sFieldSelected;
+ m_aFields.push_back(aNewField);
+ RowInserted(GetRowCount());
+ }
+ }
+ else
+ {
+ sal_Int32 nRow = GetCurRow();
+ OSL_ENSURE(nRow < static_cast<sal_Int32>(m_aFields.size()), "IndexFieldsControl::SaveModified: invalid current row!");
+ if (nRow >= 0) // may be -1 in case the control was empty
+ {
+ // remove the field from the selection
+ IndexFields::iterator aPos = m_aFields.begin() + nRow;
+
+ if (bEmptySelected)
+ {
+ aPos->sFieldName.clear();
+
+ // invalidate the row to force repaint
+ Invalidate(GetRowRectPixel(nRow));
+ return true;
+ }
+
+ if (sFieldSelected == aPos->sFieldName)
+ // nothing changed
+ return true;
+
+ aPos->sFieldName = sFieldSelected;
+ }
+ }
+
+ Invalidate(GetRowRectPixel(GetCurRow()));
+ }
+ break;
+ case COLUMN_ID_ORDER:
+ {
+ OSL_ENSURE(!isNewField(), "IndexFieldsControl::SaveModified: why the hell ...!!!");
+ // selected entry
+ weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
+ sal_Int32 nPos = rSortingListBox.get_active();
+ OSL_ENSURE(nPos != -1, "IndexFieldsControl::SaveModified: how did you get this selection??");
+ // adjust the sort flag in the index field description
+ OIndexField& rCurrentField = m_aFields[GetCurRow()];
+ rCurrentField.bSortAscending = (0 == nPos);
+
+ }
+ break;
+ default:
+ OSL_FAIL("IndexFieldsControl::SaveModified: invalid column id!");
+ }
+ return true;
+ }
+
+ void IndexFieldsControl::InitController(CellControllerRef& /*_rController*/, sal_Int32 _nRow, sal_uInt16 _nColumnId)
+ {
+ IndexFields::const_iterator aFieldDescription;
+ bool bNewField = !implGetFieldDesc(_nRow, aFieldDescription);
+
+ switch (_nColumnId)
+ {
+ case COLUMN_ID_FIELDNAME:
+ {
+ weld::ComboBox& rNameListBox = m_pFieldNameCell->get_widget();
+ rNameListBox.set_active_text(bNewField ? OUString() : aFieldDescription->sFieldName);
+ rNameListBox.save_value();
+ break;
+ }
+
+ case COLUMN_ID_ORDER:
+ {
+ weld::ComboBox& rSortingListBox = m_pSortingCell->get_widget();
+ rSortingListBox.set_active_text(aFieldDescription->bSortAscending ? m_sAscendingText : m_sDescendingText);
+ rSortingListBox.save_value();
+ break;
+ }
+
+ default:
+ OSL_FAIL("IndexFieldsControl::InitController: invalid column id!");
+ }
+ }
+
+ IMPL_LINK( IndexFieldsControl, OnListEntrySelected, DbaMouseDownListBoxController&, rController, void )
+ {
+ weld::ComboBox& rListBox = rController.GetListBox();
+ if (!rListBox.get_popup_shown())
+ m_aModifyHdl.Call(*this);
+
+ if (&rListBox != &m_pFieldNameCell->get_widget())
+ return;
+
+// a field has been selected
+ if (GetCurRow() >= GetRowCount() - 2)
+ { // and we're in one of the last two rows
+ OUString sSelectedEntry = rListBox.get_active_text();
+ sal_Int32 nCurrentRow = GetCurRow();
+ sal_Int32 rowCount = GetRowCount();
+
+ OSL_ENSURE((static_cast<sal_Int32>(m_aFields.size() + 1)) == rowCount, "IndexFieldsControl::OnListEntrySelected: inconsistence!");
+
+ if (!sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 1) /*&& (!m_nMaxColumnsInIndex || rowCount < m_nMaxColumnsInIndex )*/ )
+ { // in the last row, a non-empty string has been selected
+ // -> insert a new row
+ m_aFields.emplace_back();
+ RowInserted(GetRowCount());
+ Invalidate(GetRowRectPixel(nCurrentRow));
+ }
+ else if (sSelectedEntry.isEmpty() && (nCurrentRow == rowCount - 2))
+ { // in the (last-1)th row, an empty entry has been selected
+ // -> remove the last row
+ m_aFields.pop_back();
+ RowRemoved(GetRowCount() - 1);
+ Invalidate(GetRowRectPixel(nCurrentRow));
+ }
+ }
+
+ SaveModified();
+ }
+ OUString IndexFieldsControl::GetCellText(sal_Int32 _nRow,sal_uInt16 nColId) const
+ {
+ IndexFields::const_iterator aRow = m_aFields.end();
+ if ( _nRow >= 0 )
+ {
+ aRow = m_aFields.begin() + _nRow;
+ OSL_ENSURE(aRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!");
+ }
+ return GetRowCellText(aRow,nColId);
+ }
+ OUString IndexFieldsControl::GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const
+ {
+ if (_rRow < m_aFields.end())
+ {
+ switch (nColId)
+ {
+ case COLUMN_ID_FIELDNAME:
+ return _rRow->sFieldName;
+ case COLUMN_ID_ORDER:
+ if (_rRow->sFieldName.isEmpty())
+ return OUString();
+ else
+ return _rRow->bSortAscending ? m_sAscendingText : m_sDescendingText;
+ default:
+ OSL_FAIL("IndexFieldsControl::GetCurrentRowCellText: invalid column id!");
+ }
+ }
+ return OUString();
+ }
+ bool IndexFieldsControl::IsTabAllowed(bool /*bForward*/) const
+ {
+ return false;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/odbcconfig.cxx b/dbaccess/source/ui/dlg/odbcconfig.cxx
new file mode 100644
index 000000000..b2f3a45ff
--- /dev/null
+++ b/dbaccess/source/ui/dlg/odbcconfig.cxx
@@ -0,0 +1,325 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_folders.h>
+#include "odbcconfig.hxx"
+
+#include <rtl/bootstrap.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/diagnose.h>
+#include <osl/process.h>
+#include <osl/thread.hxx>
+#include <vcl/svapp.hxx>
+
+#ifdef HAVE_ODBC_SUPPORT
+
+#if defined(_WIN32)
+#define ODBC_LIBRARY "ODBC32.DLL"
+#endif
+#ifdef UNX
+#ifdef MACOSX
+#define ODBC_LIBRARY "libiodbc.dylib"
+#else
+#define ODBC_LIBRARY_PLAIN "libodbc.so"
+#define ODBC_LIBRARY_1 "libodbc.so.1"
+#define ODBC_LIBRARY "libodbc.so.2"
+#endif
+#endif
+
+#include <connectivity/odbc.hxx>
+
+#else
+
+#define ODBC_LIBRARY ""
+
+#endif // HAVE_ODBC_SUPPORT
+
+namespace dbaui
+{
+
+#ifdef HAVE_ODBC_SUPPORT
+typedef SQLRETURN (SQL_API* TSQLManageDataSource) (SQLHWND hwndParent);
+typedef SQLRETURN (SQL_API* TSQLAllocHandle) (SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE* OutputHandlePtr);
+typedef SQLRETURN (SQL_API* TSQLFreeHandle) (SQLSMALLINT HandleType, SQLHANDLE Handle);
+typedef SQLRETURN (SQL_API* TSQLSetEnvAttr) (SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
+typedef SQLRETURN (SQL_API* TSQLDataSources) (SQLHENV EnvironmentHandle, SQLUSMALLINT Direction, SQLCHAR* ServerName,
+ SQLSMALLINT BufferLength1, SQLSMALLINT* NameLength1Ptr, SQLCHAR* Description, SQLSMALLINT BufferLength2, SQLSMALLINT* NameLength2Ptr);
+
+#endif
+
+// OOdbcLibWrapper
+
+bool OOdbcEnumeration::load(const char* _pLibPath)
+{
+ m_sLibPath = OUString::createFromAscii(_pLibPath);
+#if defined(HAVE_ODBC_SUPPORT) && !defined(DISABLE_DYNLOADING)
+ // load the module
+ m_pOdbcLib = osl_loadModule(m_sLibPath.pData, SAL_LOADMODULE_NOW);
+ return (nullptr != m_pOdbcLib);
+#else
+ return sal_False;
+#endif
+}
+
+void OOdbcEnumeration::unload()
+{
+#if defined(HAVE_ODBC_SUPPORT) && !defined(DISABLE_DYNLOADING)
+ if (isLoaded())
+ {
+ osl_unloadModule(m_pOdbcLib);
+ m_pOdbcLib = nullptr;
+ }
+#endif
+}
+
+oslGenericFunction OOdbcEnumeration::loadSymbol(const char* _pFunctionName)
+{
+ return osl_getFunctionSymbol(m_pOdbcLib, OUString::createFromAscii(_pFunctionName).pData);
+}
+
+
+struct OdbcTypesImpl
+{
+#ifdef HAVE_ODBC_SUPPORT
+ SQLHANDLE hEnvironment;
+ OdbcTypesImpl() : hEnvironment(nullptr) { }
+#else
+ void* pDummy;
+#endif
+};
+
+OOdbcEnumeration::OOdbcEnumeration()
+ :m_pOdbcLib(nullptr)
+#ifdef HAVE_ODBC_SUPPORT
+ ,m_pAllocHandle(nullptr)
+ ,m_pFreeHandle(nullptr)
+ ,m_pSetEnvAttr(nullptr)
+ ,m_pDataSources(nullptr)
+ ,m_pImpl(new OdbcTypesImpl)
+#endif
+{
+ bool bLoaded = load(ODBC_LIBRARY);
+#ifdef ODBC_LIBRARY_1
+ if ( !bLoaded )
+ bLoaded = load(ODBC_LIBRARY_1);
+#endif
+#ifdef ODBC_LIBRARY_PLAIN
+ if ( !bLoaded )
+ bLoaded = load(ODBC_LIBRARY_PLAIN);
+#endif
+
+ if ( !bLoaded )
+ return;
+
+#ifdef HAVE_ODBC_SUPPORT
+ // load the generic functions
+ m_pAllocHandle = loadSymbol("SQLAllocHandle");
+ m_pFreeHandle = loadSymbol("SQLFreeHandle");
+ m_pSetEnvAttr = loadSymbol("SQLSetEnvAttr");
+ m_pDataSources = loadSymbol("SQLDataSources");
+
+ // all or nothing
+ if (!m_pAllocHandle || !m_pSetEnvAttr || !m_pDataSources || !m_pFreeHandle)
+ {
+ unload();
+ m_pAllocHandle = m_pFreeHandle = m_pSetEnvAttr = m_pDataSources = nullptr;
+ }
+#endif
+}
+
+OOdbcEnumeration::~OOdbcEnumeration()
+{
+ freeEnv();
+ unload();
+}
+
+// OOdbcEnumeration
+bool OOdbcEnumeration::allocEnv()
+{
+ OSL_ENSURE(isLoaded(), "OOdbcEnumeration::allocEnv: not loaded!");
+ if (!isLoaded())
+ return false;
+
+#ifdef HAVE_ODBC_SUPPORT
+ if (m_pImpl->hEnvironment)
+ // nothing to do
+ return true;
+ SQLRETURN nResult = (*reinterpret_cast<TSQLAllocHandle>(m_pAllocHandle))(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_pImpl->hEnvironment);
+ if (SQL_SUCCESS != nResult)
+ // can't do anything without environment
+ return false;
+
+ (*reinterpret_cast<TSQLSetEnvAttr>(m_pSetEnvAttr))(m_pImpl->hEnvironment, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3),SQL_IS_INTEGER);
+ return true;
+#else
+ return sal_False;
+#endif
+}
+
+void OOdbcEnumeration::freeEnv()
+{
+#ifdef HAVE_ODBC_SUPPORT
+ if (m_pImpl->hEnvironment)
+ (*reinterpret_cast<TSQLFreeHandle>(m_pFreeHandle))(SQL_HANDLE_ENV, m_pImpl->hEnvironment);
+ m_pImpl->hEnvironment = nullptr;
+#endif
+}
+
+void OOdbcEnumeration::getDatasourceNames(std::set<OUString>& _rNames)
+{
+ OSL_ENSURE(isLoaded(), "OOdbcEnumeration::getDatasourceNames: not loaded!");
+ if (!isLoaded())
+ return;
+
+ if (!allocEnv())
+ {
+ OSL_FAIL("OOdbcEnumeration::getDatasourceNames: could not allocate an ODBC environment!");
+ return;
+ }
+
+#ifdef HAVE_ODBC_SUPPORT
+ // now that we have an environment collect the data source names
+ UCHAR szDSN[SQL_MAX_DSN_LENGTH+1];
+ SWORD pcbDSN;
+ UCHAR szDescription[1024+1];
+ SWORD pcbDescription;
+ SQLRETURN nResult = SQL_SUCCESS;
+ rtl_TextEncoding nTextEncoding = osl_getThreadTextEncoding();
+
+ for ( nResult = (*reinterpret_cast<TSQLDataSources>(m_pDataSources))(m_pImpl->hEnvironment, SQL_FETCH_FIRST, szDSN,
+ sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription);
+ ;
+ nResult = (*reinterpret_cast<TSQLDataSources>(m_pDataSources))(m_pImpl->hEnvironment, SQL_FETCH_NEXT, szDSN,
+ sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription)
+ )
+ {
+ if (nResult != SQL_SUCCESS)
+ // no further error handling
+ break;
+ else
+ {
+ OUString aCurrentDsn(reinterpret_cast<const char*>(szDSN),pcbDSN, nTextEncoding);
+ _rNames.insert(aCurrentDsn);
+ }
+ }
+#else
+ (void) _rNames;
+#endif
+}
+
+#ifdef HAVE_ODBC_ADMINISTRATION
+
+// ProcessTerminationWait
+class ProcessTerminationWait : public ::osl::Thread
+{
+ oslProcess m_hProcessHandle;
+ Link<void*,void> m_aFinishHdl;
+ ImplSVEvent* m_nEventId;
+
+public:
+ ProcessTerminationWait( oslProcess _hProcessHandle, const Link<void*,void>& _rFinishHdl )
+ : m_hProcessHandle( _hProcessHandle )
+ , m_aFinishHdl( _rFinishHdl )
+ , m_nEventId(nullptr)
+ {
+ }
+
+ void disableCallback()
+ {
+ // if finished event not posted yet, disable by turning it to a no-op Link
+ m_aFinishHdl = Link<void*, void>();
+ if (m_nEventId)
+ {
+ // already posted, remove it
+ Application::RemoveUserEvent(m_nEventId);
+ m_nEventId = nullptr;
+ }
+ }
+
+ void receivedCallback()
+ {
+ m_nEventId = nullptr;
+ }
+
+protected:
+ virtual void SAL_CALL run() override
+ {
+ osl_setThreadName("dbaui::ProcessTerminationWait");
+
+ osl_joinProcess( m_hProcessHandle );
+ osl_freeProcessHandle( m_hProcessHandle );
+ m_nEventId = Application::PostUserEvent( m_aFinishHdl );
+ }
+};
+
+// OOdbcManagement
+OOdbcManagement::OOdbcManagement(const Link<void*,void>& rAsyncFinishCallback)
+ : m_aAsyncFinishCallback(rAsyncFinishCallback)
+{
+}
+
+OOdbcManagement::~OOdbcManagement()
+{
+ // wait for our thread to be finished
+ if ( m_pProcessWait )
+ m_pProcessWait->join();
+}
+
+bool OOdbcManagement::manageDataSources_async()
+{
+ OSL_PRECOND( !isRunning(), "OOdbcManagement::manageDataSources_async: still running from the previous call!" );
+ if ( isRunning() )
+ return false;
+
+ // this is done in an external process, due to #i78733#
+ // (and note this whole functionality is supported on Windows only, ATM)
+ OUString sExecutableName( "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/odbcconfig.exe" );
+ ::rtl::Bootstrap::expandMacros( sExecutableName ); //TODO: detect failure
+ oslProcess hProcessHandle(nullptr);
+ oslProcessError eError = osl_executeProcess( sExecutableName.pData, nullptr, 0, 0, nullptr, nullptr, nullptr, 0, &hProcessHandle );
+ if ( eError != osl_Process_E_None )
+ return false;
+
+ m_pProcessWait.reset( new ProcessTerminationWait( hProcessHandle, m_aAsyncFinishCallback ) );
+ m_pProcessWait->create();
+ return true;
+}
+
+void OOdbcManagement::disableCallback()
+{
+ if (m_pProcessWait)
+ m_pProcessWait->disableCallback();
+}
+
+void OOdbcManagement::receivedCallback()
+{
+ if (m_pProcessWait)
+ m_pProcessWait->receivedCallback();
+}
+
+bool OOdbcManagement::isRunning() const
+{
+ return ( m_pProcessWait && m_pProcessWait->isRunning() );
+}
+
+#endif // HAVE_ODBC_ADMINISTRATION
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/odbcconfig.hxx b/dbaccess/source/ui/dlg/odbcconfig.hxx
new file mode 100644
index 000000000..16177ad8a
--- /dev/null
+++ b/dbaccess/source/ui/dlg/odbcconfig.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if defined(_WIN32) || (defined (UNX) && !defined(ANDROID) && !defined(IOS))
+#define HAVE_ODBC_SUPPORT
+#endif
+
+#if defined(_WIN32) && defined(HAVE_ODBC_SUPPORT)
+#define HAVE_ODBC_ADMINISTRATION
+#endif
+
+#include <rtl/ustring.hxx>
+#include <tools/link.hxx>
+#include <osl/module.h>
+
+#include <memory>
+#include <set>
+
+namespace dbaui
+{
+
+// OOdbcEnumeration
+struct OdbcTypesImpl;
+class OOdbcEnumeration final
+{
+ oslModule m_pOdbcLib; // the library handle
+ OUString m_sLibPath; // the path to the library
+
+#ifdef HAVE_ODBC_SUPPORT
+ // entry points for ODBC administration
+ oslGenericFunction m_pAllocHandle;
+ oslGenericFunction m_pFreeHandle;
+ oslGenericFunction m_pSetEnvAttr;
+ oslGenericFunction m_pDataSources;
+
+#endif
+ std::unique_ptr<OdbcTypesImpl> m_pImpl;
+ // needed because we can't have a member of type SQLHANDLE: this would require us to include the respective
+ // ODBC file, which would lead to a lot of conflicts with other includes
+
+public:
+ OOdbcEnumeration();
+ ~OOdbcEnumeration();
+
+#ifdef HAVE_ODBC_SUPPORT
+ bool isLoaded() const { return nullptr != m_pOdbcLib; }
+#else
+ bool isLoaded() const { return false; }
+#endif
+ const OUString& getLibraryName() const { return m_sLibPath; }
+
+ void getDatasourceNames(std::set<OUString>& _rNames);
+
+private:
+ oslGenericFunction loadSymbol(const char* _pFunctionName);
+
+ /// load the lib
+ bool load(const char* _pLibPath);
+ /// unload the lib
+ void unload();
+ /// ensure that an ODBC environment is allocated
+ bool allocEnv();
+ /// free any allocated ODBC environment
+ void freeEnv();
+};
+
+// OOdbcManagement
+#ifdef HAVE_ODBC_ADMINISTRATION
+class ProcessTerminationWait;
+class OOdbcManagement
+{
+ std::unique_ptr< ProcessTerminationWait > m_pProcessWait;
+ Link<void*,void> m_aAsyncFinishCallback;
+
+public:
+ explicit OOdbcManagement( const Link<void*,void>& _rAsyncFinishCallback );
+ ~OOdbcManagement();
+
+ bool manageDataSources_async();
+ bool isRunning() const;
+ void disableCallback();
+ void receivedCallback();
+};
+#endif
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/optionalboolitem.cxx b/dbaccess/source/ui/dlg/optionalboolitem.cxx
new file mode 100644
index 000000000..30d176391
--- /dev/null
+++ b/dbaccess/source/ui/dlg/optionalboolitem.cxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "optionalboolitem.hxx"
+
+namespace dbaui
+{
+
+ // OptionalBoolItem
+ OptionalBoolItem::OptionalBoolItem( sal_uInt16 _nWhich )
+ :SfxPoolItem( _nWhich )
+ {
+ }
+
+ bool OptionalBoolItem::operator==( const SfxPoolItem& _rItem ) const
+ {
+ return SfxPoolItem::operator==(_rItem) &&
+ static_cast<const OptionalBoolItem&>( _rItem ).m_aValue == m_aValue;
+ }
+
+ OptionalBoolItem* OptionalBoolItem::Clone( SfxItemPool* /*_pPool*/ ) const
+ {
+ return new OptionalBoolItem( *this );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/optionalboolitem.hxx b/dbaccess/source/ui/dlg/optionalboolitem.hxx
new file mode 100644
index 000000000..c500dfa2a
--- /dev/null
+++ b/dbaccess/source/ui/dlg/optionalboolitem.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/poolitem.hxx>
+
+#include <optional>
+
+namespace dbaui
+{
+
+ // OptionalBoolItem
+ class OptionalBoolItem : public SfxPoolItem
+ {
+ ::std::optional< bool > m_aValue;
+
+ public:
+ explicit OptionalBoolItem( sal_uInt16 nWhich );
+
+ virtual bool operator==( const SfxPoolItem& _rItem ) const override;
+ virtual OptionalBoolItem* Clone( SfxItemPool* _pPool = nullptr ) const override;
+
+ bool HasValue() const { return !!m_aValue; }
+ void ClearValue() { m_aValue.reset(); }
+ bool GetValue() const { return *m_aValue; }
+ void SetValue(bool _bValue) { m_aValue = _bValue; }
+
+ const ::std::optional< bool >&
+ GetFullValue() const { return m_aValue; }
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/paramdialog.cxx b/dbaccess/source/ui/dlg/paramdialog.cxx
new file mode 100644
index 000000000..de3347682
--- /dev/null
+++ b/dbaccess/source/ui/dlg/paramdialog.cxx
@@ -0,0 +1,334 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <paramdialog.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <vcl/weld.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::util;
+ using namespace ::connectivity;
+
+ // OParameterDialog
+
+
+ OParameterDialog::OParameterDialog(
+ weld::Window* pParent, const Reference< XIndexAccess > & rParamContainer,
+ const Reference< XConnection > & _rxConnection, const Reference< XComponentContext >& rxContext)
+ : GenericDialogController(pParent, "dbaccess/ui/parametersdialog.ui", "Parameters")
+ , m_nCurrentlySelected(-1)
+ , m_xConnection(_rxConnection)
+ , m_aPredicateInput( rxContext, _rxConnection, getParseContext() )
+ , m_aResetVisitFlag("dbaccess OParameterDialog m_aResetVisitFlag")
+ , m_xAllParams(m_xBuilder->weld_tree_view("allParamTreeview"))
+ , m_xParam(m_xBuilder->weld_entry("paramEntry"))
+ , m_xTravelNext(m_xBuilder->weld_button("next"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+ {
+ m_xAllParams->set_size_request(-1, m_xAllParams->get_height_rows(10));
+
+ if (rxContext.is())
+ m_xFormatter.set( NumberFormatter::create( rxContext ), UNO_QUERY_THROW);
+ else {
+ OSL_FAIL("OParameterDialog::OParameterDialog: need a service factory!");
+ }
+
+ Reference< XNumberFormatsSupplier > xNumberFormats = ::dbtools::getNumberFormats(m_xConnection, true);
+ if (!xNumberFormats.is())
+ ::comphelper::disposeComponent(m_xFormatter);
+ else
+ m_xFormatter->attachNumberFormatsSupplier(xNumberFormats);
+ try
+ {
+ OSL_ENSURE(rParamContainer->getCount(), "OParameterDialog::OParameterDialog : can't handle empty containers !");
+
+ m_aFinalValues.realloc(rParamContainer->getCount());
+ PropertyValue* pValues = m_aFinalValues.getArray();
+
+ for (sal_Int32 i = 0, nCount = rParamContainer->getCount(); i<nCount; ++i, ++pValues)
+ {
+ Reference< XPropertySet > xParamAsSet;
+ rParamContainer->getByIndex(i) >>= xParamAsSet;
+ OSL_ENSURE(xParamAsSet.is(),"Parameter is null!");
+ if(!xParamAsSet.is())
+ continue;
+ pValues->Name = ::comphelper::getString(xParamAsSet->getPropertyValue(PROPERTY_NAME));
+ m_xAllParams->append_text(pValues->Name);
+
+ m_aVisitedParams.push_back(VisitFlags::NONE);
+ // not visited, not dirty
+ }
+
+ m_xParams = rParamContainer;
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ Construct();
+
+ m_aResetVisitFlag.SetInvokeHandler(LINK(this, OParameterDialog, OnVisitedTimeout));
+ }
+
+ OParameterDialog::~OParameterDialog()
+ {
+ if (m_aResetVisitFlag.IsActive())
+ m_aResetVisitFlag.Stop();
+ }
+
+ void OParameterDialog::Construct()
+ {
+ m_xAllParams->connect_changed(LINK(this, OParameterDialog, OnEntryListBoxSelected));
+ m_xParam->connect_focus_out(LINK(this, OParameterDialog, OnValueLoseFocusHdl));
+ m_xParam->connect_changed(LINK(this, OParameterDialog, OnValueModified));
+ m_xTravelNext->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked));
+ m_xOKBtn->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked));
+ m_xCancelBtn->connect_clicked(LINK(this, OParameterDialog, OnButtonClicked));
+
+ if (m_xAllParams->n_children())
+ {
+ m_xAllParams->select(0);
+ OnEntrySelected();
+
+ if (m_xAllParams->n_children() == 1)
+ m_xTravelNext->set_sensitive(false);
+
+ if (m_xAllParams->n_children() > 1)
+ m_xDialog->change_default_widget(m_xOKBtn.get(), m_xTravelNext.get());
+ }
+
+ m_xParam->grab_focus();
+ }
+
+ IMPL_LINK_NOARG(OParameterDialog, OnValueLoseFocusHdl, weld::Widget&, void)
+ {
+ CheckValueForError();
+ }
+
+ bool OParameterDialog::CheckValueForError()
+ {
+ if (m_nCurrentlySelected != -1)
+ {
+ if ( !( m_aVisitedParams[ m_nCurrentlySelected ] & VisitFlags::Dirty ) )
+ // nothing to do, the value isn't dirty
+ return false;
+ }
+
+ bool bRet = false;
+
+ Reference< XPropertySet > xParamAsSet;
+ m_xParams->getByIndex(m_nCurrentlySelected) >>= xParamAsSet;
+ if (xParamAsSet.is())
+ {
+ if (m_xConnection.is() && m_xFormatter.is())
+ {
+ OUString sParamValue(m_xParam->get_text());
+ bool bValid = m_aPredicateInput.normalizePredicateString( sParamValue, xParamAsSet );
+ m_xParam->set_text(sParamValue);
+ m_xParam->set_message_type(bValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
+ OUString sToolTip;
+ if ( bValid )
+ {
+ // with this the value isn't dirty anymore
+ if (m_nCurrentlySelected != -1)
+ m_aVisitedParams[m_nCurrentlySelected] &= ~VisitFlags::Dirty;
+ }
+ else
+ {
+ OUString sName;
+ try
+ {
+ sName = ::comphelper::getString(xParamAsSet->getPropertyValue(PROPERTY_NAME));
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ OUString sMessage(DBA_RES(STR_COULD_NOT_CONVERT_PARAM));
+ sToolTip = sMessage.replaceAll( "$name$", sName );
+ m_xParam->grab_focus();
+ bRet = true;
+ }
+ m_xParam->set_tooltip_text(sToolTip);
+ m_xOKBtn->set_sensitive(bValid);
+ }
+ }
+
+ return bRet;
+ }
+
+ IMPL_LINK(OParameterDialog, OnButtonClicked, weld::Button&, rButton, void)
+ {
+ if (m_xCancelBtn.get() == &rButton)
+ {
+ // no interpreting of the given values anymore...
+ m_xParam->connect_focus_out(Link<weld::Widget&, void>()); // no direct call from the control anymore ...
+ m_xDialog->response(RET_CANCEL);
+ }
+ else if (m_xOKBtn.get() == &rButton)
+ {
+ // transfer the current values into the Any
+ if (OnEntrySelected())
+ { // there was an error interpreting the current text
+ return;
+ }
+
+ if (m_xParams.is())
+ {
+ // write the parameters
+ try
+ {
+ PropertyValue* pValues = m_aFinalValues.getArray();
+ for (sal_Int32 i = 0, nCount = m_xParams->getCount(); i<nCount; ++i, ++pValues)
+ {
+ Reference< XPropertySet > xParamAsSet;
+ m_xParams->getByIndex(i) >>= xParamAsSet;
+
+ OUString sValue;
+ pValues->Value >>= sValue;
+ pValues->Value = m_aPredicateInput.getPredicateValue( sValue, xParamAsSet );
+ }
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ }
+ m_xDialog->response(RET_OK);
+ }
+ else if (m_xTravelNext.get() == &rButton)
+ {
+ if (sal_Int32 nCount = m_xAllParams->n_children())
+ {
+ sal_Int32 nCurrent = m_xAllParams->get_selected_index();
+ OSL_ENSURE(static_cast<size_t>(nCount) == m_aVisitedParams.size(), "OParameterDialog::OnButtonClicked : inconsistent lists !");
+
+ // search the next entry in list we haven't visited yet
+ sal_Int32 nNext = (nCurrent + 1) % nCount;
+ while ((nNext != nCurrent) && ( m_aVisitedParams[nNext] & VisitFlags::Visited ))
+ nNext = (nNext + 1) % nCount;
+
+ if ( m_aVisitedParams[nNext] & VisitFlags::Visited )
+ // there is no such "not visited yet" entry -> simply take the next one
+ nNext = (nCurrent + 1) % nCount;
+
+ m_xAllParams->select(nNext);
+ OnEntrySelected();
+ }
+ }
+ }
+
+ IMPL_LINK_NOARG(OParameterDialog, OnEntryListBoxSelected, weld::TreeView&, void)
+ {
+ OnEntrySelected();
+ }
+
+ bool OParameterDialog::OnEntrySelected()
+ {
+ if (m_aResetVisitFlag.IsActive())
+ {
+ LINK(this, OParameterDialog, OnVisitedTimeout).Call(&m_aResetVisitFlag);
+ m_aResetVisitFlag.Stop();
+ }
+ // save the old values
+ if (m_nCurrentlySelected != -1)
+ {
+ // do the transformation of the current text
+ if (CheckValueForError())
+ { // there was an error interpreting the text
+ m_xAllParams->select(m_nCurrentlySelected);
+ return true;
+ }
+
+ m_aFinalValues.getArray()[m_nCurrentlySelected].Value <<= m_xParam->get_text();
+ }
+
+ // initialize the controls with the new values
+ sal_Int32 nSelected = m_xAllParams->get_selected_index();
+ OSL_ENSURE(nSelected != -1, "OParameterDialog::OnEntrySelected : no current entry !");
+
+ m_xParam->set_text(::comphelper::getString(m_aFinalValues[nSelected].Value));
+ m_nCurrentlySelected = nSelected;
+
+ // with this the value isn't dirty
+ OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnEntrySelected : invalid current entry !");
+ m_aVisitedParams[m_nCurrentlySelected] &= ~VisitFlags::Dirty;
+
+ m_aResetVisitFlag.SetTimeout(1000);
+ m_aResetVisitFlag.Start();
+
+ return false;
+ }
+
+ IMPL_LINK_NOARG(OParameterDialog, OnVisitedTimeout, Timer*, void)
+ {
+ OSL_ENSURE(m_nCurrentlySelected != -1, "OParameterDialog::OnVisitedTimeout : invalid call !");
+
+ // mark the currently selected entry as visited
+ OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnVisitedTimeout : invalid entry !");
+ m_aVisitedParams[m_nCurrentlySelected] |= VisitFlags::Visited;
+
+ // was it the last "not visited yet" entry ?
+ bool bVisited = false;
+ for (auto const& visitedParam : m_aVisitedParams)
+ {
+ if (!(visitedParam & VisitFlags::Visited))
+ {
+ bVisited = true;
+ break;
+ }
+ }
+
+ if (!bVisited)
+ {
+ // yes, there isn't another one -> change the "default button"
+ m_xDialog->change_default_widget(m_xTravelNext.get(), m_xOKBtn.get());
+ }
+ }
+
+ IMPL_LINK(OParameterDialog, OnValueModified, weld::Entry&, rEdit, void)
+ {
+ // mark the currently selected entry as dirty
+ OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnValueModified : invalid entry !");
+ m_aVisitedParams[m_nCurrentlySelected] |= VisitFlags::Dirty;
+ rEdit.set_message_type(weld::EntryMessageType::Normal);
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/queryfilter.cxx b/dbaccess/source/ui/dlg/queryfilter.cxx
new file mode 100644
index 000000000..2735acee5
--- /dev/null
+++ b/dbaccess/source/ui/dlg/queryfilter.cxx
@@ -0,0 +1,748 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <queryfilter.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/string.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <connectivity/dbtools.hxx>
+#include <strings.hxx>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+
+using namespace dbaui;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+
+static void Replace_OS_PlaceHolder(OUString& aString)
+{
+ aString = aString.replaceAll( "*", "%" );
+ aString = aString.replaceAll( "?", "_" );
+}
+
+static void Replace_SQL_PlaceHolder(OUString& aString)
+{
+ aString = aString.replaceAll( "%", "*" );
+ aString = aString.replaceAll( "_", "?" );
+}
+
+DlgFilterCrit::DlgFilterCrit(weld::Window * pParent,
+ const Reference< XComponentContext >& rxContext,
+ const Reference< XConnection>& _rxConnection,
+ const Reference< XSingleSelectQueryComposer >& _rxComposer,
+ const Reference< XNameAccess>& _rxCols)
+ : GenericDialogController(pParent, "dbaccess/ui/queryfilterdialog.ui", "QueryFilterDialog")
+ , m_xQueryComposer(_rxComposer)
+ , m_xColumns( _rxCols )
+ , m_xConnection( _rxConnection )
+ , m_xMetaData( _rxConnection->getMetaData() )
+ , m_aPredicateInput( rxContext, _rxConnection, getParseContext() )
+ , m_xLB_WHEREFIELD1(m_xBuilder->weld_combo_box("field1"))
+ , m_xLB_WHERECOMP1(m_xBuilder->weld_combo_box("cond1"))
+ , m_xET_WHEREVALUE1(m_xBuilder->weld_entry("value1"))
+ , m_xLB_WHERECOND2(m_xBuilder->weld_combo_box("op2"))
+ , m_xLB_WHEREFIELD2(m_xBuilder->weld_combo_box("field2"))
+ , m_xLB_WHERECOMP2(m_xBuilder->weld_combo_box("cond2"))
+ , m_xET_WHEREVALUE2(m_xBuilder->weld_entry("value2"))
+ , m_xLB_WHERECOND3(m_xBuilder->weld_combo_box("op3"))
+ , m_xLB_WHEREFIELD3(m_xBuilder->weld_combo_box("field3"))
+ , m_xLB_WHERECOMP3(m_xBuilder->weld_combo_box("cond3"))
+ , m_xET_WHEREVALUE3(m_xBuilder->weld_entry("value3"))
+{
+ //set all condition preferred width to max width
+ //if all entries exist
+ Size aSize(m_xLB_WHERECOMP1->get_preferred_size());
+ m_xLB_WHERECOMP1->set_size_request(aSize.Width(), -1);
+ m_xLB_WHERECOMP2->set_size_request(aSize.Width(), -1);
+ m_xLB_WHERECOMP3->set_size_request(aSize.Width(), -1);
+ const sal_Int32 nEntryCount = m_xLB_WHERECOMP1->get_count();
+ m_aSTR_COMPARE_OPERATORS.resize(nEntryCount);
+ for (sal_Int32 i = 0; i < nEntryCount; ++i)
+ {
+ m_aSTR_COMPARE_OPERATORS[i] = m_xLB_WHERECOMP1->get_text(i);
+ }
+ m_xLB_WHERECOMP1->clear();
+
+ // ... also write it into the remaining fields
+ Sequence< OUString> aNames = m_xColumns->getElementNames();
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+ Reference<XPropertySet> xColumn;
+ for(;pIter != pEnd;++pIter)
+ {
+ try
+ {
+ xColumn.set( m_xColumns->getByName( *pIter ), UNO_QUERY_THROW );
+
+ sal_Int32 nDataType( 0 );
+ OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_TYPE ) >>= nDataType );
+ sal_Int32 eColumnSearch = ::dbtools::getSearchColumnFlag( m_xConnection, nDataType );
+ if ( eColumnSearch == ColumnSearch::NONE )
+ continue;
+
+ bool bIsSearchable( true );
+ OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISSEARCHABLE ) >>= bIsSearchable );
+ if ( !bIsSearchable )
+ continue;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xLB_WHEREFIELD1->append_text( *pIter );
+ m_xLB_WHEREFIELD2->append_text( *pIter );
+ m_xLB_WHEREFIELD3->append_text( *pIter );
+ }
+
+ Reference<XNameAccess> xSelectColumns = Reference<XColumnsSupplier>(m_xQueryComposer,UNO_QUERY_THROW)->getColumns();
+ aNames = xSelectColumns->getElementNames();
+ pIter = aNames.getConstArray();
+ pEnd = pIter + aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ // don't insert a column name twice
+ if ( !m_xColumns->hasByName(*pIter) )
+ {
+ xColumn.set(xSelectColumns->getByName(*pIter),UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"DlgFilterCrit::DlgFilterCrit: Column is null!");
+ sal_Int32 nDataType(0);
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType;
+ sal_Int32 eColumnSearch = dbtools::getSearchColumnFlag(m_xConnection,nDataType);
+ // TODO
+ // !pColumn->IsFunction()
+ if(eColumnSearch != ColumnSearch::NONE)
+ {
+ m_xLB_WHEREFIELD1->append_text( *pIter );
+ m_xLB_WHEREFIELD2->append_text( *pIter );
+ m_xLB_WHEREFIELD3->append_text( *pIter );
+ }
+ }
+ }
+ // initialize the listboxes with noEntry
+ m_xLB_WHEREFIELD1->set_active(0);
+ m_xLB_WHEREFIELD2->set_active(0);
+ m_xLB_WHEREFIELD3->set_active(0);
+
+ // insert the criteria into the dialog
+ Sequence<Sequence<PropertyValue > > aValues = m_xQueryComposer->getStructuredFilter();
+ int i(0);
+ fillLines(i, aValues);
+ aValues = m_xQueryComposer->getStructuredHavingClause();
+ fillLines(i, aValues);
+
+ EnableLines();
+
+ m_xLB_WHEREFIELD1->connect_changed(LINK(this,DlgFilterCrit,ListSelectHdl));
+ m_xLB_WHEREFIELD2->connect_changed(LINK(this,DlgFilterCrit,ListSelectHdl));
+ m_xLB_WHEREFIELD3->connect_changed(LINK(this,DlgFilterCrit,ListSelectHdl));
+
+ m_xLB_WHERECOMP1->connect_changed(LINK(this,DlgFilterCrit,ListSelectCompHdl));
+ m_xLB_WHERECOMP2->connect_changed(LINK(this,DlgFilterCrit,ListSelectCompHdl));
+ m_xLB_WHERECOMP3->connect_changed(LINK(this,DlgFilterCrit,ListSelectCompHdl));
+
+ m_xET_WHEREVALUE1->connect_focus_out( LINK( this, DlgFilterCrit, PredicateLoseFocus ) );
+ m_xET_WHEREVALUE2->connect_focus_out( LINK( this, DlgFilterCrit, PredicateLoseFocus ) );
+ m_xET_WHEREVALUE3->connect_focus_out( LINK( this, DlgFilterCrit, PredicateLoseFocus ) );
+
+ if (m_xET_WHEREVALUE1->get_sensitive())
+ m_xET_WHEREVALUE1->grab_focus();
+}
+
+DlgFilterCrit::~DlgFilterCrit()
+{
+}
+
+sal_Int32 DlgFilterCrit::GetOSQLPredicateType( std::u16string_view _rSelectedPredicate ) const
+{
+ sal_Int32 nPredicateIndex = -1;
+ for ( size_t i=0; i < m_aSTR_COMPARE_OPERATORS.size(); ++i)
+ if ( m_aSTR_COMPARE_OPERATORS[i] == _rSelectedPredicate )
+ {
+ nPredicateIndex = i;
+ break;
+ }
+
+ sal_Int32 nPredicateType = SQLFilterOperator::NOT_SQLNULL;
+ switch ( nPredicateIndex )
+ {
+ case 0:
+ nPredicateType = SQLFilterOperator::EQUAL;
+ break;
+ case 1:
+ nPredicateType = SQLFilterOperator::NOT_EQUAL;
+ break;
+ case 2:
+ nPredicateType = SQLFilterOperator::LESS;
+ break;
+ case 3:
+ nPredicateType = SQLFilterOperator::LESS_EQUAL;
+ break;
+ case 4:
+ nPredicateType = SQLFilterOperator::GREATER;
+ break;
+ case 5:
+ nPredicateType = SQLFilterOperator::GREATER_EQUAL;
+ break;
+ case 6:
+ nPredicateType = SQLFilterOperator::LIKE;
+ break;
+ case 7:
+ nPredicateType = SQLFilterOperator::NOT_LIKE;
+ break;
+ case 8:
+ nPredicateType = SQLFilterOperator::SQLNULL;
+ break;
+ case 9:
+ nPredicateType = SQLFilterOperator::NOT_SQLNULL;
+ break;
+ default:
+ OSL_FAIL( "DlgFilterCrit::GetOSQLPredicateType: unknown predicate string!" );
+ break;
+ }
+
+ return nPredicateType;
+}
+
+sal_Int32 DlgFilterCrit::GetSelectionPos(sal_Int32 eType, const weld::ComboBox& rListBox)
+{
+ sal_Int32 nPos;
+ switch(eType)
+ {
+ case SQLFilterOperator::EQUAL:
+ nPos = 0;
+ break;
+ case SQLFilterOperator::NOT_EQUAL:
+ nPos = 1;
+ break;
+ case SQLFilterOperator::LESS:
+ nPos = 2;
+ break;
+ case SQLFilterOperator::LESS_EQUAL:
+ nPos = 3;
+ break;
+ case SQLFilterOperator::GREATER:
+ nPos = 4;
+ break;
+ case SQLFilterOperator::GREATER_EQUAL:
+ nPos = 5;
+ break;
+ case SQLFilterOperator::NOT_LIKE:
+ nPos = rListBox.get_count() > 2 ? rListBox.get_count()-3 : 0;
+ break;
+ case SQLFilterOperator::LIKE:
+ nPos = rListBox.get_count() > 2 ? rListBox.get_count()-4 : 1;
+ break;
+ case SQLFilterOperator::SQLNULL:
+ nPos = rListBox.get_count()-2;
+ break;
+ case SQLFilterOperator::NOT_SQLNULL:
+ nPos = rListBox.get_count()-1;
+ break;
+ default:
+ // TODO What value should this be?
+ nPos = 0;
+ break;
+ }
+ return nPos;
+}
+
+bool DlgFilterCrit::getCondition(const weld::ComboBox& _rField,const weld::ComboBox& _rComp,const weld::Entry& _rValue,PropertyValue& _rFilter) const
+{
+ bool bHaving = false;
+ try
+ {
+ _rFilter.Name = _rField.get_active_text();
+ Reference< XPropertySet > xColumn = getQueryColumn(_rFilter.Name);
+ if ( xColumn.is() )
+ {
+ bool bFunction = false;
+ OUString sTableName;
+ Reference< XPropertySetInfo > xInfo = xColumn->getPropertySetInfo();
+ if ( xInfo->hasPropertyByName(PROPERTY_REALNAME) )
+ {
+ if ( xInfo->hasPropertyByName(PROPERTY_TABLENAME) )
+ {
+ xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
+ if ( !sTableName.isEmpty() )
+ {
+ // properly quote all parts of the table name, so
+ // e.g. <schema>.<table> becomes "<schema>"."<table>"
+ OUString aCatlog,aSchema,aTable;
+ ::dbtools::qualifiedNameComponents( m_xMetaData, sTableName, aCatlog, aSchema, aTable, ::dbtools::EComposeRule::InDataManipulation );
+ sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ }
+ xColumn->getPropertyValue(PROPERTY_REALNAME) >>= _rFilter.Name;
+ static constexpr OUStringLiteral sAgg = u"AggregateFunction";
+ if ( xInfo->hasPropertyByName(sAgg) )
+ xColumn->getPropertyValue(sAgg) >>= bHaving;
+ static constexpr OUStringLiteral sFunction = u"Function";
+ if ( xInfo->hasPropertyByName(sFunction) )
+ xColumn->getPropertyValue(sFunction) >>= bFunction;
+ }
+ if ( !bFunction )
+ {
+ const OUString aQuote = m_xMetaData.is() ? m_xMetaData->getIdentifierQuoteString() : OUString();
+ _rFilter.Name = ::dbtools::quoteName(aQuote,_rFilter.Name);
+ if ( !sTableName.isEmpty() )
+ {
+ sTableName += "." + _rFilter.Name;
+ _rFilter.Name = sTableName;
+ }
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+
+ _rFilter.Handle = GetOSQLPredicateType( _rComp.get_active_text() );
+ if ( SQLFilterOperator::SQLNULL != _rFilter.Handle && _rFilter.Handle != SQLFilterOperator::NOT_SQLNULL )
+ {
+ OUString sPredicateValue;
+ m_aPredicateInput.getPredicateValue( _rValue.get_text(), getMatchingColumn( _rValue ) ) >>= sPredicateValue;
+ if ( _rFilter.Handle == SQLFilterOperator::LIKE ||
+ _rFilter.Handle == SQLFilterOperator::NOT_LIKE )
+ ::Replace_OS_PlaceHolder( sPredicateValue );
+ _rFilter.Value <<= sPredicateValue;
+ }
+ return bHaving;
+}
+
+Reference< XPropertySet > DlgFilterCrit::getColumn( const OUString& _rFieldName ) const
+{
+ Reference< XPropertySet > xColumn;
+ try
+ {
+ if ( m_xColumns.is() && m_xColumns->hasByName( _rFieldName ) )
+ m_xColumns->getByName( _rFieldName ) >>= xColumn;
+
+ Reference< XNameAccess> xColumns = Reference< XColumnsSupplier >(m_xQueryComposer,UNO_QUERY_THROW)->getColumns();
+ if ( xColumns.is() && !xColumn.is() )
+ {
+ Sequence< OUString> aSeq = xColumns->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ Reference<XPropertySet> xProp(xColumns->getByName(*pIter),UNO_QUERY);
+ if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME) )
+ {
+ OUString sRealName;
+ xProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ if ( sRealName == _rFieldName )
+ {
+ if ( m_xColumns.is() && m_xColumns->hasByName( *pIter ) )
+ m_xColumns->getByName( *pIter ) >>= xColumn;
+ break;
+ }
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return xColumn;
+}
+
+Reference< XPropertySet > DlgFilterCrit::getQueryColumn( const OUString& _rFieldName ) const
+{
+ Reference< XPropertySet > xColumn;
+ try
+ {
+ Reference< XNameAccess> xColumns = Reference< XColumnsSupplier >(m_xQueryComposer,UNO_QUERY_THROW)->getColumns();
+ if ( xColumns.is() && xColumns->hasByName( _rFieldName ) )
+ xColumns->getByName( _rFieldName ) >>= xColumn;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return xColumn;
+}
+
+Reference< XPropertySet > DlgFilterCrit::getMatchingColumn( const weld::Entry& _rValueInput ) const
+{
+ // the name
+ OUString sField;
+ if ( &_rValueInput == m_xET_WHEREVALUE1.get() )
+ {
+ sField = m_xLB_WHEREFIELD1->get_active_text();
+ }
+ else if ( &_rValueInput == m_xET_WHEREVALUE2.get() )
+ {
+ sField = m_xLB_WHEREFIELD2->get_active_text();
+ }
+ else if ( &_rValueInput == m_xET_WHEREVALUE3.get() )
+ {
+ sField = m_xLB_WHEREFIELD3->get_active_text();
+ }
+ else {
+ OSL_FAIL( "DlgFilterCrit::getMatchingColumn: invalid event source!" );
+ }
+
+ // the field itself
+ return getColumn( sField );
+}
+
+IMPL_LINK( DlgFilterCrit, PredicateLoseFocus, weld::Widget&, rControl, void )
+{
+ weld::Entry& rField = dynamic_cast<weld::Entry&>(rControl);
+ // retrieve the field affected
+ Reference< XPropertySet> xColumn(getMatchingColumn(rField));
+ // and normalize its content
+ if ( xColumn.is() )
+ {
+ OUString sText(rField.get_text());
+ m_aPredicateInput.normalizePredicateString(sText, xColumn);
+ rField.set_text(sText);
+ }
+}
+
+void DlgFilterCrit::SetLine( int nIdx, const PropertyValue& _rItem, bool _bOr )
+{
+ OUString aStr;
+ _rItem.Value >>= aStr;
+ if ( _rItem.Handle == SQLFilterOperator::LIKE ||
+ _rItem.Handle == SQLFilterOperator::NOT_LIKE )
+ ::Replace_SQL_PlaceHolder(aStr);
+ aStr = comphelper::string::stripEnd(aStr, ' ');
+
+ Reference< XPropertySet > xColumn = getColumn( _rItem.Name );
+
+ // to make sure that we only set first three
+ weld::ComboBox* pColumnListControl = nullptr;
+ weld::ComboBox* pPredicateListControl = nullptr;
+ weld::Entry* pPredicateValueControl = nullptr;
+ switch( nIdx )
+ {
+ case 0:
+ pColumnListControl = m_xLB_WHEREFIELD1.get();
+ pPredicateListControl = m_xLB_WHERECOMP1.get();
+ pPredicateValueControl = m_xET_WHEREVALUE1.get();
+ break;
+ case 1:
+ m_xLB_WHERECOND2->set_active( _bOr ? 1 : 0 );
+
+ pColumnListControl = m_xLB_WHEREFIELD2.get();
+ pPredicateListControl = m_xLB_WHERECOMP2.get();
+ pPredicateValueControl = m_xET_WHEREVALUE2.get();
+ break;
+ case 2:
+ m_xLB_WHERECOND3->set_active( _bOr ? 1 : 0 );
+
+ pColumnListControl = m_xLB_WHEREFIELD3.get();
+ pPredicateListControl = m_xLB_WHERECOMP3.get();
+ pPredicateValueControl = m_xET_WHEREVALUE3.get();
+ break;
+ }
+
+ if ( !(pColumnListControl && pPredicateListControl && pPredicateValueControl) )
+ return;
+
+ OUString sName;
+ if ( xColumn.is() )
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ else
+ sName = _rItem.Name;
+ // select the appropriate field name
+ SelectField( *pColumnListControl, sName );
+ ListSelectHdl( *pColumnListControl );
+
+ // select the appropriate condition
+ pPredicateListControl->set_active( GetSelectionPos( _rItem.Handle, *pPredicateListControl ) );
+
+ // initially normalize this value
+ OUString aString( aStr );
+ m_aPredicateInput.normalizePredicateString( aString, xColumn );
+ pPredicateValueControl->set_text( aString );
+}
+
+void DlgFilterCrit::SelectField(weld::ComboBox& rBox, std::u16string_view rField)
+{
+ const sal_Int32 nCnt = rBox.get_count();
+
+ for( sal_Int32 i=0 ; i<nCnt ; i++ )
+ {
+ if (rBox.get_text(i) == rField)
+ {
+ rBox.set_active(i);
+ return;
+ }
+ }
+
+ rBox.set_active(0);
+}
+
+void DlgFilterCrit::EnableLines()
+{
+ // enabling/disabling of whole lines
+ if( m_xLB_WHEREFIELD1->get_active() == 0 )
+ {
+ m_xLB_WHEREFIELD2->set_sensitive(false);
+ m_xLB_WHERECOND2->set_sensitive(false);
+ m_xLB_WHERECOMP2->set_sensitive(false);
+ m_xET_WHEREVALUE2->set_sensitive(false);
+
+ m_xLB_WHEREFIELD3->set_sensitive(false);
+ m_xLB_WHERECOND3->set_sensitive(false);
+ m_xLB_WHERECOMP3->set_sensitive(false);
+ m_xET_WHEREVALUE3->set_sensitive(false);
+ }
+ else
+ {
+ m_xLB_WHEREFIELD2->set_sensitive(true);
+ m_xLB_WHERECOND2->set_sensitive(true);
+ m_xLB_WHERECOMP2->set_sensitive(true);
+ m_xET_WHEREVALUE2->set_sensitive(true);
+
+ m_xLB_WHEREFIELD3->set_sensitive(true);
+ m_xLB_WHERECOND3->set_sensitive(true);
+ m_xLB_WHERECOMP3->set_sensitive(true);
+ m_xET_WHEREVALUE3->set_sensitive(true);
+ }
+
+ if( m_xLB_WHEREFIELD2->get_active() == 0 )
+ {
+ m_xLB_WHEREFIELD3->set_sensitive(false);
+ m_xLB_WHERECOND3->set_sensitive(false);
+ m_xLB_WHERECOMP3->set_sensitive(false);
+ m_xET_WHEREVALUE3->set_sensitive(false);
+ }
+ else
+ {
+ m_xLB_WHEREFIELD3->set_sensitive(true);
+ m_xLB_WHERECOND3->set_sensitive(true);
+ m_xLB_WHERECOMP3->set_sensitive(true);
+ m_xET_WHEREVALUE3->set_sensitive(true);
+ }
+
+ // comparison field equal to NOENTRY
+ if( m_xLB_WHEREFIELD1->get_active() == 0 )
+ {
+ m_xLB_WHERECOMP1->set_sensitive(false);
+ m_xET_WHEREVALUE1->set_sensitive(false);
+ }
+ else
+ {
+ m_xLB_WHEREFIELD1->set_sensitive(true);
+ m_xLB_WHERECOMP1->set_sensitive(true);
+ m_xET_WHEREVALUE1->set_sensitive(true);
+ }
+
+ if( m_xLB_WHEREFIELD2->get_active() == 0 )
+ {
+ m_xLB_WHERECOND2->set_sensitive(false);
+ m_xLB_WHERECOMP2->set_sensitive(false);
+ m_xET_WHEREVALUE2->set_sensitive(false);
+ }
+ else
+ {
+ m_xLB_WHERECOND2->set_sensitive(true);
+ m_xLB_WHEREFIELD2->set_sensitive(true);
+ m_xLB_WHERECOMP2->set_sensitive(true);
+ m_xET_WHEREVALUE2->set_sensitive(true);
+ }
+
+ if( m_xLB_WHEREFIELD3->get_active() == 0 )
+ {
+ m_xLB_WHERECOND3->set_sensitive(false);
+ m_xLB_WHERECOMP3->set_sensitive(false);
+ m_xET_WHEREVALUE3->set_sensitive(false);
+ }
+ else
+ {
+ m_xLB_WHERECOND3->set_sensitive(true);
+ m_xLB_WHERECOND3->set_sensitive(true);
+ m_xLB_WHEREFIELD3->set_sensitive(true);
+ m_xLB_WHERECOMP3->set_sensitive(true);
+ m_xET_WHEREVALUE3->set_sensitive(true);
+ }
+
+ // comparison operator equal to ISNULL or ISNOTNULL
+ if(m_xLB_WHERECOMP1->get_count() > 2 &&
+ ((m_xLB_WHERECOMP1->get_active() == m_xLB_WHERECOMP1->get_count()-1) ||
+ (m_xLB_WHERECOMP1->get_active() == m_xLB_WHERECOMP1->get_count()-2)) )
+ m_xET_WHEREVALUE1->set_sensitive(false);
+
+ if(m_xLB_WHERECOMP2->get_count() > 2 &&
+ ((m_xLB_WHERECOMP2->get_active() == m_xLB_WHERECOMP2->get_count()-1) ||
+ (m_xLB_WHERECOMP2->get_active() == m_xLB_WHERECOMP2->get_count()-2)) )
+ m_xET_WHEREVALUE2->set_sensitive(false);
+
+ if(m_xLB_WHERECOMP3->get_count() > 2 &&
+ ((m_xLB_WHERECOMP3->get_active() == m_xLB_WHERECOMP3->get_count()-1) ||
+ (m_xLB_WHERECOMP3->get_active() == m_xLB_WHERECOMP3->get_count()-2)) )
+ m_xET_WHEREVALUE3->set_sensitive(false);
+}
+
+IMPL_LINK( DlgFilterCrit, ListSelectHdl, weld::ComboBox&, rListBox, void )
+{
+ OUString aName;
+ weld::ComboBox* pComp;
+ if(&rListBox == m_xLB_WHEREFIELD1.get())
+ {
+ aName = m_xLB_WHEREFIELD1->get_active_text();
+ pComp = m_xLB_WHERECOMP1.get();
+ }
+ else if(&rListBox == m_xLB_WHEREFIELD2.get())
+ {
+ aName = m_xLB_WHEREFIELD2->get_active_text();
+ pComp = m_xLB_WHERECOMP2.get();
+ }
+ else
+ {
+ aName = m_xLB_WHEREFIELD3->get_active_text();
+ pComp = m_xLB_WHERECOMP3.get();
+ }
+
+ pComp->clear();
+
+ Reference<XPropertySet> xColumn = getColumn(aName);
+ if ( xColumn.is() )
+ {
+ sal_Int32 nDataType = 0;
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType;
+ sal_Int32 eColumnSearch = dbtools::getSearchColumnFlag(m_xConnection,nDataType);
+
+ if(eColumnSearch == ColumnSearch::FULL)
+ {
+ for(size_t i=0;i < m_aSTR_COMPARE_OPERATORS.size(); i++)
+ pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]);
+ }
+ else if(eColumnSearch == ColumnSearch::CHAR)
+ {
+ for(sal_Int32 i=6; i<10; i++)
+ pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]);
+ }
+ else if(eColumnSearch == ColumnSearch::BASIC)
+ {
+ size_t i;
+ for( i = 0; i < 6; i++ )
+ pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]);
+ for(i=8; i < m_aSTR_COMPARE_OPERATORS.size(); ++i)
+ pComp->append_text(m_aSTR_COMPARE_OPERATORS[i]);
+ }
+ else
+ {
+ OSL_FAIL("DlgFilterCrit::ListSelectHdl: This column should not exist at all.");
+ }
+ }
+ pComp->set_active(0);
+
+ EnableLines();
+}
+
+IMPL_LINK_NOARG(DlgFilterCrit, ListSelectCompHdl, weld::ComboBox&, void)
+{
+ EnableLines();
+}
+
+void DlgFilterCrit::BuildWherePart()
+{
+ Sequence<Sequence<PropertyValue> > aFilter(1),aHaving(1);
+
+ if( m_xLB_WHEREFIELD1->get_active() != 0 )
+ {
+ PropertyValue aValue;
+ if ( getCondition(*m_xLB_WHEREFIELD1,*m_xLB_WHERECOMP1,*m_xET_WHEREVALUE1,aValue) )
+ {
+ aHaving = { { aValue } };
+ }
+ else
+ {
+ aFilter = { { aValue} };
+ }
+ }
+
+ if( m_xLB_WHEREFIELD2->get_active() != 0 )
+ {
+ PropertyValue aValue;
+ Sequence<Sequence<PropertyValue> >& _rValues = aFilter;
+ if ( getCondition(*m_xLB_WHEREFIELD2,*m_xLB_WHERECOMP2,*m_xET_WHEREVALUE2,aValue) )
+ _rValues = aHaving;
+ if ( m_xLB_WHERECOND2->get_active() )
+ _rValues.realloc( _rValues.getLength() + 1);
+ sal_Int32 nPos = _rValues.getLength() - 1;
+ sal_Int32 nAndPos = _rValues[nPos].getLength();
+ auto pValues = _rValues.getArray();
+ pValues[nPos].realloc( _rValues[nPos].getLength() + 1);
+ pValues[nPos].getArray()[nAndPos] = aValue;
+ }
+
+ if( m_xLB_WHEREFIELD3->get_active() != 0 )
+ {
+ PropertyValue aValue;
+ Sequence<Sequence<PropertyValue> >& _rValues = aFilter;
+ if ( getCondition(*m_xLB_WHEREFIELD3,*m_xLB_WHERECOMP3,*m_xET_WHEREVALUE3,aValue) )
+ _rValues = aHaving;
+ if (m_xLB_WHERECOND3->get_active())
+ _rValues.realloc( _rValues.getLength() + 1);
+ sal_Int32 nPos = _rValues.getLength() - 1;
+ sal_Int32 nAndPos = _rValues[nPos].getLength();
+ auto pValues = _rValues.getArray();
+ pValues[nPos].realloc( _rValues[nPos].getLength() + 1);
+ pValues[nPos].getArray()[nAndPos] = aValue;
+ }
+ try
+ {
+ m_xQueryComposer->setStructuredFilter(aFilter);
+ m_xQueryComposer->setStructuredHavingClause(aHaving);
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void DlgFilterCrit::fillLines(int &i, const Sequence< Sequence< PropertyValue > >& _aValues)
+{
+ const Sequence<PropertyValue >* pOrIter = _aValues.getConstArray();
+ const Sequence<PropertyValue >* pOrEnd = pOrIter + _aValues.getLength();
+ bool bOr(i != 0); // WHERE clause and HAVING clause are always ANDed, nor ORed
+ for(; pOrIter != pOrEnd; ++pOrIter)
+ {
+ const PropertyValue* pAndIter = pOrIter->getConstArray();
+ const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength();
+ for(;pAndIter != pAndEnd; ++pAndIter)
+ {
+ SetLine( i++,*pAndIter,bOr);
+ bOr = false;
+ }
+ bOr=true;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/queryorder.cxx b/dbaccess/source/ui/dlg/queryorder.cxx
new file mode 100644
index 000000000..40b25cdd3
--- /dev/null
+++ b/dbaccess/source/ui/dlg/queryorder.cxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <queryorder.hxx>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <tools/diagnose_ex.h>
+
+using namespace dbaui;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+
+
+DlgOrderCrit::DlgOrderCrit(weld::Window * pParent,
+ const Reference< XConnection>& _rxConnection,
+ const Reference< XSingleSelectQueryComposer >& _rxComposer,
+ const Reference< XNameAccess>& _rxCols)
+ : GenericDialogController(pParent, "dbaccess/ui/sortdialog.ui", "SortDialog")
+ , m_xQueryComposer(_rxComposer)
+ , m_xColumns(_rxCols)
+ , m_xConnection(_rxConnection)
+ , m_xLB_ORDERFIELD1(m_xBuilder->weld_combo_box("field1"))
+ , m_xLB_ORDERVALUE1(m_xBuilder->weld_combo_box("value1"))
+ , m_xLB_ORDERFIELD2(m_xBuilder->weld_combo_box("field2"))
+ , m_xLB_ORDERVALUE2(m_xBuilder->weld_combo_box("value2"))
+ , m_xLB_ORDERFIELD3(m_xBuilder->weld_combo_box("field3"))
+ , m_xLB_ORDERVALUE3(m_xBuilder->weld_combo_box("value3"))
+{
+ m_aColumnList[0] = m_xLB_ORDERFIELD1.get();
+ m_aColumnList[1] = m_xLB_ORDERFIELD2.get();
+ m_aColumnList[2] = m_xLB_ORDERFIELD3.get();
+
+ m_aValueList[0] = m_xLB_ORDERVALUE1.get();
+ m_aValueList[1] = m_xLB_ORDERVALUE2.get();
+ m_aValueList[2] = m_xLB_ORDERVALUE3.get();
+
+ OUString aSTR_NOENTRY(DBA_RES(STR_VALUE_NONE));
+ for (auto j : m_aColumnList)
+ {
+ j->append_text(aSTR_NOENTRY);
+ }
+
+ for (int j=0; j < DOG_ROWS; ++j)
+ {
+ m_aColumnList[j]->set_active(0);
+ m_aValueList[j]->set_active(0);
+ }
+ try
+ {
+ // ... also the remaining fields
+ Sequence< OUString> aNames = m_xColumns->getElementNames();
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+ Reference<XPropertySet> xColumn;
+ for(;pIter != pEnd;++pIter)
+ {
+ xColumn.set(m_xColumns->getByName(*pIter),UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"Column is null!");
+ if ( xColumn.is() )
+ {
+ sal_Int32 nDataType = 0;
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType;
+ sal_Int32 eColumnSearch = dbtools::getSearchColumnFlag(m_xConnection,nDataType);
+ if(eColumnSearch != ColumnSearch::NONE)
+ {
+ for (auto j : m_aColumnList)
+ {
+ j->append_text(*pIter);
+ }
+ }
+ }
+ }
+
+ m_sOrgOrder = m_xQueryComposer->getOrder();
+ impl_initializeOrderList_nothrow();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ EnableLines();
+
+ m_xLB_ORDERFIELD1->connect_changed(LINK(this,DlgOrderCrit,FieldListSelectHdl));
+ m_xLB_ORDERFIELD2->connect_changed(LINK(this,DlgOrderCrit,FieldListSelectHdl));
+}
+
+DlgOrderCrit::~DlgOrderCrit()
+{
+}
+
+IMPL_LINK_NOARG( DlgOrderCrit, FieldListSelectHdl, weld::ComboBox&, void )
+{
+ EnableLines();
+}
+
+void DlgOrderCrit::impl_initializeOrderList_nothrow()
+{
+ try
+ {
+ static const OUStringLiteral sNameProperty = u"Name";
+ static const OUStringLiteral sAscendingProperty = u"IsAscending";
+
+ Reference< XIndexAccess > xOrderColumns( m_xQueryComposer->getOrderColumns(), UNO_SET_THROW );
+ sal_Int32 nColumns = xOrderColumns->getCount();
+ if ( nColumns > DOG_ROWS )
+ nColumns = DOG_ROWS;
+
+ for ( sal_Int32 i = 0; i < nColumns; ++i )
+ {
+ Reference< XPropertySet > xColumn( xOrderColumns->getByIndex( i ), UNO_QUERY_THROW );
+
+ OUString sColumnName;
+ bool bIsAscending( true );
+
+ xColumn->getPropertyValue( sNameProperty ) >>= sColumnName;
+ xColumn->getPropertyValue( sAscendingProperty ) >>= bIsAscending;
+
+ m_aColumnList[i]->set_active_text(sColumnName);
+ m_aValueList[i]->set_active(bIsAscending ? 0 : 1);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void DlgOrderCrit::EnableLines()
+{
+
+ if ( m_xLB_ORDERFIELD1->get_active() == 0 )
+ {
+ m_xLB_ORDERFIELD2->set_sensitive(false);
+ m_xLB_ORDERVALUE2->set_sensitive(false);
+
+ m_xLB_ORDERFIELD2->set_active( 0 );
+ m_xLB_ORDERVALUE2->set_active( 0 );
+ }
+ else
+ {
+ m_xLB_ORDERFIELD2->set_sensitive(true);
+ m_xLB_ORDERVALUE2->set_sensitive(true);
+ }
+
+ if ( m_xLB_ORDERFIELD2->get_active() == 0 )
+ {
+ m_xLB_ORDERFIELD3->set_sensitive(false);
+ m_xLB_ORDERVALUE3->set_sensitive(false);
+
+ m_xLB_ORDERFIELD3->set_active( 0 );
+ m_xLB_ORDERVALUE3->set_active( 0 );
+ }
+ else
+ {
+ m_xLB_ORDERFIELD3->set_sensitive(true);
+ m_xLB_ORDERVALUE3->set_sensitive(true);
+ }
+}
+
+OUString DlgOrderCrit::GetOrderList( ) const
+{
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ OUString sQuote = xMetaData.is() ? xMetaData->getIdentifierQuoteString() : OUString();
+
+ OUStringBuffer sOrder;
+ for( sal_uInt16 i=0 ; i<DOG_ROWS; i++ )
+ {
+ if (m_aColumnList[i]->get_active() != 0)
+ {
+ if(!sOrder.isEmpty())
+ sOrder.append(",");
+
+ OUString sName = m_aColumnList[i]->get_active_text();
+ sOrder.append(::dbtools::quoteName(sQuote,sName));
+ if (m_aValueList[i]->get_active())
+ sOrder.append(" DESC ");
+ else
+ sOrder.append(" ASC ");
+ }
+ }
+ return sOrder.makeStringAndClear();
+}
+
+void DlgOrderCrit::BuildOrderPart()
+{
+ m_xQueryComposer->setOrder(GetOrderList());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/sqlmessage.cxx b/dbaccess/source/ui/dlg/sqlmessage.cxx
new file mode 100644
index 000000000..eacc59083
--- /dev/null
+++ b/dbaccess/source/ui/dlg/sqlmessage.cxx
@@ -0,0 +1,604 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <sqlmessage.hxx>
+#include <strings.hrc>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/diagnose.h>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <unotools/configmgr.hxx>
+
+#include <tools/urlobj.hxx>
+
+#define RET_MORE RET_RETRY + 1
+
+using namespace dbtools;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdb;
+using namespace com::sun::star::sdbc;
+
+namespace dbaui
+{
+
+namespace
+{
+ class ImageProvider
+ {
+ private:
+ OUString m_defaultImageID;
+
+ public:
+ explicit ImageProvider(const OUString& defaultImageID)
+ : m_defaultImageID(defaultImageID)
+ {
+ }
+
+ const OUString& getImage() const
+ {
+ return m_defaultImageID;
+ }
+ };
+
+ class LabelProvider
+ {
+ private:
+ OUString m_label;
+ public:
+ explicit LabelProvider(TranslateId labelResourceID)
+ : m_label(DBA_RES(labelResourceID))
+ {
+ }
+
+ const OUString& getLabel() const
+ {
+ return m_label;
+ }
+ };
+
+ class ProviderFactory
+ {
+ private:
+ mutable std::shared_ptr< ImageProvider > m_pErrorImage;
+ mutable std::shared_ptr< ImageProvider > m_pWarningsImage;
+ mutable std::shared_ptr< ImageProvider > m_pInfoImage;
+ mutable std::shared_ptr< LabelProvider > m_pErrorLabel;
+ mutable std::shared_ptr< LabelProvider > m_pWarningsLabel;
+ mutable std::shared_ptr< LabelProvider > m_pInfoLabel;
+
+ public:
+ ProviderFactory()
+ {
+ }
+
+ std::shared_ptr< ImageProvider > const & getImageProvider( SQLExceptionInfo::TYPE _eType ) const
+ {
+ std::shared_ptr< ImageProvider >* ppProvider( &m_pErrorImage );
+ OUString sNormalImageID("dialog-error");
+
+ switch ( _eType )
+ {
+ case SQLExceptionInfo::TYPE::SQLWarning:
+ ppProvider = &m_pWarningsImage;
+ sNormalImageID = "dialog-warning";
+ break;
+
+ case SQLExceptionInfo::TYPE::SQLContext:
+ ppProvider = &m_pInfoImage;
+ sNormalImageID = "dialog-information";
+ break;
+
+ default:
+ break;
+ }
+
+ if ( !ppProvider->get() )
+ (*ppProvider) = std::make_shared<ImageProvider>(sNormalImageID);
+ return *ppProvider;
+ }
+
+ std::shared_ptr< LabelProvider > const & getLabelProvider( SQLExceptionInfo::TYPE _eType, bool _bSubLabel ) const
+ {
+ std::shared_ptr< LabelProvider >* ppProvider( &m_pErrorLabel );
+ TranslateId pLabelID( STR_EXCEPTION_ERROR );
+
+ switch ( _eType )
+ {
+ case SQLExceptionInfo::TYPE::SQLWarning:
+ ppProvider = &m_pWarningsLabel;
+ pLabelID = STR_EXCEPTION_WARNING;
+ break;
+
+ case SQLExceptionInfo::TYPE::SQLContext:
+ ppProvider = &m_pInfoLabel;
+ pLabelID = _bSubLabel ? STR_EXCEPTION_DETAILS : STR_EXCEPTION_INFO;
+ break;
+ default:
+ break;
+ }
+
+ if ( !ppProvider->get() )
+ (*ppProvider) = std::make_shared<LabelProvider>( pLabelID );
+ return *ppProvider;
+ }
+
+ };
+
+ /// a stripped version of the SQLException, packed for displaying
+ struct ExceptionDisplayInfo
+ {
+ SQLExceptionInfo::TYPE eType;
+
+ std::shared_ptr< ImageProvider > pImageProvider;
+ std::shared_ptr< LabelProvider > pLabelProvider;
+
+ bool bSubEntry;
+
+ OUString sMessage;
+ OUString sSQLState;
+ OUString sErrorCode;
+
+ ExceptionDisplayInfo() : eType( SQLExceptionInfo::TYPE::Undefined ), bSubEntry( false ) { }
+ explicit ExceptionDisplayInfo( SQLExceptionInfo::TYPE _eType ) : eType( _eType ), bSubEntry( false ) { }
+ };
+
+ bool lcl_hasDetails( const ExceptionDisplayInfo& _displayInfo )
+ {
+ return ( !_displayInfo.sErrorCode.isEmpty() )
+ || ( !_displayInfo.sSQLState.isEmpty()
+ && _displayInfo.sSQLState != "S1000"
+ );
+ }
+
+ typedef std::vector< ExceptionDisplayInfo > ExceptionDisplayChain;
+
+ /// strips the [OOoBase] vendor identifier from the given error message, if applicable
+ OUString lcl_stripOOoBaseVendor( const OUString& _rErrorMessage )
+ {
+ OUString sErrorMessage( _rErrorMessage );
+
+ const OUString sVendorIdentifier( ::connectivity::SQLError::getMessagePrefix() );
+ if ( sErrorMessage.startsWith( sVendorIdentifier ) )
+ {
+ // characters to strip
+ sal_Int32 nStripLen( sVendorIdentifier.getLength() );
+ // usually, there should be a whitespace between the vendor and the real message
+ while ( ( sErrorMessage.getLength() > nStripLen )
+ && ( sErrorMessage[nStripLen] == ' ' )
+ )
+ ++nStripLen;
+ sErrorMessage = sErrorMessage.copy( nStripLen );
+ }
+
+ return sErrorMessage;
+ }
+
+ void lcl_buildExceptionChain( const SQLExceptionInfo& _rErrorInfo, const ProviderFactory& _rFactory, ExceptionDisplayChain& _out_rChain )
+ {
+ ExceptionDisplayChain().swap(_out_rChain);
+
+ SQLExceptionIteratorHelper iter( _rErrorInfo );
+ while ( iter.hasMoreElements() )
+ {
+ // current chain element
+ SQLExceptionInfo aCurrentElement;
+ iter.next( aCurrentElement );
+
+ const SQLException* pCurrentError = aCurrentElement;
+ OSL_ENSURE( pCurrentError, "lcl_buildExceptionChain: iterator failure!" );
+ // hasMoreElements should not have returned <TRUE/> in this case
+
+ ExceptionDisplayInfo aDisplayInfo( aCurrentElement.getType() );
+
+ aDisplayInfo.sMessage = pCurrentError->Message.trim();
+ aDisplayInfo.sSQLState = pCurrentError->SQLState;
+ if ( pCurrentError->ErrorCode )
+ aDisplayInfo.sErrorCode = OUString::number( pCurrentError->ErrorCode );
+
+ if ( aDisplayInfo.sMessage.isEmpty()
+ && !lcl_hasDetails( aDisplayInfo )
+ )
+ {
+ OSL_FAIL( "lcl_buildExceptionChain: useless exception: no state, no error code, no message!" );
+ continue;
+ }
+
+ aDisplayInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() );
+ aDisplayInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), false );
+
+ _out_rChain.push_back( aDisplayInfo );
+
+ if ( aCurrentElement.getType() == SQLExceptionInfo::TYPE::SQLContext )
+ {
+ const SQLContext* pContext = aCurrentElement;
+ if ( !pContext->Details.isEmpty() )
+ {
+ ExceptionDisplayInfo aSubInfo( aCurrentElement.getType() );
+
+ aSubInfo.sMessage = pContext->Details;
+ aSubInfo.pImageProvider = _rFactory.getImageProvider( aCurrentElement.getType() );
+ aSubInfo.pLabelProvider = _rFactory.getLabelProvider( aCurrentElement.getType(), true );
+ aSubInfo.bSubEntry = true;
+
+ _out_rChain.push_back( aSubInfo );
+ }
+ }
+ }
+ }
+
+ void lcl_insertExceptionEntry(weld::TreeView& rList, size_t nElementPos, const ExceptionDisplayInfo& rEntry)
+ {
+ rList.append(OUString::number(nElementPos), rEntry.pLabelProvider->getLabel(), rEntry.pImageProvider->getImage());
+ }
+}
+
+namespace {
+
+class OExceptionChainDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::TreeView> m_xExceptionList;
+ std::unique_ptr<weld::TextView> m_xExceptionText;
+
+ OUString m_sStatusLabel;
+ OUString m_sErrorCodeLabel;
+
+ ExceptionDisplayChain m_aExceptions;
+
+public:
+ OExceptionChainDialog(weld::Window* pParent, ExceptionDisplayChain&& rExceptions);
+
+protected:
+ DECL_LINK(OnExceptionSelected, weld::TreeView&, void);
+};
+
+}
+
+OExceptionChainDialog::OExceptionChainDialog(weld::Window* pParent, ExceptionDisplayChain&& rExceptions)
+ : GenericDialogController(pParent, "dbaccess/ui/sqlexception.ui", "SQLExceptionDialog")
+ , m_xExceptionList(m_xBuilder->weld_tree_view("list"))
+ , m_xExceptionText(m_xBuilder->weld_text_view("description"))
+ , m_aExceptions(std::move(rExceptions))
+{
+ int nListWidth = m_xExceptionText->get_approximate_digit_width() * 28;
+ int nTextWidth = m_xExceptionText->get_approximate_digit_width() * 42;
+ int nHeight = m_xExceptionList->get_height_rows(6);
+ m_xExceptionList->set_size_request(nListWidth, nHeight);
+ m_xExceptionText->set_size_request(nTextWidth, nHeight);
+
+ m_sStatusLabel = DBA_RES( STR_EXCEPTION_STATUS );
+ m_sErrorCodeLabel = DBA_RES( STR_EXCEPTION_ERRORCODE );
+
+ m_xExceptionList->connect_changed(LINK(this, OExceptionChainDialog, OnExceptionSelected));
+
+ bool bHave22018 = false;
+ size_t elementPos = 0;
+
+ for (auto const& elem : m_aExceptions)
+ {
+ lcl_insertExceptionEntry(*m_xExceptionList, elementPos, elem);
+ bHave22018 = elem.sSQLState == "22018";
+ ++elementPos;
+ }
+
+ // if the error has the code 22018, then add an additional explanation
+ // #i24021#
+ if ( bHave22018 )
+ {
+ ProviderFactory aProviderFactory;
+
+ ExceptionDisplayInfo aInfo22018;
+ aInfo22018.sMessage = DBA_RES( STR_EXPLAN_STRINGCONVERSION_ERROR );
+ aInfo22018.pLabelProvider = aProviderFactory.getLabelProvider( SQLExceptionInfo::TYPE::SQLContext, false );
+ aInfo22018.pImageProvider = aProviderFactory.getImageProvider( SQLExceptionInfo::TYPE::SQLContext );
+ m_aExceptions.push_back( aInfo22018 );
+
+ lcl_insertExceptionEntry(*m_xExceptionList, m_aExceptions.size() - 1, aInfo22018);
+ }
+
+ if (m_xExceptionList->n_children())
+ {
+ m_xExceptionList->select(0);
+ OnExceptionSelected(*m_xExceptionList);
+ }
+}
+
+IMPL_LINK_NOARG(OExceptionChainDialog, OnExceptionSelected, weld::TreeView&, void)
+{
+ OUString sText;
+
+ OUString sId(m_xExceptionList->get_selected_id());
+ if (!sId.isEmpty())
+ {
+ const ExceptionDisplayInfo& aExceptionInfo(m_aExceptions[sId.toUInt32()]);
+
+ if ( !aExceptionInfo.sSQLState.isEmpty() )
+ {
+ sText += m_sStatusLabel + ": " + aExceptionInfo.sSQLState + "\n";
+ }
+
+ if ( !aExceptionInfo.sErrorCode.isEmpty() )
+ {
+ sText += m_sErrorCodeLabel + ": " + aExceptionInfo.sErrorCode + "\n";
+ }
+
+ if ( !sText.isEmpty() )
+ sText += "\n";
+
+ sText += aExceptionInfo.sMessage;
+ }
+
+ m_xExceptionText->set_text(sText);
+}
+
+// SQLMessageBox_Impl
+struct SQLMessageBox_Impl
+{
+ ExceptionDisplayChain aDisplayInfo;
+
+ explicit SQLMessageBox_Impl( const SQLExceptionInfo& _rExceptionInfo )
+ {
+ // transform the exception chain to a form more suitable for displaying it here
+ ProviderFactory aProviderFactory;
+ lcl_buildExceptionChain( _rExceptionInfo, aProviderFactory, aDisplayInfo );
+ }
+};
+
+namespace
+{
+ void lcl_addButton(weld::MessageDialog* pDialog, StandardButtonType eType, bool bDefault)
+ {
+ sal_uInt16 nButtonID = 0;
+ switch (eType)
+ {
+ case StandardButtonType::Yes:
+ nButtonID = RET_YES;
+ pDialog->add_button(GetStandardText(StandardButtonType::Yes), nButtonID);
+ break;
+ case StandardButtonType::No:
+ nButtonID = RET_NO;
+ pDialog->add_button(GetStandardText(StandardButtonType::No), nButtonID);
+ break;
+ case StandardButtonType::OK:
+ nButtonID = RET_OK;
+ pDialog->add_button(GetStandardText(StandardButtonType::OK), nButtonID);
+ break;
+ case StandardButtonType::Cancel:
+ nButtonID = RET_CANCEL;
+ pDialog->add_button(GetStandardText(StandardButtonType::Cancel), nButtonID);
+ break;
+ case StandardButtonType::Retry:
+ nButtonID = RET_RETRY;
+ pDialog->add_button(GetStandardText(StandardButtonType::Retry), nButtonID);
+ break;
+ case StandardButtonType::Help:
+ nButtonID = RET_HELP;
+ pDialog->add_button(GetStandardText(StandardButtonType::Help), nButtonID);
+ break;
+ default:
+ OSL_FAIL( "lcl_addButton: invalid button id!" );
+ break;
+ }
+ if (bDefault)
+ pDialog->set_default_response(nButtonID);
+ }
+}
+
+void OSQLMessageBox::impl_fillMessages()
+{
+ OSL_PRECOND( !m_pImpl->aDisplayInfo.empty(), "OSQLMessageBox::impl_fillMessages: nothing to display at all?" );
+
+ if ( m_pImpl->aDisplayInfo.empty() )
+ return;
+ const ExceptionDisplayInfo* pSecondInfo = nullptr;
+
+ const ExceptionDisplayInfo& rFirstInfo = *m_pImpl->aDisplayInfo.begin();
+ if ( m_pImpl->aDisplayInfo.size() > 1 )
+ pSecondInfo = &m_pImpl->aDisplayInfo[1];
+ OUString sPrimary, sSecondary;
+ sPrimary = rFirstInfo.sMessage;
+ // one or two texts to display?
+ if ( pSecondInfo )
+ {
+ // we show two elements in the main dialog if and only if one of
+ // - the first element in the chain is an SQLContext, and the second
+ // element denotes its sub entry
+ // - the first and the second element are both independent (i.e. the second
+ // is no sub entry), and none of them is a context.
+ bool bFirstElementIsContext = ( rFirstInfo.eType == SQLExceptionInfo::TYPE::SQLContext );
+ bool bSecondElementIsContext = ( pSecondInfo->eType == SQLExceptionInfo::TYPE::SQLContext );
+
+ if ( bFirstElementIsContext && pSecondInfo->bSubEntry )
+ sSecondary = pSecondInfo->sMessage;
+ if ( !bFirstElementIsContext && !bSecondElementIsContext )
+ sSecondary = pSecondInfo->sMessage;
+ }
+
+ // primary text
+ m_xDialog->set_primary_text(lcl_stripOOoBaseVendor(sPrimary));
+
+ // secondary text (if applicable)
+ m_xDialog->set_secondary_text(lcl_stripOOoBaseVendor(sSecondary));
+}
+
+void OSQLMessageBox::impl_createStandardButtons( MessBoxStyle _nStyle )
+{
+ if ( _nStyle & MessBoxStyle::YesNoCancel )
+ {
+ lcl_addButton(m_xDialog.get(), StandardButtonType::Yes, bool(_nStyle & MessBoxStyle::DefaultYes));
+ lcl_addButton(m_xDialog.get(), StandardButtonType::No, bool(_nStyle & MessBoxStyle::DefaultNo));
+ lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel));
+ }
+ else if ( _nStyle & MessBoxStyle::OkCancel )
+ {
+ lcl_addButton(m_xDialog.get(), StandardButtonType::OK, bool(_nStyle & MessBoxStyle::DefaultOk));
+ lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel));
+ }
+ else if ( _nStyle & MessBoxStyle::YesNo )
+ {
+ lcl_addButton(m_xDialog.get(), StandardButtonType::Yes, bool(_nStyle & MessBoxStyle::DefaultYes));
+ lcl_addButton(m_xDialog.get(), StandardButtonType::No, bool(_nStyle & MessBoxStyle::DefaultNo));
+ }
+ else if ( _nStyle & MessBoxStyle::RetryCancel )
+ {
+ lcl_addButton(m_xDialog.get(), StandardButtonType::Retry, bool(_nStyle & MessBoxStyle::DefaultRetry));
+ lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel));
+ }
+ else if ( _nStyle & MessBoxStyle::Ok )
+ {
+ lcl_addButton(m_xDialog.get(), StandardButtonType::OK, true);
+ }
+
+ if ( m_sHelpURL.isEmpty() )
+ return;
+
+ lcl_addButton(m_xDialog.get(), StandardButtonType::Help, false);
+
+ OUString aTmp;
+ INetURLObject aHID( m_sHelpURL );
+ if ( aHID.GetProtocol() == INetProtocol::Hid )
+ aTmp = aHID.GetURLPath();
+ else
+ aTmp = m_sHelpURL;
+
+ m_xDialog->set_help_id(OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8));
+}
+
+void OSQLMessageBox::impl_addDetailsButton()
+{
+ size_t nFirstPageVisible = m_xDialog->get_secondary_text().isEmpty() ? 1 : 2;
+
+ bool bMoreDetailsAvailable = m_pImpl->aDisplayInfo.size() > nFirstPageVisible;
+ if ( !bMoreDetailsAvailable )
+ {
+ // even if the text fits into what we can display, we might need to details button
+ // if there is more non-trivial information in the errors than the mere messages
+ for (auto const& error : m_pImpl->aDisplayInfo)
+ {
+ if ( lcl_hasDetails(error) )
+ {
+ bMoreDetailsAvailable = true;
+ break;
+ }
+ }
+ }
+
+ if ( bMoreDetailsAvailable )
+ {
+ m_xDialog->add_button(GetStandardText(StandardButtonType::More), RET_MORE);
+ m_xMoreButton.reset(m_xDialog->weld_widget_for_response(RET_MORE));
+ m_xMoreButton->connect_clicked(LINK(this, OSQLMessageBox, ButtonClickHdl));
+ }
+}
+
+void OSQLMessageBox::Construct(weld::Window* pParent, MessBoxStyle _nStyle, MessageType _eImage)
+{
+ // init the image
+ MessageType eType( _eImage );
+ if ( eType == AUTO )
+ {
+ switch ( m_pImpl->aDisplayInfo[0].eType )
+ {
+ case SQLExceptionInfo::TYPE::SQLException: eType = Error; break;
+ case SQLExceptionInfo::TYPE::SQLWarning: eType = Warning; break;
+ case SQLExceptionInfo::TYPE::SQLContext: eType = Info; break;
+ default: OSL_FAIL( "OSQLMessageBox::Construct: invalid type!" );
+ }
+ }
+ VclMessageType eMessageType;
+ switch (eType)
+ {
+ default:
+ OSL_FAIL( "OSQLMessageBox::impl_initImage: unsupported image type!" );
+ [[fallthrough]];
+ case Info:
+ eMessageType = VclMessageType::Info;
+ break;
+ case Warning:
+ eMessageType = VclMessageType::Warning;
+ break;
+ case Error:
+ eMessageType = VclMessageType::Error;
+ break;
+ case Query:
+ eMessageType = VclMessageType::Question;
+ break;
+ }
+
+ m_xDialog.reset(Application::CreateMessageDialog(pParent, eMessageType, VclButtonsType::NONE, ""));
+ m_xDialog->set_title(utl::ConfigManager::getProductName() + " Base");
+
+ impl_fillMessages();
+
+ // create buttons
+ impl_createStandardButtons( _nStyle );
+ impl_addDetailsButton();
+}
+
+OSQLMessageBox::OSQLMessageBox(weld::Window* pParent, const SQLExceptionInfo& rException, MessBoxStyle nStyle, const OUString& rHelpURL)
+ : m_pImpl(new SQLMessageBox_Impl(rException))
+ , m_sHelpURL(rHelpURL)
+{
+ Construct(pParent, nStyle, AUTO);
+}
+
+OSQLMessageBox::OSQLMessageBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage, MessBoxStyle nStyle, MessageType eType, const ::dbtools::SQLExceptionInfo* pAdditionalErrorInfo )
+{
+ SQLContext aError;
+ aError.Message = rTitle;
+ aError.Details = rMessage;
+ if (pAdditionalErrorInfo)
+ aError.NextException = pAdditionalErrorInfo->get();
+
+ m_pImpl.reset(new SQLMessageBox_Impl(SQLExceptionInfo(aError)));
+
+ Construct(pParent, nStyle, eType);
+}
+
+OSQLMessageBox::~OSQLMessageBox()
+{
+}
+
+IMPL_LINK_NOARG(OSQLMessageBox, ButtonClickHdl, weld::Button&, void)
+{
+ OExceptionChainDialog aDlg(m_xDialog.get(), std::vector(m_pImpl->aDisplayInfo));
+ aDlg.run();
+}
+
+// OSQLWarningBox
+OSQLWarningBox::OSQLWarningBox(weld::Window* pParent, const OUString& rMessage, MessBoxStyle nStyle,
+ const ::dbtools::SQLExceptionInfo* pAdditionalErrorInfo )
+ : OSQLMessageBox(pParent, DBA_RES(STR_EXCEPTION_WARNING), rMessage, nStyle, MessageType::Warning, pAdditionalErrorInfo)
+{
+}
+
+// OSQLErrorBox
+OSQLErrorBox::OSQLErrorBox(weld::Window* pParent, const OUString& rMessage)
+ : OSQLMessageBox(pParent, DBA_RES(STR_EXCEPTION_ERROR), rMessage, MessBoxStyle::Ok | MessBoxStyle::DefaultOk,
+ MessageType::Error, nullptr)
+{
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/tablespage.cxx b/dbaccess/source/ui/dlg/tablespage.cxx
new file mode 100644
index 000000000..6094f84e7
--- /dev/null
+++ b/dbaccess/source/ui/dlg/tablespage.cxx
@@ -0,0 +1,488 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "tablespage.hxx"
+#include <dsitems.hxx>
+#include <datasourceconnector.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <stringlistitem.hxx>
+#include <svl/stritem.hxx>
+#include <strings.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <sqlmessage.hxx>
+#include <UITools.hxx>
+#include <osl/diagnose.h>
+#include <TablesSingleDlg.hxx>
+#include <tools/diagnose_ex.h>
+#include <cppuhelper/exc_hlp.hxx>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::util;
+ using namespace ::dbtools;
+ using namespace ::comphelper;
+
+ // OTableSubscriptionPage
+ OTableSubscriptionPage::OTableSubscriptionPage(weld::Container* pPage, OTableSubscriptionDialog* pTablesDlg, const SfxItemSet& _rCoreAttrs)
+ : OGenericAdministrationPage(pPage, pTablesDlg, "dbaccess/ui/tablesfilterpage.ui", "TablesFilterPage", _rCoreAttrs)
+ , m_bCatalogAtStart(true)
+ , m_pTablesDlg(pTablesDlg)
+ , m_xTables(m_xBuilder->weld_widget("TablesFilterPage"))
+ , m_xTablesList(new OTableTreeListBox(m_xBuilder->weld_tree_view("treeview"), true))
+ {
+ m_xTablesList->init();
+
+ weld::TreeView& rWidget = m_xTablesList->GetWidget();
+
+ rWidget.set_size_request(rWidget.get_approximate_digit_width() * 48,
+ rWidget.get_height_rows(12));
+
+ // initialize the TabListBox
+ rWidget.set_selection_mode(SelectionMode::Multiple);
+
+ rWidget.connect_toggled(LINK(this, OTableSubscriptionPage, OnTreeEntryChecked));
+ }
+
+ OTableSubscriptionPage::~OTableSubscriptionPage()
+ {
+ // just to make sure that our connection will be removed
+ try
+ {
+ ::comphelper::disposeComponent(m_xCurrentConnection);
+ }
+ catch (RuntimeException&) { }
+ }
+
+ void OTableSubscriptionPage::implCheckTables(const Sequence< OUString >& _rTables)
+ {
+ // the meta data for the current connection, used for splitting up table names
+ Reference< XDatabaseMetaData > xMeta;
+ try
+ {
+ if (m_xCurrentConnection.is())
+ xMeta = m_xCurrentConnection->getMetaData();
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("OTableSubscriptionPage::implCheckTables : could not retrieve the current connection's meta data!");
+ }
+
+ // uncheck all
+ CheckAll(false);
+
+ // check the ones which are in the list
+ OUString sCatalog, sSchema, sName;
+
+ std::unique_ptr<weld::TreeIter> xRootEntry(m_xTablesList->getAllObjectsEntry());
+
+ for (const OUString& rIncludeTable : _rTables)
+ {
+ if (xMeta.is())
+ qualifiedNameComponents(xMeta, rIncludeTable, sCatalog, sSchema, sName,::dbtools::EComposeRule::InDataManipulation);
+ else
+ sName = rIncludeTable;
+
+ bool bAllTables = (1 == sName.getLength()) && ('%' == sName[0]);
+ bool bAllSchemas = (1 == sSchema.getLength()) && ('%' == sSchema[0]);
+
+ // the catalog entry
+ std::unique_ptr<weld::TreeIter> xCatalog(m_xTablesList->GetEntryPosByName(sCatalog, xRootEntry.get()));
+ if (!(xCatalog || sCatalog.isEmpty()))
+ // the table (resp. its catalog) referred in this filter entry does not exist anymore
+ continue;
+
+ if (bAllSchemas && xCatalog)
+ {
+ m_xTablesList->checkWildcard(*xCatalog);
+ continue;
+ }
+
+ // the schema entry
+ std::unique_ptr<weld::TreeIter> xSchema = m_xTablesList->GetEntryPosByName(sSchema, (xCatalog ? xCatalog.get() : xRootEntry.get()));
+ if (!(xSchema || sSchema.isEmpty()))
+ // the table (resp. its schema) referred in this filter entry does not exist anymore
+ continue;
+
+ if (bAllTables && xSchema)
+ {
+ m_xTablesList->checkWildcard(*xSchema);
+ continue;
+ }
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTablesList->GetEntryPosByName(sName, xSchema ? xSchema.get() : (xCatalog ? xCatalog.get() : xRootEntry.get())));
+ if (xEntry)
+ m_xTablesList->GetWidget().set_toggle(*xEntry, TRISTATE_TRUE);
+ }
+ m_xTablesList->CheckButtons();
+ }
+
+ void OTableSubscriptionPage::implCompleteTablesCheck( const css::uno::Sequence< OUString >& _rTableFilter )
+ {
+ if (!_rTableFilter.hasElements())
+ { // no tables visible
+ CheckAll(false);
+ }
+ else
+ {
+ if ((1 == _rTableFilter.getLength()) && _rTableFilter[0] == "%")
+ { // all tables visible
+ CheckAll();
+ }
+ else
+ implCheckTables( _rTableFilter );
+ }
+ }
+
+ void OTableSubscriptionPage::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue)
+ {
+ // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa)
+ bool bValid, bReadonly;
+ getFlags(_rSet, bValid, bReadonly);
+
+ // get the name of the data source we're working for
+ const SfxStringItem* pNameItem = _rSet.GetItem<SfxStringItem>(DSID_NAME);
+ OSL_ENSURE(pNameItem, "OTableSubscriptionPage::implInitControls: missing the name attribute!");
+ OUString sDSName = pNameItem->GetValue();
+
+ if (bValid && !sDSName.isEmpty() && !m_xCurrentConnection.is() )
+ { // get the current table list from the connection for the current settings
+
+ // the PropertyValues for the current dialog settings
+ Sequence< PropertyValue > aConnectionParams;
+ OSL_ENSURE(m_pTablesDlg, "OTableSubscriptionPage::implInitControls: need a parent dialog doing the translation!");
+ if ( m_pTablesDlg )
+ {
+ if (!m_pTablesDlg->getCurrentSettings(aConnectionParams))
+ {
+ m_xTablesList->GetWidget().clear();
+ m_pTablesDlg->endExecution();
+ return;
+ }
+ }
+
+ // fill the table list with this connection information
+ SQLExceptionInfo aErrorInfo;
+
+ try
+ {
+ weld::WaitObject aWaitCursor(GetFrameWeld());
+
+ Reference<XPropertySet> xProp = m_pTablesDlg->getCurrentDataSource();
+ OSL_ENSURE(xProp.is(),"No data source set!");
+ if ( xProp.is() )
+ {
+ Any aTableFilter = xProp->getPropertyValue(PROPERTY_TABLEFILTER);
+ Any aTableTypeFilter = xProp->getPropertyValue(PROPERTY_TABLETYPEFILTER);
+
+ Reference<XModifiable> xModi(getDataSourceOrModel(xProp),UNO_QUERY);
+ bool bModified = ( xModi.is() && xModi->isModified() );
+
+ Sequence< OUString > aNewTableFilter { "%" };
+ xProp->setPropertyValue(PROPERTY_TABLEFILTER,Any(aNewTableFilter));
+
+ xProp->setPropertyValue( PROPERTY_TABLETYPEFILTER, Any( Sequence< OUString >() ) );
+ Reference< css::lang::XEventListener> xEvt;
+ aErrorInfo = ::dbaui::createConnection(xProp, m_xORB, xEvt, m_xCurrentConnection);
+
+ xProp->setPropertyValue(PROPERTY_TABLEFILTER,aTableFilter);
+ xProp->setPropertyValue(PROPERTY_TABLETYPEFILTER,aTableTypeFilter);
+
+ if ( xModi.is() && !bModified )
+ xModi->setModified(false);
+
+ }
+
+ if ( m_xCurrentConnection.is() )
+ {
+ m_xTablesList->UpdateTableList( m_xCurrentConnection );
+ if (m_pTablesDlg)
+ m_pTablesDlg->successfullyConnected();
+ }
+ }
+ catch (const SQLException&)
+ {
+ aErrorInfo = ::cppu::getCaughtException();
+ }
+
+ if (aErrorInfo.isValid())
+ {
+ // establishing the connection failed. Show an error window and exit.
+ OSQLMessageBox aMessageBox(GetFrameWeld(), aErrorInfo);
+ aMessageBox.run();
+ m_xTables->set_sensitive(false);
+ m_xTablesList->GetWidget().clear();
+
+ if ( m_pTablesDlg )
+ {
+ m_pTablesDlg->clearPassword();
+ m_pTablesDlg->endExecution();
+ }
+ }
+ else
+ {
+ // in addition, we need some infos about the connection used
+ m_sCatalogSeparator = "."; // (default)
+ m_bCatalogAtStart = true; // (default)
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta;
+ if (m_xCurrentConnection.is())
+ xMeta = m_xCurrentConnection->getMetaData();
+ if (xMeta.is() && xMeta->supportsCatalogsInDataManipulation())
+ {
+ m_sCatalogSeparator = xMeta->getCatalogSeparator();
+ m_bCatalogAtStart = xMeta->isCatalogAtStart();
+ }
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ // get the current table filter
+ const OStringListItem* pTableFilter = _rSet.GetItem<OStringListItem>(DSID_TABLEFILTER);
+ Sequence< OUString > aTableFilter;
+ if (pTableFilter)
+ aTableFilter = pTableFilter->getList();
+
+ implCompleteTablesCheck( aTableFilter );
+
+ // expand the first entry by default
+ std::unique_ptr<weld::TreeIter> xExpand = m_xTablesList->getAllObjectsEntry();
+ while (xExpand)
+ {
+ m_xTablesList->GetWidget().expand_row(*xExpand);
+ if (!m_xTablesList->GetWidget().iter_children(*xExpand))
+ break;
+ std::unique_ptr<weld::TreeIter> xSibling(m_xTablesList->GetWidget().make_iterator(xExpand.get()));
+ if (m_xTablesList->GetWidget().iter_next_sibling(*xSibling))
+ xExpand.reset();
+ }
+
+ // update the toolbox according the current selection and check state
+ OGenericAdministrationPage::implInitControls(_rSet, _bSaveValue);
+ }
+
+ void OTableSubscriptionPage::CheckAll( bool _bCheck )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTablesList->GetWidget().make_iterator());
+ if (m_xTablesList->GetWidget().get_iter_first(*xEntry))
+ {
+ do
+ {
+ m_xTablesList->GetWidget().set_toggle(*xEntry, _bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
+ }
+ while (m_xTablesList->GetWidget().iter_next(*xEntry));
+ }
+
+ if (_bCheck)
+ {
+ auto xRoot = m_xTablesList->getAllObjectsEntry();
+ if (xRoot)
+ m_xTablesList->checkWildcard(*xRoot);
+ }
+ }
+
+ DeactivateRC OTableSubscriptionPage::DeactivatePage(SfxItemSet* _pSet)
+ {
+ DeactivateRC nResult = OGenericAdministrationPage::DeactivatePage(_pSet);
+
+ // dispose the connection, we don't need it anymore, so we're not wasting resources
+ try
+ {
+ ::comphelper::disposeComponent(m_xCurrentConnection);
+ }
+ catch (RuntimeException&) { }
+
+ return nResult;
+ }
+
+ IMPL_LINK(OTableSubscriptionPage, OnTreeEntryChecked, const weld::TreeView::iter_col&, rRowCol, void)
+ {
+ m_xTablesList->checkedButton_noBroadcast(rRowCol.first);
+ callModifiedHdl();
+ }
+
+ Sequence< OUString > OTableSubscriptionPage::collectDetailedSelection() const
+ {
+ Sequence< OUString > aTableFilter;
+ constexpr OUStringLiteral sWildcard = u"%";
+
+ std::unique_ptr<weld::TreeIter> xAllObjectsEntry(m_xTablesList->getAllObjectsEntry());
+ if (!xAllObjectsEntry)
+ return aTableFilter;
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTablesList->GetWidget().make_iterator(xAllObjectsEntry.get()));
+ if (!m_xTablesList->GetWidget().iter_next(*xEntry))
+ xEntry.reset();
+ while (xEntry)
+ {
+ bool bCatalogWildcard = false;
+ bool bSchemaWildcard = false;
+ std::unique_ptr<weld::TreeIter> xSchema;
+ std::unique_ptr<weld::TreeIter> xCatalog;
+
+ if (m_xTablesList->GetWidget().get_toggle(*xEntry) == TRISTATE_TRUE && !m_xTablesList->GetWidget().iter_has_child(*xEntry))
+ { // checked and a leaf, which means it's no catalog, no schema, but a real table
+ OUStringBuffer sComposedName;
+ OUString sCatalog;
+ if (m_xTablesList->GetWidget().get_iter_depth(*xEntry))
+ {
+ xSchema = m_xTablesList->GetWidget().make_iterator(xEntry.get());
+ m_xTablesList->GetWidget().iter_parent(*xSchema);
+ if (xAllObjectsEntry->equal(*xSchema))
+ {
+ // do not want to have the root entry
+ xSchema.reset();
+ }
+
+ if (xSchema)
+ { // it's a real schema entry, not the "all objects" root
+ if (m_xTablesList->GetWidget().get_iter_depth(*xSchema))
+ {
+ xCatalog = m_xTablesList->GetWidget().make_iterator(xSchema.get());
+ m_xTablesList->GetWidget().iter_parent(*xCatalog);
+ if (xAllObjectsEntry->equal(*xCatalog))
+ {
+ // do not want to have the root entry
+ xCatalog.reset();
+ }
+
+ if (xCatalog)
+ { // it's a real catalog entry, not the "all objects" root
+ bCatalogWildcard = m_xTablesList->isWildcardChecked(*xCatalog);
+ if (m_bCatalogAtStart)
+ {
+ sComposedName.append(m_xTablesList->GetWidget().get_text(*xCatalog) + m_sCatalogSeparator);
+ if (bCatalogWildcard)
+ sComposedName.append(sWildcard);
+ }
+ else
+ {
+ if (bCatalogWildcard)
+ sCatalog = sWildcard;
+ else
+ sCatalog.clear();
+ sCatalog += m_sCatalogSeparator + m_xTablesList->GetWidget().get_text(*xCatalog) ;
+ }
+ }
+ }
+ bSchemaWildcard = m_xTablesList->isWildcardChecked(*xSchema);
+ sComposedName.append(m_xTablesList->GetWidget().get_text(*xSchema) + ".");
+ }
+
+ if (bSchemaWildcard)
+ sComposedName.append(sWildcard);
+ }
+ if (!bSchemaWildcard && !bCatalogWildcard)
+ sComposedName.append(m_xTablesList->GetWidget().get_text(*xEntry));
+
+ if (!m_bCatalogAtStart && !bCatalogWildcard)
+ sComposedName.append(sCatalog);
+
+ // need some space
+ sal_Int32 nOldLen = aTableFilter.getLength();
+ aTableFilter.realloc(nOldLen + 1);
+ // add the new name
+ aTableFilter.getArray()[nOldLen] = sComposedName.makeStringAndClear();
+ }
+
+ if (bCatalogWildcard)
+ xEntry = implNextSibling(xCatalog.get());
+ else if (bSchemaWildcard)
+ xEntry = implNextSibling(xSchema.get());
+ else
+ {
+ if (!m_xTablesList->GetWidget().iter_next(*xEntry))
+ xEntry.reset();
+ }
+ }
+
+ return aTableFilter;
+ }
+
+ std::unique_ptr<weld::TreeIter> OTableSubscriptionPage::implNextSibling(const weld::TreeIter* pEntry) const
+ {
+ std::unique_ptr<weld::TreeIter> xReturn;
+ if (pEntry)
+ {
+ xReturn = m_xTablesList->GetWidget().make_iterator(pEntry);
+ if (!m_xTablesList->GetWidget().iter_next_sibling(*xReturn))
+ {
+ std::unique_ptr<weld::TreeIter> xParent = m_xTablesList->GetWidget().make_iterator(pEntry);
+ if (m_xTablesList->GetWidget().iter_parent(*xParent))
+ xReturn = implNextSibling(xParent.get());
+ else
+ xReturn.reset();
+ }
+ }
+ return xReturn;
+ }
+
+ bool OTableSubscriptionPage::FillItemSet( SfxItemSet* _rCoreAttrs )
+ {
+ bool bValid, bReadonly;
+ getFlags(*_rCoreAttrs, bValid, bReadonly);
+
+ if (!bValid || bReadonly)
+ // don't store anything if the data we're working with is invalid or readonly
+ return true;
+
+ // create the output string which contains all the table names
+ if ( m_xCurrentConnection.is() )
+ { // collect the table filter data only if we have a connection - else no tables are displayed at all
+ Sequence< OUString > aTableFilter;
+ auto xRoot = m_xTablesList->getAllObjectsEntry();
+ if (xRoot && m_xTablesList->isWildcardChecked(*xRoot))
+ {
+ aTableFilter = { "%" };
+ }
+ else
+ {
+ aTableFilter = collectDetailedSelection();
+ }
+ _rCoreAttrs->Put( OStringListItem(DSID_TABLEFILTER, aTableFilter) );
+ }
+
+ return true;
+ }
+
+ void OTableSubscriptionPage::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& /*_rControlList*/)
+ {
+ }
+
+ void OTableSubscriptionPage::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
+ {
+ _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Widget>(m_xTables.get()));
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/tablespage.hxx b/dbaccess/source/ui/dlg/tablespage.hxx
new file mode 100644
index 000000000..483518b2a
--- /dev/null
+++ b/dbaccess/source/ui/dlg/tablespage.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "adminpages.hxx"
+#include <tabletree.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace dbaui
+{
+
+ // OTableSubscriptionPage
+ class OTableSubscriptionDialog;
+ class OTableSubscriptionPage final
+ :public OGenericAdministrationPage
+ {
+ private:
+ OUString m_sCatalogSeparator;
+ bool m_bCatalogAtStart : 1;
+
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xCurrentConnection; /// valid as long as the page is active
+ OTableSubscriptionDialog* m_pTablesDlg;
+
+ std::unique_ptr<weld::Widget> m_xTables;
+ std::unique_ptr<OTableTreeListBox> m_xTablesList;
+
+ public:
+ virtual bool FillItemSet(SfxItemSet* _rCoreAttrs) override;
+ virtual DeactivateRC DeactivatePage(SfxItemSet* _pSet) override;
+
+ OTableSubscriptionPage(weld::Container* pPage, OTableSubscriptionDialog* pController, const SfxItemSet& _rCoreAttrs);
+ virtual ~OTableSubscriptionPage() override;
+
+ private:
+ virtual void fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+ virtual void fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList) override;
+
+ DECL_LINK(OnTreeEntryChecked, const weld::TreeView::iter_col&, void);
+
+ /** check the tables in <member>m_aTablesList</member> according to <arg>_rTables</arg>
+ */
+ void implCheckTables(const css::uno::Sequence< OUString >& _rTables);
+
+ /// returns the next sibling, if not available, the next sibling of the parent, a.s.o.
+ std::unique_ptr<weld::TreeIter> implNextSibling(const weld::TreeIter* pEntry) const;
+
+ /** return the current selection in <member>m_aTablesList</member>
+ */
+ css::uno::Sequence< OUString > collectDetailedSelection() const;
+
+ /// (un)check all entries
+ void CheckAll( bool bCheck = true );
+
+ virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override;
+
+ // checks the tables according to the filter given
+ // in opposite to implCheckTables, this method handles the case of an empty sequence, too ...
+ void implCompleteTablesCheck( const css::uno::Sequence< OUString >& _rTableFilter );
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/dlg/textconnectionsettings.cxx b/dbaccess/source/ui/dlg/textconnectionsettings.cxx
new file mode 100644
index 000000000..5076b3d32
--- /dev/null
+++ b/dbaccess/source/ui/dlg/textconnectionsettings.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <textconnectionsettings.hxx>
+#include "TextConnectionHelper.hxx"
+#include <dsitems.hxx>
+#include <stringconstants.hxx>
+
+namespace dbaui
+{
+ // TextConnectionSettingsDialog
+ TextConnectionSettingsDialog::TextConnectionSettingsDialog(weld::Window* pParent, SfxItemSet& rItems)
+ : GenericDialogController(pParent, "dbaccess/ui/textconnectionsettings.ui", "TextConnectionSettingsDialog")
+ , m_rItems(rItems)
+ , m_xContainer(m_xBuilder->weld_widget("TextPageContainer"))
+ , m_xOK(m_xBuilder->weld_button("ok"))
+ , m_xTextConnectionHelper(new OTextConnectionHelper(m_xContainer.get(), TC_HEADER | TC_SEPARATORS | TC_CHARSET))
+ {
+ m_xOK->connect_clicked(LINK(this, TextConnectionSettingsDialog, OnOK));
+ }
+
+ TextConnectionSettingsDialog::~TextConnectionSettingsDialog()
+ {
+ }
+
+ void TextConnectionSettingsDialog::bindItemStorages( SfxItemSet& _rSet, PropertyValues& _rValues )
+ {
+ _rValues[ PROPERTY_ID_HEADER_LINE ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_TEXTFILEHEADER );
+ _rValues[ PROPERTY_ID_FIELD_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_FIELDDELIMITER );
+ _rValues[ PROPERTY_ID_STRING_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_TEXTDELIMITER );
+ _rValues[ PROPERTY_ID_DECIMAL_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_DECIMALDELIMITER );
+ _rValues[ PROPERTY_ID_THOUSAND_DELIMITER ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_THOUSANDSDELIMITER );
+ _rValues[ PROPERTY_ID_ENCODING ] = std::make_shared<SetItemPropertyStorage>( _rSet, DSID_CHARSET );
+ }
+
+ short TextConnectionSettingsDialog::run()
+ {
+ m_xTextConnectionHelper->implInitControls(m_rItems, true);
+ return GenericDialogController::run();
+ }
+
+ IMPL_LINK_NOARG(TextConnectionSettingsDialog, OnOK, weld::Button&, void)
+ {
+ if (m_xTextConnectionHelper->prepareLeave())
+ {
+ m_xTextConnectionHelper->FillItemSet( m_rItems, false/*bUnused*/ );
+ m_xDialog->response(RET_OK);
+ }
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/AppElementType.hxx b/dbaccess/source/ui/inc/AppElementType.hxx
new file mode 100644
index 000000000..59105cf22
--- /dev/null
+++ b/dbaccess/source/ui/inc/AppElementType.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+
+namespace dbaui
+{
+
+ enum ElementType
+ {
+ E_TABLE = css::sdb::application::DatabaseObject::TABLE,
+ E_QUERY = css::sdb::application::DatabaseObject::QUERY,
+ E_FORM = css::sdb::application::DatabaseObject::FORM,
+ E_REPORT = css::sdb::application::DatabaseObject::REPORT,
+
+ E_NONE = 4,
+ E_ELEMENT_TYPE_COUNT = E_NONE
+ };
+
+ enum PreviewMode
+ {
+ E_PREVIEWNONE = 0,
+ E_DOCUMENT = 1,
+ E_DOCUMENTINFO = 2
+ };
+
+ enum ElementOpenMode
+ {
+ E_OPEN_NORMAL,
+ E_OPEN_DESIGN,
+ E_OPEN_FOR_MAIL
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/ChildWindow.hxx b/dbaccess/source/ui/inc/ChildWindow.hxx
new file mode 100644
index 000000000..8da6c8570
--- /dev/null
+++ b/dbaccess/source/ui/inc/ChildWindow.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+class OChildWindow
+{
+protected:
+ OChildWindow(weld::Container* pParent, const OUString& rUIXMLDescription, const OString& rID);
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+
+public:
+ virtual ~OChildWindow();
+
+ virtual void GrabFocus() = 0;
+
+ virtual bool HasChildPathFocus() const = 0;
+
+ void Enable(bool bEnable) { m_xContainer->set_sensitive(bEnable); }
+
+ void SetHelpId(const OString& rHelpId) { m_xContainer->set_help_id(rHelpId); }
+
+ void Show() { m_xContainer->show(); }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/dbaccess/source/ui/inc/CollectionView.hxx b/dbaccess/source/ui/inc/CollectionView.hxx
new file mode 100644
index 000000000..c80e98f5e
--- /dev/null
+++ b/dbaccess/source/ui/inc/CollectionView.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaui
+{
+ /* this class allows to browse through the collection of forms and reports
+ */
+ class OCollectionView : public weld::GenericDialogController
+ {
+ css::uno::Reference< css::ucb::XContent> m_xContent;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::ucb::XCommandEnvironment > m_xCmdEnv;
+ bool m_bCreateForm;
+
+ std::unique_ptr<weld::Label> m_xFTCurrentPath;
+ std::unique_ptr<weld::Button> m_xNewFolder;
+ std::unique_ptr<weld::Button> m_xUp;
+ std::unique_ptr<weld::TreeView> m_xView;
+ std::unique_ptr<weld::Entry> m_xName;
+ std::unique_ptr<weld::Button> m_xPB_OK;
+
+ DECL_LINK(Up_Click, weld::Button&, void);
+ DECL_LINK(NewFolder_Click, weld::Button&, void);
+ DECL_LINK(Save_Click, weld::Button&, void);
+ DECL_LINK(Dbl_Click_FileView, weld::TreeView&, bool);
+
+ /// sets the fixedtext to the right content
+ void initCurrentPath();
+
+ void Initialize();
+ public:
+ OCollectionView(weld::Window * pParent,
+ const css::uno::Reference< css::ucb::XContent>& _xContent,
+ const OUString& _sDefaultName,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ virtual ~OCollectionView() override;
+ const css::uno::Reference< css::ucb::XContent>& getSelectedFolder() const { return m_xContent;}
+ OUString getName() const;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/ColumnControlWindow.hxx b/dbaccess/source/ui/inc/ColumnControlWindow.hxx
new file mode 100644
index 000000000..e68b99067
--- /dev/null
+++ b/dbaccess/source/ui/inc/ColumnControlWindow.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "FieldDescControl.hxx"
+#include "TypeInfo.hxx"
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <vcl/InterimItemWindow.hxx>
+
+namespace dbaui
+{
+ // OColumnControlWindow
+ class OColumnControlWindow : public OFieldDescControl
+ {
+ css::lang::Locale m_aLocale;
+ css::uno::Reference< css::uno::XComponentContext> m_xContext;
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ mutable css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier
+
+ OTypeInfoMap m_aDestTypeInfo;
+ std::vector<OTypeInfoMap::iterator> m_aDestTypeInfoIndex;
+
+ mutable TOTypeInfoSP m_pTypeInfo; // default type
+ OUString m_sTypeNames; // these type names are the ones out of the resource file
+ OUString m_sAutoIncrementValue;
+ bool m_bAutoIncrementEnabled;
+ protected:
+ virtual void ActivateAggregate( EControlType eType ) override;
+ virtual void DeactivateAggregate( EControlType eType ) override;
+
+ virtual css::lang::Locale GetLocale() const override;
+ virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const override;
+ virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) override;
+ virtual bool isAutoIncrementValueEnabled() const override;
+ virtual OUString getAutoIncrementValue() const override;
+ virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) override;
+
+ public:
+ OColumnControlWindow(weld::Container* pParent,
+ const css::uno::Reference< css::uno::XComponentContext>& _rxContext);
+
+ void setConnection(const css::uno::Reference< css::sdbc::XConnection>& _xCon);
+
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override;
+ virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override;
+ virtual const OTypeInfoMap* getTypeInfo() const override;
+ TOTypeInfoSP const & getDefaultTyp() const;
+ };
+
+ class OColumnControlTopLevel final : public InterimItemWindow
+ {
+ std::unique_ptr<OColumnControlWindow> m_xControl;
+ public:
+ OColumnControlTopLevel(vcl::Window* pParent,
+ const css::uno::Reference< css::uno::XComponentContext>& _rxContext);
+ virtual void dispose() override;
+
+ OColumnControlWindow& GetControl() { return *m_xControl; }
+
+ virtual void GetFocus() override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/ConnectionLine.hxx b/dbaccess/source/ui/inc/ConnectionLine.hxx
new file mode 100644
index 000000000..954c7e02d
--- /dev/null
+++ b/dbaccess/source/ui/inc/ConnectionLine.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <tools/gen.hxx>
+#include "ConnectionLineData.hxx"
+#include <vcl/vclptr.hxx>
+
+class OutputDevice;
+namespace dbaui
+{
+
+ // ConnData ---------->* ConnLineData
+ // ^1 ^1
+ // | |
+ // Conn ---------->* ConnLine
+
+ /*
+ the class OConnectionLine represents the graphical line between the to two windows
+ **/
+ class OTableConnection;
+ class OConnectionLine final
+ {
+ VclPtr<OTableConnection> m_pTabConn;
+ OConnectionLineDataRef m_pData;
+
+ Point m_aSourceConnPos,
+ m_aDestConnPos;
+ Point m_aSourceDescrLinePos,
+ m_aDestDescrLinePos;
+ public:
+ OConnectionLine( OTableConnection* pConn, OConnectionLineDataRef const & pLineData );
+ OConnectionLine( const OConnectionLine& rLine );
+ ~OConnectionLine();
+
+ OConnectionLine& operator=( const OConnectionLine& rLine );
+
+ tools::Rectangle GetBoundingRect() const;
+ bool RecalcLine();
+ void Draw( OutputDevice* pOutDev );
+ bool CheckHit( const Point& rMousePos ) const;
+
+ bool IsValid() const;
+
+ tools::Rectangle GetSourceTextPos() const;
+ tools::Rectangle GetDestTextPos() const;
+
+ const OConnectionLineDataRef& GetData() const { return m_pData; }
+
+ Point getMidPoint() const;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/ConnectionLineAccess.hxx b/dbaccess/source/ui/inc/ConnectionLineAccess.hxx
new file mode 100644
index 000000000..1652b8b0b
--- /dev/null
+++ b/dbaccess/source/ui/inc/ConnectionLineAccess.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TableConnection.hxx"
+#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
+#include <cppuhelper/implbase2.hxx>
+#include <toolkit/awt/vclxaccessiblecomponent.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace dbaui
+{
+ typedef ::cppu::ImplHelper2< css::accessibility::XAccessibleRelationSet,
+ css::accessibility::XAccessible
+ > OConnectionLineAccess_BASE;
+ class OTableConnection;
+ /** the class OConnectionLineAccess represents the accessible object for the connection between two table windows
+ like they are used in the QueryDesign and the RelationDesign
+ */
+ class OConnectionLineAccess : public VCLXAccessibleComponent
+ , public OConnectionLineAccess_BASE
+ {
+ VclPtr<const OTableConnection> m_pLine; // the window which I should give accessibility to
+ protected:
+ /** this function is called upon disposing the component
+ */
+ virtual void SAL_CALL disposing() override;
+
+ public:
+ OConnectionLineAccess(OTableConnection* _pLine);
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override
+ { // here inline is allowed because we do not use this class outside this dll
+ VCLXAccessibleComponent::acquire( );
+ }
+ virtual void SAL_CALL release( ) noexcept override
+ { // here inline is allowed because we do not use this class outside this dll
+ VCLXAccessibleComponent::release( );
+ }
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ // XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+
+ // XAccessibleComponent
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual css::awt::Rectangle SAL_CALL getBounds( ) override;
+ virtual css::awt::Point SAL_CALL getLocation( ) override;
+ virtual css::awt::Point SAL_CALL getLocationOnScreen( ) override;
+ virtual css::awt::Size SAL_CALL getSize( ) override;
+
+ // XAccessibleRelationSet
+ virtual sal_Int32 SAL_CALL getRelationCount( ) override;
+ virtual css::accessibility::AccessibleRelation SAL_CALL getRelation( sal_Int32 nIndex ) override;
+ virtual sal_Bool SAL_CALL containsRelation( sal_Int16 aRelationType ) override;
+ virtual css::accessibility::AccessibleRelation SAL_CALL getRelationByType( sal_Int16 aRelationType ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/ConnectionLineData.hxx b/dbaccess/source/ui/inc/ConnectionLineData.hxx
new file mode 100644
index 000000000..10ad0bfdd
--- /dev/null
+++ b/dbaccess/source/ui/inc/ConnectionLineData.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "QEnumTypes.hxx"
+#include <vector>
+
+#include <rtl/ref.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+#include <rtl/ustring.hxx>
+
+namespace dbaui
+{
+
+ // ConnData ---------->* ConnLineData
+ // ^1 ^1
+ // | |
+ // Conn ---------->* ConnLine
+
+ /**
+ the class OConnectionLineData contains the data of a connection
+ e.g. the source and the destination field
+ **/
+ class OConnectionLineData : public ::salhelper::SimpleReferenceObject
+ {
+ OUString m_aSourceFieldName;
+ OUString m_aDestFieldName;
+
+ friend bool operator==(const OConnectionLineData& lhs, const OConnectionLineData& rhs);
+ friend bool operator!=(const OConnectionLineData& lhs, const OConnectionLineData& rhs) { return !(lhs == rhs); }
+ protected:
+ virtual ~OConnectionLineData() override;
+ public:
+ OConnectionLineData();
+ OConnectionLineData( const OUString& rSourceFieldName, const OUString& rDestFieldName );
+ OConnectionLineData( const OConnectionLineData& rConnLineData );
+ // provide a copy of own instance (this is somehow more acceptable for me compared to a virtual assignment operator
+ void CopyFrom(const OConnectionLineData& rSource);
+
+ // member access (write)
+ void SetFieldName(EConnectionSide nWhich, const OUString& strFieldName)
+ {
+ if (nWhich==JTCS_FROM)
+ m_aSourceFieldName = strFieldName;
+ else
+ m_aDestFieldName = strFieldName;
+ }
+ void SetSourceFieldName( const OUString& rSourceFieldName){ SetFieldName(JTCS_FROM, rSourceFieldName); }
+ void SetDestFieldName( const OUString& rDestFieldName ){ SetFieldName(JTCS_TO, rDestFieldName); }
+
+ // member access (read)
+ const OUString& GetFieldName(EConnectionSide nWhich) const { return (nWhich == JTCS_FROM) ? m_aSourceFieldName : m_aDestFieldName; }
+ OUString const & GetSourceFieldName() const { return GetFieldName(JTCS_FROM); }
+ OUString const & GetDestFieldName() const { return GetFieldName(JTCS_TO); }
+
+ void Reset();
+ OConnectionLineData& operator=( const OConnectionLineData& rConnLineData );
+ };
+
+ typedef ::rtl::Reference< OConnectionLineData > OConnectionLineDataRef;
+ typedef std::vector< OConnectionLineDataRef > OConnectionLineDataVec;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/DExport.hxx b/dbaccess/source/ui/inc/DExport.hxx
new file mode 100644
index 000000000..ab7c85811
--- /dev/null
+++ b/dbaccess/source/ui/inc/DExport.hxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <map>
+#include <vector>
+#include <comphelper/stl_types.hxx>
+#include "TypeInfo.hxx"
+#include "WTypeSelect.hxx"
+#include "commontypes.hxx"
+#include "IUpdateHelper.hxx"
+
+namespace com::sun::star {
+ namespace awt{
+ struct FontDescriptor;
+ }
+ namespace sdbc{
+ class XPreparedStatement;
+ class XDatabaseMetaData;
+ }
+}
+
+#define COLUMN_POSITION_NOT_FOUND (sal_Int32(-1))
+
+class SvNumberFormatter;
+namespace dbaui
+{
+ class OFieldDescription;
+ class ODatabaseExport
+ {
+ public:
+ typedef std::map<OUString, OFieldDescription*, ::comphelper::UStringMixLess> TColumns;
+ typedef std::vector<TColumns::const_iterator> TColumnVector;
+ typedef std::vector< std::pair<sal_Int32,sal_Int32> > TPositions;
+
+ protected:
+ TPositions m_vColumnPositions; ///< columns to be used
+ std::vector<sal_Int32> m_vColumnTypes; ///< ColumnTypes for faster access
+ std::vector<sal_Int32> m_vColumnSize;
+ std::vector<sal_Int16> m_vNumberFormat;
+ css::lang::Locale m_aLocale;
+
+ TColumns m_aDestColumns; ///< container for new created columns
+ TColumnVector m_vDestVector;
+
+ css::uno::Reference< css::beans::XPropertySet > m_xTable; ///< dest table
+ css::uno::Reference< css::container::XNameAccess> m_xTables; ///< container
+ SharedConnection m_xConnection; ///< dest conn
+
+ std::shared_ptr<IUpdateHelper> m_pUpdateHelper;
+ css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; ///< a number formatter working with the connection's NumberFormatsSupplier
+ css::uno::Reference< css::uno::XComponentContext> m_xContext;
+ css::util::Date m_aNullDate;
+
+ SvNumberFormatter* m_pFormatter;
+ SvStream& m_rInputStream;
+ /// for saving the selected tablename
+ OUString m_sDefaultTableName;
+
+ OUString m_sTextToken; ///< cell content
+ OUString m_sNumToken; ///< SDNUM value
+ TOTypeInfoSP m_pTypeInfo; ///< contains the default type
+ const TColumnVector* m_pColumnList;
+ const OTypeInfoMap* m_pInfoMap;
+ sal_Int32 m_nColumnPos; ///< current column position
+ sal_Int32 m_nRows; ///< number of rows to be searched
+ sal_Int32 m_nRowCount; ///< current count of rows
+ bool m_bError; ///< error and termination code
+ bool m_bInTbl; ///< true, if parser is in RTF table
+ bool m_bHead; ///< true, if the header hasn't been read yet
+ bool m_bDontAskAgain;///< if there is an error when pasting, don't show it again
+ bool m_bIsAutoIncrement; ///< if PKey is set by user
+ bool m_bFoundTable; ///< set to true when a table was found
+ bool m_bCheckOnly;
+ bool m_bAppendFirstLine;
+
+
+ virtual TypeSelectionPageFactory
+ getTypeSelectionPageFactory() = 0;
+
+ void CreateDefaultColumn(const OUString& _rColumnName);
+ sal_Int16 CheckString(const OUString& aToken, sal_Int16 _nOldNumberFormat);
+ void adjustFormat();
+ void eraseTokens();
+ void insertValueIntoColumn();
+ void createRowSet();
+ void showErrorDialog(const css::sdbc::SQLException& e);
+ void ensureFormatter();
+
+ /** executeWizard calls a wizard to create/append data
+
+ @param _sTableName the tablename
+ @param _aTextColor the text color of the new created table
+ @param _rFont the font of the new table
+
+ @return true when an error occurs
+ */
+ bool executeWizard( const OUString& _sTableName,
+ const css::uno::Any& _aTextColor,
+ const css::awt::FontDescriptor& _rFont);
+
+ virtual ~ODatabaseExport();
+
+ public:
+ ODatabaseExport(
+ const SharedConnection& _rxConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ SvStream& _rInputStream
+ );
+
+ // required for automatic type recognition
+ ODatabaseExport(
+ sal_Int32 nRows,
+ TPositions&& _rColumnPositions,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const TColumnVector* rList,
+ const OTypeInfoMap* _pInfoMap,
+ bool _bAutoIncrementEnabled,
+ SvStream& _rInputStream
+ );
+
+ void SetColumnTypes(const TColumnVector* rList,const OTypeInfoMap* _pInfoMap);
+
+ void SetTableName(const OUString &_sTableName){ m_sDefaultTableName = _sTableName ; }
+
+ void enableCheckOnly() { m_bCheckOnly = true; }
+ bool isCheckEnabled() const { return m_bCheckOnly; }
+
+ static css::uno::Reference< css::sdbc::XPreparedStatement > createPreparedStatment( const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData
+ ,const css::uno::Reference< css::beans::XPropertySet>& _xDestTable
+ ,const TPositions& _rvColumnPositions);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/FieldControls.hxx b/dbaccess/source/ui/inc/FieldControls.hxx
new file mode 100644
index 000000000..7eb88ec4e
--- /dev/null
+++ b/dbaccess/source/ui/inc/FieldControls.hxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "SqlNameEdit.hxx"
+#include <unotools/resmgr.hxx>
+
+namespace dbaui
+{
+
+ class OPropColumnEditCtrl : public OSQLNameEntry
+ {
+ short m_nPos;
+ OUString m_strHelpText;
+ public:
+ OPropColumnEditCtrl(std::unique_ptr<weld::Entry> xEntry, OUString const & _rAllowedChars, TranslateId pHelpId, short nPosition);
+
+ short GetPos() const { return m_nPos; }
+ const OUString& GetHelp() const { return m_strHelpText; }
+ };
+
+ class OPropEditCtrl : public OWidgetBase
+ {
+ std::unique_ptr<weld::Entry> m_xEntry;
+ short m_nPos;
+ OUString m_strHelpText;
+
+ public:
+ OPropEditCtrl(std::unique_ptr<weld::Entry> xEntry, TranslateId pHelpId, short nPosition);
+
+ void set_text(const OUString& rText) { m_xEntry->set_text(rText); }
+ OUString get_text() const { return m_xEntry->get_text(); }
+ void set_editable(bool bEditable) { m_xEntry->set_editable(bEditable); }
+
+ virtual void save_value() override { m_xEntry->save_value(); }
+ virtual bool get_value_changed_from_saved() const override { return m_xEntry->get_value_changed_from_saved(); }
+
+ short GetPos() const { return m_nPos; }
+ const OUString& GetHelp() const { return m_strHelpText; }
+ };
+
+ class OPropNumericEditCtrl : public OWidgetBase
+ {
+ std::unique_ptr<weld::SpinButton> m_xSpinButton;
+ short m_nPos;
+ OUString m_strHelpText;
+
+ public:
+ OPropNumericEditCtrl(std::unique_ptr<weld::SpinButton> xSpinButton, TranslateId pHelpId, short nPosition);
+
+ void set_text(const OUString& rText) { m_xSpinButton->set_text(rText); }
+ OUString get_text() const { return m_xSpinButton->get_text(); }
+
+ virtual void save_value() override { m_xSpinButton->save_value(); }
+ virtual bool get_value_changed_from_saved() const override { return m_xSpinButton->get_value_changed_from_saved(); }
+ void set_digits(int nLen) { m_xSpinButton->set_digits(nLen); }
+ void set_min(int nMin) { m_xSpinButton->set_min(nMin); }
+ void set_max(int nMax) { m_xSpinButton->set_max(nMax); }
+ void set_range(int nMin, int nMax) { m_xSpinButton->set_range(nMin, nMax); }
+ int get_value() const { return m_xSpinButton->get_value(); }
+
+ short GetPos() const { return m_nPos; }
+ const OUString& GetHelp() const { return m_strHelpText; }
+
+ void set_editable(bool bEditable) { m_xSpinButton->set_editable(bEditable); }
+ };
+
+ class OPropListBoxCtrl : public OWidgetBase
+ {
+ std::unique_ptr<weld::ComboBox> m_xComboBox;
+ short m_nPos;
+ OUString m_strHelpText;
+
+ public:
+ OPropListBoxCtrl(std::unique_ptr<weld::ComboBox> xComboBox, TranslateId pHelpId, short nPosition);
+ virtual ~OPropListBoxCtrl() override
+ {
+ m_xComboBox->clear();
+ }
+
+ virtual void save_value() override { m_xComboBox->save_value(); }
+ virtual bool get_value_changed_from_saved() const override { return m_xComboBox->get_value_changed_from_saved(); }
+
+ weld::ComboBox& GetComboBox() { return *m_xComboBox; }
+
+ OUString get_active_text() const { return m_xComboBox->get_active_text(); }
+ void set_active_text(const OUString &rText) { m_xComboBox->set_active_text(rText); }
+
+ int get_active() const { return m_xComboBox->get_active(); }
+ void set_active(int nPos) { m_xComboBox->set_active(nPos); }
+
+ int get_count() const { return m_xComboBox->get_count(); }
+
+ void append_text(const OUString &rText) { m_xComboBox->append_text(rText); }
+ void remove_text(const OUString &rText) { m_xComboBox->remove_text(rText); }
+ int find_text(const OUString &rText) const { return m_xComboBox->find_text(rText); }
+
+ short GetPos() const { return m_nPos; }
+ const OUString& GetHelp() const { return m_strHelpText; }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/FieldDescControl.hxx b/dbaccess/source/ui/inc/FieldDescControl.hxx
new file mode 100644
index 000000000..478a41070
--- /dev/null
+++ b/dbaccess/source/ui/inc/FieldDescControl.hxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+#include "IClipBoardTest.hxx"
+#include "QEnumTypes.hxx"
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include "TypeInfo.hxx"
+#include <unotools/resmgr.hxx>
+
+// field description columns of a table
+#define FIELD_NAME 1
+#define FIELD_TYPE 2
+#define HELP_TEXT 3
+#define COLUMN_DESCRIPTION 4
+
+#define FIELD_FIRST_VIRTUAL_COLUMN 5
+
+#define FIELD_PROPERTY_REQUIRED 5
+#define FIELD_PROPERTY_NUMTYPE 6
+#define FIELD_PROPERTY_AUTOINC 7
+#define FIELD_PROPERTY_DEFAULT 8
+#define FIELD_PROPERTY_TEXTLEN 9
+#define FIELD_PROPERTY_LENGTH 10
+#define FIELD_PROPERTY_SCALE 11
+#define FIELD_PROPERTY_BOOL_DEFAULT 12
+#define FIELD_PROPERTY_FORMAT 13
+#define FIELD_PROPERTY_COLUMNNAME 14
+#define FIELD_PROPERTY_TYPE 15
+#define FIELD_PROPERTY_AUTOINCREMENT 16
+
+namespace dbaui
+{
+ class OTableDesignHelpBar;
+ class OPropListBoxCtrl;
+ class OPropEditCtrl;
+ class OPropNumericEditCtrl;
+ class OFieldDescription;
+ class OPropColumnEditCtrl;
+
+ class OFieldDescControl : public IClipboardTest
+ {
+ private:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+
+ OTableDesignHelpBar* m_pHelp;
+ weld::Widget* m_pLastFocusWindow;
+ weld::Widget* m_pActFocusWindow;
+
+ std::unique_ptr<weld::Label> m_xDefaultText;
+ std::unique_ptr<weld::Label> m_xRequiredText;
+ std::unique_ptr<weld::Label> m_xAutoIncrementText;
+ std::unique_ptr<weld::Label> m_xTextLenText;
+ std::unique_ptr<weld::Label> m_xNumTypeText;
+ std::unique_ptr<weld::Label> m_xLengthText;
+ std::unique_ptr<weld::Label> m_xScaleText;
+ std::unique_ptr<weld::Label> m_xFormatText;
+ std::unique_ptr<weld::Label> m_xBoolDefaultText;
+ std::unique_ptr<weld::Label> m_xColumnNameText;
+ std::unique_ptr<weld::Label> m_xTypeText;
+ std::unique_ptr<weld::Label> m_xAutoIncrementValueText;
+
+ std::unique_ptr<OPropListBoxCtrl> m_xRequired;
+ std::unique_ptr<OPropListBoxCtrl> m_xNumType;
+ std::unique_ptr<OPropListBoxCtrl> m_xAutoIncrement;
+ std::unique_ptr<OPropEditCtrl> m_xDefault;
+ std::unique_ptr<OPropNumericEditCtrl> m_xTextLen;
+ std::unique_ptr<OPropNumericEditCtrl> m_xLength;
+ std::unique_ptr<OPropNumericEditCtrl> m_xScale;
+ std::unique_ptr<OPropEditCtrl> m_xFormatSample;
+ std::unique_ptr<OPropListBoxCtrl> m_xBoolDefault;
+ std::unique_ptr<OPropColumnEditCtrl> m_xColumnName;
+ std::unique_ptr<OPropListBoxCtrl> m_xType;
+ std::unique_ptr<OPropEditCtrl> m_xAutoIncrementValue;
+
+ std::unique_ptr<weld::Button> m_xFormat;
+
+ Link<weld::Widget&, void> m_aControlFocusIn;
+
+ TOTypeInfoSP m_pPreviousType;
+ short m_nPos;
+ OUString aYes;
+ OUString aNo;
+
+ sal_Int32 m_nEditWidth;
+
+ OFieldDescription* pActFieldDescr;
+
+ DECL_LINK(FormatClickHdl, weld::Button&, void);
+ DECL_LINK(ChangeHdl, weld::ComboBox&, void);
+
+ // used by ActivatePropertyField
+ DECL_LINK( OnControlFocusLost, weld::Widget&, void );
+ DECL_LINK( OnControlFocusGot, weld::Widget&, void );
+
+ DECL_LINK( HelpFocusOut, weld::Widget&, void );
+
+ void UpdateFormatSample(OFieldDescription const * pFieldDescr);
+
+ bool isTextFormat(const OFieldDescription* _pFieldDescr,sal_uInt32& _nFormatKey) const;
+ std::unique_ptr<OPropNumericEditCtrl> CreateNumericControl(const OString& rId, TranslateId pHelpId, short _nProperty, const OString& _sHelpId);
+ void InitializeControl(weld::Widget* _pControl,const OString& _sHelpId);
+ void InitializeControl(OPropListBoxCtrl* _pControl,const OString& _sHelpId,bool _bAddChangeHandler);
+
+ bool IsFocusInEditableWidget() const;
+
+ void dispose();
+ protected:
+ void saveCurrentFieldDescData() { SaveData( pActFieldDescr ); }
+ OFieldDescription* getCurrentFieldDescData() { return pActFieldDescr; }
+ void setCurrentFieldDescData( OFieldDescription* _pDesc ) { pActFieldDescr = _pDesc; }
+
+ virtual void ActivateAggregate( EControlType eType );
+ virtual void DeactivateAggregate( EControlType eType );
+ virtual bool IsReadOnly() { return false; };
+
+ virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const = 0;
+
+ virtual css::lang::Locale GetLocale() const = 0;
+
+ virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) = 0;
+ virtual void SetModified(bool bModified); // base implementation is empty
+
+ virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) = 0;
+ virtual const OTypeInfoMap* getTypeInfo() const = 0;
+
+ virtual bool isAutoIncrementValueEnabled() const = 0;
+ virtual OUString getAutoIncrementValue() const = 0;
+
+ OUString BoolStringPersistent(std::u16string_view rUIString) const;
+ OUString BoolStringUI(const OUString& rPersistentString) const;
+
+ const OPropColumnEditCtrl* getColumnCtrl() const { return m_xColumnName.get(); }
+
+ void implFocusLost(weld::Widget* _pWhich);
+
+ public:
+ OFieldDescControl(weld::Container* pPage, OTableDesignHelpBar* pHelpBar);
+ virtual ~OFieldDescControl();
+
+ void DisplayData(OFieldDescription* pFieldDescr );
+
+ void SaveData( OFieldDescription* pFieldDescr );
+
+ void SetControlText( sal_uInt16 nControlId, const OUString& rText );
+ void SetReadOnly( bool bReadOnly );
+
+ void Enable(bool bEnable) { m_xContainer->set_sensitive(bEnable); }
+ void SetHelpId(const OString& rId) { m_xContainer->set_help_id(rId); }
+
+ virtual bool isCutAllowed() override;
+ virtual bool isCopyAllowed() override;
+ virtual bool isPasteAllowed() override;
+
+ virtual void cut() override;
+ virtual void copy() override;
+ virtual void paste() override;
+
+ void connect_focus_in(const Link<weld::Widget&, void>& rLink)
+ {
+ m_aControlFocusIn = rLink;
+ }
+
+ void Init();
+
+ void GrabFocus();
+
+ bool HasChildPathFocus() const;
+
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() = 0;
+ virtual css::uno::Reference< css::sdbc::XConnection> getConnection() = 0;
+
+ OUString getControlDefault( const OFieldDescription* pFieldDescr, bool _bCheck = true) const;
+ // tdf#138409 take the control default in the UI Locale format, e.g. 12,34 and return a string
+ // suitable as the database default, e.g. 12.34
+ OUString CanonicalizeToControlDefault(const OFieldDescription* pFieldDescr, const OUString& rUserText) const;
+
+ void setEditWidth(sal_Int32 _nWidth) { m_nEditWidth = _nWidth; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/FieldDescriptions.hxx b/dbaccess/source/ui/inc/FieldDescriptions.hxx
new file mode 100644
index 000000000..5eccd7430
--- /dev/null
+++ b/dbaccess/source/ui/inc/FieldDescriptions.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <editeng/svxenum.hxx>
+#include "TypeInfo.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+
+namespace dbaui
+{
+ class OFieldDescription
+ {
+ private:
+ css::uno::Any m_aControlDefault; // the value which the control inserts as default
+ css::uno::Any m_aWidth; // sal_Int32 or void
+ css::uno::Any m_aRelativePosition; // sal_Int32 or void
+
+ TOTypeInfoSP m_pType;
+
+ css::uno::Reference< css::beans::XPropertySet > m_xDest;
+ css::uno::Reference< css::beans::XPropertySetInfo > m_xDestInfo;
+
+ OUString m_sName;
+ OUString m_sTypeName;
+ OUString m_sDescription;
+ OUString m_sHelpText;
+
+ OUString m_sAutoIncrementValue;
+ sal_Int32 m_nType; // only used when m_pType is null
+ sal_Int32 m_nPrecision;
+ sal_Int32 m_nScale;
+ sal_Int32 m_nIsNullable;
+ sal_Int32 m_nFormatKey;
+ SvxCellHorJustify m_eHorJustify;
+ bool m_bIsAutoIncrement;
+ bool m_bIsPrimaryKey;
+ bool m_bIsCurrency;
+ bool m_bHidden;
+
+ public:
+ OFieldDescription();
+ OFieldDescription( const OFieldDescription& rDescr );
+ OFieldDescription(const css::uno::Reference< css::beans::XPropertySet >& _xAffectedCol
+ ,bool _bUseAsDest = false);
+ ~OFieldDescription();
+
+ void SetName(const OUString& _rName);
+ void SetDescription(const OUString& _rDescription);
+ void SetHelpText(const OUString& _sHelptext);
+ void SetDefaultValue(const css::uno::Any& _rDefaultValue);
+ void SetControlDefault(const css::uno::Any& _rControlDefault);
+ void SetAutoIncrementValue(const OUString& _sAutoIncValue);
+ void SetType(const TOTypeInfoSP& _pType);
+ void SetTypeValue(sal_Int32 _nType);
+ void SetTypeName(const OUString& _sTypeName);
+ void SetPrecision(sal_Int32 _rPrecision);
+ void SetScale(sal_Int32 _rScale);
+ void SetIsNullable(sal_Int32 _rIsNullable);
+ void SetFormatKey(sal_Int32 _rFormatKey);
+ void SetHorJustify(const SvxCellHorJustify& _rHorJustify);
+ void SetAutoIncrement(bool _bAuto);
+ void SetPrimaryKey(bool _bPKey);
+ void SetCurrency(bool _bIsCurrency);
+
+ /** copies the content of the field description into the column
+ @param _rxColumn the dest
+ */
+ void copyColumnSettingsTo(const css::uno::Reference< css::beans::XPropertySet >& _rxColumn);
+
+ void FillFromTypeInfo(const TOTypeInfoSP& _pType,bool _bForce,bool _bReset);
+
+ OUString GetName() const;
+ OUString GetDescription() const;
+ OUString GetHelpText() const;
+ css::uno::Any GetControlDefault() const;
+ OUString GetAutoIncrementValue() const;
+ sal_Int32 GetType() const;
+ OUString GetTypeName() const;
+ sal_Int32 GetPrecision() const;
+ sal_Int32 GetScale() const;
+ sal_Int32 GetIsNullable() const;
+ sal_Int32 GetFormatKey() const;
+ SvxCellHorJustify GetHorJustify() const;
+ const TOTypeInfoSP& getTypeInfo() const { return m_pType;}
+ TOTypeInfoSP getSpecialTypeInfo() const;
+ bool IsAutoIncrement() const;
+ bool IsPrimaryKey() const { return m_bIsPrimaryKey;}
+ bool IsCurrency() const { return m_bIsCurrency;}
+ bool IsNullable() const;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/GeneralUndo.hxx b/dbaccess/source/ui/inc/GeneralUndo.hxx
new file mode 100644
index 000000000..1bbb593e3
--- /dev/null
+++ b/dbaccess/source/ui/inc/GeneralUndo.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svl/undo.hxx>
+#include <core_resource.hxx>
+
+namespace dbaui
+{
+ // SbaCommentUndoAction - Undo base class for actions whose GetComment provides
+ // a string loaded from a Sba resource
+
+ class OCommentUndoAction : public SfxUndoAction
+ {
+ OUString m_strComment; // undo, redo comment
+
+ public:
+ OCommentUndoAction(TranslateId pCommentID) { m_strComment = DBA_RES(pCommentID); }
+
+ virtual OUString GetComment() const override { return m_strComment; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/HtmlReader.hxx b/dbaccess/source/ui/inc/HtmlReader.hxx
new file mode 100644
index 000000000..5c4ddde13
--- /dev/null
+++ b/dbaccess/source/ui/inc/HtmlReader.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "DExport.hxx"
+#include <svtools/parhtml.hxx>
+#include <editeng/svxenum.hxx>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+class SvStream;
+
+namespace dbaui
+{
+ class OHTMLReader final : public HTMLParser, public ODatabaseExport
+ {
+ OUString m_sCurrent;
+ sal_Int32 m_nTableCount;
+ sal_Int16 m_nColumnWidth; ///< maximum column width
+
+ virtual void NextToken( HtmlTokenId nToken ) override; // base class
+ bool CreateTable( HtmlTokenId nToken );
+ virtual TypeSelectionPageFactory
+ getTypeSelectionPageFactory() override;
+
+ void TableDataOn(SvxCellHorJustify& eVal);
+ void TableFontOn(css::awt::FontDescriptor& _rFont, Color &_rTextColor);
+ sal_Int16 GetWidthPixel( const HTMLOption& rOption );
+ void setTextEncoding();
+ void fetchOptions();
+ virtual ~OHTMLReader() override;
+
+ public:
+ OHTMLReader(SvStream& rIn,
+ const SharedConnection& _rxConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ // required for automatic type recognition
+ OHTMLReader(SvStream& rIn,
+ sal_Int32 nRows,
+ TPositions&& _rColumnPositions,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const TColumnVector* rList,
+ const OTypeInfoMap* _pInfoMap,
+ bool _bAutoIncrementEnabled);
+
+ virtual SvParserState CallParser() override;// base class
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/IClipBoardTest.hxx b/dbaccess/source/ui/inc/IClipBoardTest.hxx
new file mode 100644
index 000000000..e3eb04962
--- /dev/null
+++ b/dbaccess/source/ui/inc/IClipBoardTest.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <sal/types.h>
+
+namespace dbaui
+{
+ class SAL_NO_VTABLE IClipboardTest
+ {
+ public:
+ virtual bool isCutAllowed() = 0;
+ virtual bool isCopyAllowed() = 0;
+ virtual bool isPasteAllowed() = 0;
+
+ virtual void copy() = 0;
+ virtual void cut() = 0;
+ virtual void paste() = 0;
+
+ protected:
+ ~IClipboardTest() {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/IItemSetHelper.hxx b/dbaccess/source/ui/inc/IItemSetHelper.hxx
new file mode 100644
index 000000000..cdc1026ea
--- /dev/null
+++ b/dbaccess/source/ui/inc/IItemSetHelper.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace com::sun::star {
+ namespace sdbc {
+ class XConnection;
+ class XDriver;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+}
+
+class SfxItemSet;
+namespace dbaui
+{
+ class SAL_NO_VTABLE IItemSetHelper
+ {
+ public:
+ virtual const SfxItemSet* getOutputSet() const = 0;
+ virtual SfxItemSet* getWriteOutputSet() = 0;
+
+ protected:
+ ~IItemSetHelper() {}
+ };
+
+ class SAL_NO_VTABLE IDatabaseSettingsDialog
+ {
+ public:
+ virtual css::uno::Reference< css::uno::XComponentContext > getORB() const = 0;
+ virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() = 0;
+ virtual css::uno::Reference< css::sdbc::XDriver > getDriver() = 0;
+ virtual OUString getDatasourceType(const SfxItemSet& _rSet) const = 0;
+ virtual void clearPassword() = 0;
+ virtual void saveDatasource() = 0;
+ virtual void setTitle(const OUString& _sTitle) = 0;
+
+ /** enables or disables the user's possibility to confirm the settings
+
+ In a wizard, disabling this will usually disable the "Finish" button.
+ In a normal tab dialog, this will usually disable the "OK" button.
+ */
+ virtual void enableConfirmSettings( bool _bEnable ) = 0;
+
+ protected:
+ ~IDatabaseSettingsDialog() {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/IUpdateHelper.hxx b/dbaccess/source/ui/inc/IUpdateHelper.hxx
new file mode 100644
index 000000000..e6ef24a96
--- /dev/null
+++ b/dbaccess/source/ui/inc/IUpdateHelper.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+
+namespace dbaui
+{
+ class SAL_NO_VTABLE IUpdateHelper
+ {
+ public:
+ virtual void updateString(sal_Int32 _nPos, const OUString& _sValue) = 0;
+ virtual void updateDouble(sal_Int32 _nPos,const double& _nValue) = 0;
+ virtual void updateInt(sal_Int32 _nPos, sal_Int32 _nValue) = 0;
+ virtual void updateNull(sal_Int32 _nPos, ::sal_Int32 sqlType) = 0;
+ virtual void updateDate(sal_Int32 _nPos,const css::util::Date& _nValue) = 0;
+ virtual void updateTime(sal_Int32 _nPos,const css::util::Time& _nValue) = 0;
+ virtual void updateTimestamp(sal_Int32 _nPos,const css::util::DateTime& _nValue) = 0;
+ virtual void insertRow() = 0;
+
+ protected:
+ ~IUpdateHelper() {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/JAccess.hxx b/dbaccess/source/ui/inc/JAccess.hxx
new file mode 100644
index 000000000..3a630faa2
--- /dev/null
+++ b/dbaccess/source/ui/inc/JAccess.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "JoinTableView.hxx"
+#include <toolkit/awt/vclxaccessiblecomponent.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace dbaui
+{
+ class OJoinTableView;
+ typedef ::cppu::ImplHelper1< css::accessibility::XAccessible
+ > OJoinDesignViewAccess_BASE;
+ /** the class OJoinDesignViewAccess represents the accessible object for join views
+ like the QueryDesign and the RelationDesign
+ */
+ class OJoinDesignViewAccess : public VCLXAccessibleComponent, public OJoinDesignViewAccess_BASE
+ {
+ VclPtr<OJoinTableView> m_pTableView; // the window which I should give accessibility to
+
+ public:
+ /** OJoinDesignViewAccess needs a valid view
+ */
+ OJoinDesignViewAccess( OJoinTableView* _pTableView);
+
+ // XInterface
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ // XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+
+ void notifyAccessibleEvent(
+ const sal_Int16 _nEventId,
+ const css::uno::Any& _rOldValue,
+ const css::uno::Any& _rNewValue
+ )
+ {
+ NotifyAccessibleEvent(_nEventId,_rOldValue,_rNewValue);
+ }
+
+ void clearTableView();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/JoinController.hxx b/dbaccess/source/ui/inc/JoinController.hxx
new file mode 100644
index 000000000..941082322
--- /dev/null
+++ b/dbaccess/source/ui/inc/JoinController.hxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "singledoccontroller.hxx"
+#include "JoinTableView.hxx"
+#include "JoinDesignView.hxx"
+#include "TableConnectionData.hxx"
+#include "TableWindowData.hxx"
+#include <memory>
+
+namespace comphelper
+{
+ class NamedValueCollection;
+}
+
+namespace dbaui
+{
+ class OAddTableDlg;
+ class AddTableDialogContext;
+ class OTableWindow;
+ typedef OSingleDocumentController OJoinController_BASE;
+
+ class OJoinController : public OJoinController_BASE
+ {
+ protected:
+ TTableConnectionData m_vTableConnectionData;
+ TTableWindowData m_vTableData;
+
+ ::dbtools::SQLExceptionInfo m_aExceptionInfo;
+
+ std::shared_ptr<OAddTableDlg> m_xAddTableDialog;
+ std::unique_ptr< AddTableDialogContext > m_pDialogContext;
+ Point m_aMinimumTableViewSize;
+
+ // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot.
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ // execute a feature
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ /** loads the information for the windows.
+ @param i_rViewSettings
+ The properties which comes from the layout information.
+ */
+ void loadTableWindows( const ::comphelper::NamedValueCollection& i_rViewSettings );
+
+ /** loads the information for one window.
+ @param _rTable
+ The properties which comes from the layout information.
+ */
+ void loadTableWindow( const ::comphelper::NamedValueCollection& i_rTableWindowSettings );
+
+ /** saves the TableWindows structure in a sequence of property values
+ @param _rViewProps
+ Contains the new sequence.
+ */
+ void saveTableWindows( ::comphelper::NamedValueCollection& o_rViewSettings ) const;
+
+ virtual ~OJoinController() override;
+ public:
+ OJoinController(const css::uno::Reference< css::uno::XComponentContext >& _rM);
+
+ // attribute access
+ TTableWindowData& getTableWindowData() { return m_vTableData; }
+ TTableConnectionData& getTableConnectionData() { return m_vTableConnectionData;}
+ OAddTableDlg* getAddTableDialog()const { return m_xAddTableDialog.get(); }
+
+ // OSingleDocumentController overridables
+ virtual void reconnect( bool _bUI ) override;
+ virtual void impl_onModifyChanged() override;
+
+ // own overridables
+ /** determines whether or not it's allowed for database views to participate in the game
+ */
+ virtual bool allowViews() const = 0;
+
+ /** determines whether or not it's allowed for queries to participate in the game
+ */
+ virtual bool allowQueries() const = 0;
+
+ /** provides access to the OJoinDesignView belonging to the controller, which might
+ or might not be the direct view (getView)
+ */
+ virtual OJoinDesignView* getJoinView();
+
+ /** erase the data in the data vector
+ @param _pData
+ the data which should be erased
+ */
+ void removeConnectionData(const TTableConnectionData::value_type& _pData);
+
+ void SaveTabWinsPosSize( OJoinTableView::OTableWindowMap* pTabWinList, tools::Long nOffsetX, tools::Long nOffsetY );
+
+ static void SaveTabWinPosSize(OTableWindow const * pTabWin, tools::Long nOffsetX, tools::Long nOffsetY);
+
+ // UNO interface overridables
+ // XEventListener
+ using OJoinController_BASE::disposing;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL disposing() override;
+ // css::frame::XController
+ virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override;
+
+ // misc
+ /** only defines a method to save a SQLException in d&d methods to show the error at a later state
+ set the internal member m_aExceptionInfo to _rInfo
+ */
+ void setErrorOccurred(const ::dbtools::SQLExceptionInfo& _rInfo)
+ {
+ m_aExceptionInfo = _rInfo;
+ }
+ /**
+ just returns the internal member and clears it
+ */
+ ::dbtools::SQLExceptionInfo clearOccurredError()
+ {
+ ::dbtools::SQLExceptionInfo aInfo = m_aExceptionInfo;
+ m_aExceptionInfo = ::dbtools::SQLExceptionInfo();
+ return aInfo;
+ }
+
+ // show the dialog
+ void runDialogAsync();
+
+ protected:
+ TTableWindowData::value_type createTableWindowData(const OUString& _sComposedName,const OUString& _sTableName,const OUString& _sWindowName);
+ // ask the user if the design should be saved when it is modified
+ virtual short saveModified() = 0;
+ // called when the original state should be reset (first time load)
+ virtual void reset() = 0;
+ virtual void describeSupportedFeatures() override;
+
+ AddTableDialogContext& impl_getDialogContext() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/JoinDesignView.hxx b/dbaccess/source/ui/inc/JoinDesignView.hxx
new file mode 100644
index 000000000..f4871e9df
--- /dev/null
+++ b/dbaccess/source/ui/inc/JoinDesignView.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <dbaccess/dataview.hxx>
+
+class Splitter;
+
+namespace dbaui
+{
+ class OJoinController;
+ class OScrollWindowHelper;
+ class OJoinTableView;
+ class OTableWindow;
+
+ class OJoinDesignView : public ODataView
+ {
+ protected:
+ VclPtr<OScrollWindowHelper> m_pScrollWindow; // contains only the scrollbars
+ VclPtr<OJoinTableView> m_pTableView; // presents the upper window
+ OJoinController& m_rController;
+
+ public:
+ OJoinDesignView(vcl::Window* pParent,
+ OJoinController& _rController,
+ const css::uno::Reference< css::uno::XComponentContext >& );
+ virtual ~OJoinDesignView() override;
+ virtual void dispose() override;
+
+ // set the view readonly or not
+ virtual void setReadOnly(bool _bReadOnly);
+ // set the statement for representation
+ /// late construction
+ virtual void Construct() override;
+ virtual void initialize() override;
+ virtual void KeyInput( const KeyEvent& rEvt ) override;
+
+ void SaveTabWinUIConfig(OTableWindow const * pWin);
+ OJoinController& getController() const { return m_rController; }
+ // called when fields are deleted
+
+ OJoinTableView* getTableView() const { return m_pTableView; }
+ OScrollWindowHelper* getScrollHelper() const { return m_pScrollWindow; }
+ protected:
+ // return the Rectangle where I can paint myself
+ virtual void resizeDocumentView(tools::Rectangle& rRect) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/JoinExchange.hxx b/dbaccess/source/ui/inc/JoinExchange.hxx
new file mode 100644
index 000000000..7401ec886
--- /dev/null
+++ b/dbaccess/source/ui/inc/JoinExchange.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TableWindowListBox.hxx"
+
+#include <vcl/transfer.hxx>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaui
+{
+ // OJoinExchObj: Additional data to create Joins in the JoinShell
+
+ typedef ::cppu::ImplHelper1< css::lang::XUnoTunnel > OJoinExchObj_Base;
+ class OJoinExchObj final : public TransferDataContainer, public OJoinExchObj_Base
+ {
+ bool m_bFirstEntry;
+
+ OJoinExchangeData m_jxdSourceDescription;
+
+ virtual ~OJoinExchObj() override;
+
+ public:
+ OJoinExchObj();
+ void setDescriptors(const OJoinExchangeData& jxdSource, bool _bFirstEntry);
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+ // XUnoTunnel
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& _rIdentifier ) override;
+
+ static OJoinExchangeData GetSourceDescription(const css::uno::Reference< css::datatransfer::XTransferable >& _rxObject);
+ static bool isFormatAvailable( const DataFlavorExVector& _rFormats ,SotClipboardFormatId _nSlotID=SotClipboardFormatId::SBA_JOIN);
+
+ private:
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/JoinTableView.hxx b/dbaccess/source/ui/inc/JoinTableView.hxx
new file mode 100644
index 000000000..80de958ea
--- /dev/null
+++ b/dbaccess/source/ui/inc/JoinTableView.hxx
@@ -0,0 +1,325 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/window.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/transfer.hxx>
+
+#include "callbacks.hxx"
+#include "TableConnectionData.hxx"
+#include "TableWindowData.hxx"
+
+#include <map>
+#include <vector>
+
+struct AcceptDropEvent;
+struct ExecuteDropEvent;
+class SfxUndoAction;
+
+namespace dbaui
+{
+ class OTableConnection;
+ class OTableWindow;
+ struct OJoinExchangeData;
+ class OJoinDesignView;
+ class OTableWindowData;
+ class OJoinDesignViewAccess;
+
+ // this class contains only the scrollbars to avoid that
+ // the tablewindows clip the scrollbars
+ class OJoinTableView;
+ class OScrollWindowHelper : public vcl::Window
+ {
+ VclPtr<ScrollBar> m_aHScrollBar;
+ VclPtr<ScrollBar> m_aVScrollBar;
+ VclPtr<vcl::Window> m_pCornerWindow;
+ VclPtr<OJoinTableView> m_pTableView;
+
+ protected:
+ virtual void Resize() override;
+
+ public:
+ OScrollWindowHelper( vcl::Window* pParent);
+ virtual ~OScrollWindowHelper() override;
+ virtual void dispose() override;
+
+ void setTableView(OJoinTableView* _pTableView);
+
+ void resetRange(const Point& _aSize);
+
+ // own methods
+ ScrollBar& GetHScrollBar() { return *m_aHScrollBar; }
+ ScrollBar& GetVScrollBar() { return *m_aVScrollBar; }
+ };
+
+
+ class OJoinTableView : public vcl::Window,
+ public IDragTransferableListener,
+ public DropTargetHelper
+ {
+ friend class OJoinMoveTabWinUndoAct;
+
+ public:
+ typedef std::map<OUString, VclPtr<OTableWindow> > OTableWindowMap;
+
+ private:
+ OTableWindowMap m_aTableMap;
+ std::vector<VclPtr<OTableConnection> > m_vTableConnection;
+
+ Idle m_aDragScrollIdle;
+ tools::Rectangle m_aDragRect;
+ tools::Rectangle m_aSizingRect;
+ Point m_aDragOffset;
+ Point m_aScrollOffset;
+ Point m_ptPrevDraggingPos;
+ Size m_aOutputSize;
+
+
+ VclPtr<OTableWindow> m_pDragWin;
+ VclPtr<OTableWindow> m_pSizingWin;
+ VclPtr<OTableConnection> m_pSelectedConn;
+
+
+ DECL_LINK(OnDragScrollTimer, Timer*, void);
+
+ protected:
+ VclPtr<OTableWindow> m_pLastFocusTabWin;
+ VclPtr<OJoinDesignView> m_pView;
+ rtl::Reference<OJoinDesignViewAccess> m_pAccessible;
+
+ public:
+ OJoinTableView( vcl::Window* pParent, OJoinDesignView* pView );
+ virtual ~OJoinTableView() override;
+ virtual void dispose() override;
+
+ // window override
+ virtual void StateChanged( StateChangedType nStateChange ) override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+ virtual void KeyInput( const KeyEvent& rEvt ) override;
+ // Accessibility
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ // own methods
+ ScrollBar& GetHScrollBar() { return static_cast<OScrollWindowHelper*>(GetParent())->GetHScrollBar(); }
+ ScrollBar& GetVScrollBar() { return static_cast<OScrollWindowHelper*>(GetParent())->GetVScrollBar(); }
+ DECL_LINK( ScrollHdl, ScrollBar*, void );
+
+ void DrawConnections(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect);
+ void InvalidateConnections();
+
+ void BeginChildMove( OTableWindow* pTabWin, const Point& rMousePos );
+ void BeginChildSizing( OTableWindow* pTabWin, PointerStyle nPointer );
+
+ void NotifyTitleClicked( OTableWindow* pTabWin, const Point& rMousePos );
+
+ virtual void AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool bNewTable = false);
+ virtual void RemoveTabWin( OTableWindow* pTabWin );
+
+ // hide all TabWins (does NOT delete them; they are put in an UNDO action)
+ void HideTabWins();
+
+ virtual void AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) = 0;
+
+ /** RemoveConnection allows to remove connections from join table view
+
+ it implies that the same as addConnection
+
+ @param rConnection the connection which should be removed
+ @param bDelete when true then the connection will be deleted
+
+ @return an iterator to next valid connection, so it can be used in any loop
+ */
+ virtual bool RemoveConnection(VclPtr<OTableConnection>& rConnection, bool bDelete);
+
+ /** allows to add new connections to join table view
+
+ it implies an invalidation of the features ID_BROWSER_ADDTABLE and
+ SID_RELATION_ADD_RELATION also the modified flag will be set to true
+
+ @param _pConnection the connection which should be added
+ @param _bAddData when true then the data should also be appended
+ */
+ void addConnection(OTableConnection* _pConnection,bool _bAddData = true);
+
+ bool ScrollPane( tools::Long nDelta, bool bHoriz, bool bPaintScrollBars );
+ sal_uLong GetTabWinCount() const;
+ const Point& GetScrollOffset() const { return m_aScrollOffset; }
+
+ OJoinDesignView* getDesignView() const { return m_pView; }
+ OTableWindow* GetTabWindow( const OUString& rName );
+
+ VclPtr<OTableConnection>& GetSelectedConn() { return m_pSelectedConn; }
+ /** @note NULL is explicitly allowed (then no-op) */
+ void DeselectConn(OTableConnection* pConn);
+ void SelectConn(OTableConnection* pConn);
+
+ OTableWindowMap& GetTabWinMap() { return m_aTableMap; }
+
+ /** gives a read only access to the connection vector
+ */
+ const std::vector<VclPtr<OTableConnection> >& getTableConnections() const { return m_vTableConnection; }
+
+ bool ExistsAConn(const OTableWindow* pFromWin) const;
+
+ /** search for all connections of a table
+
+ @param _pFromWin the table for which connections should be found
+ @return an iterator which can be used to travel all connections of the table
+ */
+ std::vector<VclPtr<OTableConnection> >::const_iterator getTableConnections(const OTableWindow* _pFromWin) const;
+
+ /** how many connection belongs to single table
+
+ @param _pFromWin the table for which connections should be found
+ @return the count of connections which belongs to this table
+ */
+ sal_Int32 getConnectionCount(const OTableWindow* _pFromWin) const;
+
+ OTableConnection* GetTabConn(const OTableWindow* pLhs,const OTableWindow* pRhs,bool _bSuppressCrossOrNaturalJoin = false) const;
+
+ /** clear the window map and connection vector without destroying it
+
+ that means that the data of the windows and connection will be
+ untouched
+ */
+ void clearLayoutInformation();
+
+ /** set the focus to that tab win which most recently had it
+ (or to the first available one) **/
+ void GrabTabWinFocus();
+
+ /** take all WinData and ConnData from the document and create the
+ corresponding Wins and Conns */
+ virtual void ReSync() { }
+
+ /** Hard deletion
+
+ That means that all Conns and Wins are deleted from their respective
+ lists and the corresponding Data removed from the document */
+ virtual void ClearAll();
+
+ /** @note used by AddTabDlg to see if more tables can be added */
+ virtual bool IsAddAllowed();
+ virtual bool PreNotify(NotifyEvent& rNEvt) override;
+
+ // DnD stuff
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ /** @note can be used for special ui handling after d&d */
+ virtual void lookForUiActivities();
+
+ /** Hook that is called after moving/resizing TabWins
+
+ The position is 'virtual': the container has a virtual area of
+ which only a part - changeable by scroll bar - is visible.
+ Therefore: ptOldPosition is always positive, even if it represents
+ a point with a negative physical ordinate above the visible area
+
+ @note The standard implementation just passes the new data to the
+ Wins
+ */
+ void TabWinMoved(OTableWindow* ptWhich, const Point& ptOldPosition);
+
+ void TabWinSized(OTableWindow* ptWhich, const Point& ptOldPosition, const Size& szOldSize);
+
+ void modified();
+
+ /** check if the given window is visible.
+
+ @param _rPoint The Point to check
+ @param _rSize The Size to be check as well
+ @return true if the area is visible, false otherwise
+ */
+ bool isMovementAllowed(const Point& _rPoint,const Size& _rSize);
+
+ const Size& getRealOutputSize() const { return m_aOutputSize; }
+
+ virtual void EnsureVisible(const OTableWindow* _pWin);
+ void EnsureVisible(const Point& _rPoint,const Size& _rSize);
+
+ TTableWindowData::value_type createTableWindowData(const OUString& _rComposedName
+ ,const OUString& _sTableName
+ ,const OUString& _rWinName);
+
+ protected:
+ virtual void MouseButtonUp( const MouseEvent& rEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rEvt ) override;
+ virtual void Tracking( const TrackingEvent& rTEvt ) override;
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+ virtual void ConnDoubleClicked(VclPtr<OTableConnection>& rConnection);
+ void SetDefaultTabWinPosSize( OTableWindow* pTabWin );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+
+ virtual void Resize() override;
+
+ virtual void dragFinished( ) override;
+ /// @note here the physical position (that can be changed while
+ /// resizing) is used, as no scrolling can take place while resizing
+ virtual void Command(const CommandEvent& rEvt) override;
+
+ virtual std::shared_ptr<OTableWindowData> CreateImpl(const OUString& _rComposedName
+ ,const OUString& _sTableName
+ ,const OUString& _rWinName);
+
+ /** factory method to create table windows
+
+ @param _pData The data corresponding to the window.
+ @return The new TableWindow
+ */
+ virtual VclPtr<OTableWindow> createWindow(const TTableWindowData::value_type& _pData) = 0;
+
+ /** determines whether the classes Init method should accept a query
+ name, or only table names */
+ virtual bool allowQueries() const;
+
+ /** called when init fails at the tablewindowdata because the m_xTable
+ object could not provide columns, but no exception was thrown.
+ Expected to throw. */
+ virtual void onNoColumns_throw();
+
+ virtual bool suppressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const;
+
+ private:
+ void InitColors();
+ void ScrollWhileDragging();
+
+ /** opens the context menu to delete a connection
+ @param _aPos the position where the popup menu should appear
+ @param _pSelConnection the connection which should be deleted
+ */
+ void executePopup(const Point& _aPos, VclPtr<OTableConnection>& rSelConnection);
+
+ /** invalidates this window without children and set the controller
+ modified
+ @param _pAction a possible undo action to add at the controller
+ */
+ void invalidateAndModify(std::unique_ptr<SfxUndoAction> _pAction);
+
+ private:
+ using Window::Scroll;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/QEnumTypes.hxx b/dbaccess/source/ui/inc/QEnumTypes.hxx
new file mode 100644
index 000000000..b889870c9
--- /dev/null
+++ b/dbaccess/source/ui/inc/QEnumTypes.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+namespace dbaui
+{
+ enum EOrderDir
+ {
+ ORDER_NONE=0,
+ ORDER_ASC,
+ ORDER_DESC
+ };
+
+ enum EFunctionType
+ {
+ FKT_NONE =0x00000000,
+ FKT_OTHER =0x00000001,
+ FKT_AGGREGATE =0x00000002,
+ FKT_CONDITION =0x00000004,
+ FKT_NUMERIC =0x00000008
+ // if this function type is set, it is either EXISTS or UNIQUE,
+ // the FieldName contains the complete statement
+ };
+
+ enum EConnectionSide
+ {
+ JTCS_FROM=0,
+ JTCS_TO
+ };
+
+ enum ETableFieldType
+ {
+ TAB_NORMAL_FIELD=0,
+ TAB_PRIMARY_FIELD
+ };
+
+ enum EJoinType
+ {
+ FULL_JOIN=0,
+ LEFT_JOIN,
+ RIGHT_JOIN,
+ CROSS_JOIN,
+ INNER_JOIN
+ };
+
+ enum EControlType
+ {
+ tpDefault = 0,
+ tpRequired,
+ tpTextLen,
+ tpNumType,
+ tpLength,
+ tpScale,
+ tpFormat,
+ tpAutoIncrement,
+ tpBoolDefault,
+ tpColumnName,
+ tpType,
+ tpAutoIncrementValue
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/QueryDesignView.hxx b/dbaccess/source/ui/inc/QueryDesignView.hxx
new file mode 100644
index 000000000..efef444e8
--- /dev/null
+++ b/dbaccess/source/ui/inc/QueryDesignView.hxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "JoinDesignView.hxx"
+#include <vcl/split.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "querycontroller.hxx"
+
+namespace connectivity
+{
+ class OSQLParseNode;
+}
+namespace weld
+{
+ class ComboBox;
+}
+namespace dbaui
+{
+ enum SqlParseError
+ {
+ eIllegalJoin,
+ eStatementTooLong,
+ eNoConnection,
+ eNoSelectStatement,
+ eStatementTooComplex,
+ eNoColumnInLike,
+ eColumnNotFound,
+ eNativeMode,
+ eTooManyTables,
+ eTooManyColumns,
+ eIllegalJoinCondition,
+ eOk
+ };
+
+ class OSelectionBrowseBox;
+ class OQueryContainerWindow;
+ class OQueryController;
+
+ class OQueryDesignView : public OJoinDesignView
+ {
+ enum ChildFocusState
+ {
+ SELECTION,
+ TABLEVIEW,
+ NONE
+ };
+
+ VclPtr<Splitter> m_aSplitter;
+
+ css::lang::Locale m_aLocale;
+ OUString m_sDecimalSep;
+
+ VclPtr<OSelectionBrowseBox> m_pSelectionBox; // presents the lower window
+ ChildFocusState m_eChildFocus;
+ bool m_bInSplitHandler;
+
+ public:
+ OQueryDesignView(OQueryContainerWindow* pParent, OQueryController& _rController, const css::uno::Reference< css::uno::XComponentContext >& );
+ virtual ~OQueryDesignView() override;
+ virtual void dispose() override;
+
+ bool isCutAllowed() const;
+ bool isPasteAllowed() const;
+ bool isCopyAllowed() const;
+ void copy();
+ void cut();
+ void paste();
+ // clears the whole query
+ void clear();
+ // set the view readonly or not
+ virtual void setReadOnly(bool _bReadOnly) override;
+ // check if the statement is correct when not returning false
+ bool checkStatement();
+ // returns the current sql statement
+ OUString getStatement();
+ /// late construction
+ virtual void Construct() override;
+ virtual void initialize() override;
+ // Window overrides
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void GetFocus() override;
+
+ bool isSlotEnabled(sal_Int32 _nSlotId);
+ void setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable);
+ void setNoneVisibleRow(sal_Int32 _nRows);
+
+ const css::lang::Locale& getLocale() const { return m_aLocale;}
+ const OUString& getDecimalSeparator() const { return m_sDecimalSep;}
+
+ SqlParseError InsertField( const OTableFieldDescRef& rInfo, bool bActivate = true);
+ bool HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const;
+ // called when a table from tabview was deleted
+ void TableDeleted(const OUString& rAliasName);
+
+ sal_Int32 getColWidth( sal_uInt16 _nColPos) const;
+ void fillValidFields(std::u16string_view strTableName, weld::ComboBox& rFieldList);
+
+ void SaveUIConfig();
+ void stopTimer();
+ void startTimer();
+ void reset();
+
+ /** initializes the view from the current parser / parse iterator of the controller
+
+ @param _pErrorInfo
+ When not <NULL/>, the instance pointed to by this parameter takes the error
+ which happened during the initialization.
+ If it is not <NULL/>, then any such error will be displayed, using the controller's
+ showError method.
+
+ @return <TRUE/> if and only if the initialization was successful
+ */
+ bool initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo );
+
+ void initByFieldDescriptions(
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rFieldDescriptions
+ );
+
+ std::unique_ptr<::connectivity::OSQLParseNode> getPredicateTreeFromEntry( const OTableFieldDescRef& pEntry,
+ const OUString& _sCriteria,
+ OUString& _rsErrorMessage,
+ css::uno::Reference< css::beans::XPropertySet>& _rxColumn) const;
+
+ void fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode
+ ,const OUString& sFunctionTerm
+ ,OTableFieldDescRef& aInfo);
+ protected:
+ // return the Rectangle where I can paint myself
+ virtual void resizeDocumentView(tools::Rectangle& rRect) override;
+ DECL_LINK( SplitHdl, Splitter*, void );
+
+ private:
+ using OJoinDesignView::SaveTabWinUIConfig;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx b/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx
new file mode 100644
index 000000000..2d8bb80dc
--- /dev/null
+++ b/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+
+/**
+ * Dialog to set such properties of a query as distinct values and limit
+ * It can be opened from Edit menu in Query Design View
+ */
+class QueryPropertiesDialog : public weld::GenericDialogController
+{
+
+public:
+
+ QueryPropertiesDialog(
+ weld::Window* pParent, const bool bDistinct, const sal_Int64 nLimit );
+ virtual ~QueryPropertiesDialog() override;
+ bool getDistinct() const
+ {
+ return m_xRB_Distinct->get_active();
+ }
+
+ sal_Int64 getLimit() const;
+
+private:
+
+ std::unique_ptr<weld::RadioButton> m_xRB_Distinct;
+ std::unique_ptr<weld::RadioButton> m_xRB_NonDistinct;
+ std::unique_ptr<weld::ComboBox> m_xLB_Limit;
+};
+
+} ///dbaui namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/QueryTableView.hxx b/dbaccess/source/ui/inc/QueryTableView.hxx
new file mode 100644
index 000000000..26133d2cc
--- /dev/null
+++ b/dbaccess/source/ui/inc/QueryTableView.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "JoinTableView.hxx"
+#include "TableFieldDescription.hxx"
+
+namespace dbaui
+{
+ class OQueryTabWinUndoAct;
+ class OQueryTableConnection;
+ class OQueryTableWindow;
+ class OQueryDesignView;
+
+ class OQueryTableView : public OJoinTableView
+ {
+ protected:
+ virtual void ConnDoubleClicked(VclPtr<OTableConnection>& rConnection) override;
+
+ virtual VclPtr<OTableWindow> createWindow(const TTableWindowData::value_type& _pData) override;
+
+ /** called when init fails at the tablewindowdata because the m_xTable
+ object could not provide columns, but no exception was thrown.
+ Expected to throw. */
+ virtual void onNoColumns_throw() override;
+
+ virtual bool suppressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const override;
+
+ public:
+ OQueryTableView(vcl::Window* pParent,OQueryDesignView* pView);
+
+ /// base class overwritten: create and delete windows
+ /// (not really delete, as it becomes an UndoAction)
+ bool ContainsTabWin(const OTableWindow& rTabWin); // #i122589# Allow to check if OTableWindow is registered
+ virtual void AddTabWin( const OUString& _rTableName, const OUString& _rAliasName, bool bNewTable = false ) override;
+ virtual void RemoveTabWin(OTableWindow* pTabWin) override;
+
+ /// AddTabWin, setting an alias
+ void AddTabWin(const OUString& strDatabase, const OUString& strTableName, const OUString& strAlias, bool bNewTable);
+ /// search TabWin
+ OQueryTableWindow* FindTable(const OUString& rAliasName);
+ bool FindTableFromField(const OUString& rFieldName, OTableFieldDescRef const & rInfo, sal_uInt16& rCnt);
+
+ /// base class overwritten: create and delete Connections
+ virtual void AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) override;
+
+ virtual bool RemoveConnection(VclPtr<OTableConnection>& rConn, bool bDelete) override;
+
+ // transfer of connections from and to UndoAction
+
+ /// Inserting a Connection the structure
+ void GetConnection(OQueryTableConnection* pConn);
+ /** Removing a Connection from the structure
+
+ This results effectively in complete reset of request form, as all
+ windows are hidden, as are all Connections to these windows and all
+ request columns based on those tables */
+ void DropConnection(VclPtr<OQueryTableConnection> const & rConn);
+
+ // show and hide TabWin (NOT create or delete)
+ bool ShowTabWin(OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction, bool _bAppend);
+ void HideTabWin(OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction);
+
+ /// ensure visibility of TabWins (+ and invalidate connections)
+ virtual void EnsureVisible(const OTableWindow* _pWin) override;
+
+ /// how many tables with a certain alias do I already have?
+ sal_Int32 CountTableAlias(const OUString& rName, sal_Int32& rMax);
+
+ /// insert field (simply passed to parents)
+ void InsertField(const OTableFieldDescRef& rInfo);
+
+ /// rebuild everything (TabWins, Connections)
+ /// (PRECONDITION: ClearAll was called previously)
+ virtual void ReSync() override;
+
+ /// delete everything hard (TabWins, Connections), without any notifications
+ virtual void ClearAll() override;
+
+ // used by AddTabDlg to see if tables can still be added
+ //virtual sal_Bool IsAddAllowed();
+
+ /// announce new Connection and insert it, if not existing yet
+ void NotifyTabConnection(const OQueryTableConnection& rNewConn, bool _bCreateUndoAction = true);
+
+ bool ExistsAVisitedConn(const OQueryTableWindow* pFrom) const;
+
+ virtual std::shared_ptr<OTableWindowData> CreateImpl(const OUString& _rComposedName
+ ,const OUString& _sTableName
+ ,const OUString& _rWinName) override;
+
+ /** opens the join dialog and allows to create a new join connection */
+ void createNewConnection();
+
+ private:
+ using OJoinTableView::EnsureVisible;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/QueryTextView.hxx b/dbaccess/source/ui/inc/QueryTextView.hxx
new file mode 100644
index 000000000..33f66342b
--- /dev/null
+++ b/dbaccess/source/ui/inc/QueryTextView.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+#include "querycontainerwindow.hxx"
+#include "sqledit.hxx"
+
+namespace dbaui
+{
+ class OQueryTextView final : public InterimItemWindow
+ {
+ friend class OQueryViewSwitch;
+
+ OQueryController& m_rController;
+ std::unique_ptr<SQLEditView> m_xSQL;
+ std::unique_ptr<weld::CustomWeld> m_xSQLEd;
+
+ Timer m_timerUndoActionCreation;
+ OUString m_strOrigText; // is restored on undo
+ Timer m_timerInvalidate;
+ bool m_bStopTimer;
+
+ DECL_LINK(OnUndoActionTimer, Timer*, void);
+ DECL_LINK(OnInvalidateTimer, Timer*, void);
+ DECL_LINK(ModifyHdl, LinkParamNone*, void);
+
+ public:
+ OQueryTextView(OQueryContainerWindow* pParent, OQueryController& rController);
+ virtual ~OQueryTextView() override;
+ virtual void dispose() override;
+
+ void SetSQLText(const OUString& rNewText);
+ OUString GetSQLText() const;
+
+ virtual void GetFocus() override;
+
+ bool isCutAllowed() const;
+ void copy();
+ void cut();
+ void paste();
+ // clears the whole query
+ void clear();
+ // set the statement for representation
+ void setStatement(const OUString& _rsStatement);
+ OUString getStatement() const;
+
+ void stopTimer();
+ void startTimer();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/QueryViewSwitch.hxx b/dbaccess/source/ui/inc/QueryViewSwitch.hxx
new file mode 100644
index 000000000..0f17d40bd
--- /dev/null
+++ b/dbaccess/source/ui/inc/QueryViewSwitch.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <tools/gen.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace dbtools
+{
+ class SQLExceptionInfo;
+}
+
+namespace dbaui
+{
+ class OQueryDesignView;
+ class OQueryTextView;
+ class OAddTableDlg;
+ class OQueryContainerWindow;
+ class OQueryController;
+
+ class OQueryViewSwitch final
+ {
+ VclPtr<OQueryDesignView> m_pDesignView;
+ VclPtr<OQueryTextView> m_pTextView;
+ bool m_bAddTableDialogWasVisible; // true if so
+ public:
+ OQueryViewSwitch(OQueryContainerWindow* pParent, OQueryController& _rController,const css::uno::Reference< css::uno::XComponentContext >& );
+ ~OQueryViewSwitch();
+
+ bool isCutAllowed() const;
+ bool isPasteAllowed() const;
+ bool isCopyAllowed() const;
+ void copy();
+ void cut();
+ void paste();
+ // clears the whole query
+ void clear();
+ // check if the statement is correct when not returning false
+ bool checkStatement();
+ // set the statement for representation
+ void setStatement(const OUString& _rsStatement);
+ // returns the current sql statement
+ OUString getStatement();
+ /// late construction
+ void Construct();
+ void initialize();
+ /** show the text or the design view
+ @return
+ <TRUE/> if and only if the view could be successfully, switched, <FALSE/> otherwise
+ (In the latter case, the controller will issue another switchView call to restore the
+ old state)
+ */
+ bool switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo );
+ void forceInitialView();
+ bool isSlotEnabled(sal_Int32 _nSlotId);
+ void setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable);
+ void setNoneVisibleRow(sal_Int32 _nRows);
+ void SaveUIConfig();
+ void reset();
+ void GrabFocus();
+
+ // returns the add table dialog from the design view
+ OAddTableDlg* getAddTableDialog();
+
+ OQueryDesignView* getDesignView() const { return m_pDesignView; }
+ OQueryContainerWindow* getContainer() const;
+
+ void SetPosSizePixel( Point _rPt,Size _rSize);
+ css::uno::Reference< css::uno::XComponentContext > const & getORB() const;
+
+ private:
+ void impl_forceSQLView();
+ bool impl_postViewSwitch( const bool i_bGraphicalDesign, const bool i_bSuccess );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RTableConnectionData.hxx b/dbaccess/source/ui/inc/RTableConnectionData.hxx
new file mode 100644
index 000000000..0dd40e2fa
--- /dev/null
+++ b/dbaccess/source/ui/inc/RTableConnectionData.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TableConnectionData.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "QEnumTypes.hxx"
+
+namespace dbaui
+{
+ enum class Cardinality {
+ Undefined, OneMany, ManyOne, OneOne
+ };
+
+ class OConnectionLineData;
+ class ORelationTableConnectionData final : public OTableConnectionData
+ {
+ friend bool operator==(const ORelationTableConnectionData& lhs, const ORelationTableConnectionData& rhs);
+
+ ::osl::Mutex m_aMutex;
+
+ // @see com.sun.star.sdbc.KeyRule
+ sal_Int32 m_nUpdateRules;
+ sal_Int32 m_nDeleteRules;
+ Cardinality m_nCardinality;
+
+ bool checkPrimaryKey(const css::uno::Reference< css::beans::XPropertySet>& i_xTable, EConnectionSide _eEConnectionSide) const;
+ bool IsSourcePrimKey() const { return checkPrimaryKey(getReferencingTable()->getTable(),JTCS_FROM); }
+ bool IsDestPrimKey() const { return checkPrimaryKey(getReferencedTable()->getTable(),JTCS_TO); }
+
+ ORelationTableConnectionData& operator=( const ORelationTableConnectionData& rConnData );
+ public:
+ ORelationTableConnectionData();
+ ORelationTableConnectionData( const ORelationTableConnectionData& rConnData );
+ ORelationTableConnectionData( const TTableWindowData::value_type& _pReferencingTable,
+ const TTableWindowData::value_type& _pReferencedTable,
+ const OUString& rConnName = OUString() );
+ virtual ~ORelationTableConnectionData() override;
+
+ virtual void CopyFrom(const OTableConnectionData& rSource) override;
+ virtual std::shared_ptr<OTableConnectionData> NewInstance() const override { return std::make_shared<ORelationTableConnectionData>(); }
+
+ /** Update create a new relation
+
+ @return true if successful
+ */
+ virtual bool Update() override;
+
+ void SetCardinality();
+ void SetUpdateRules( sal_Int32 nAttr ){ m_nUpdateRules = nAttr; }
+ void SetDeleteRules( sal_Int32 nAttr ){ m_nDeleteRules = nAttr; }
+
+ sal_Int32 GetUpdateRules() const { return m_nUpdateRules; }
+ sal_Int32 GetDeleteRules() const { return m_nDeleteRules; }
+ Cardinality GetCardinality() const { return m_nCardinality; }
+
+ void IsConnectionPossible();
+ void ChangeOrientation();
+ void DropRelation();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RelControliFace.hxx b/dbaccess/source/ui/inc/RelControliFace.hxx
new file mode 100644
index 000000000..65ef79db0
--- /dev/null
+++ b/dbaccess/source/ui/inc/RelControliFace.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+namespace dbaui
+{
+ class IRelationControlInterface
+ {
+ public:
+ virtual ~IRelationControlInterface(){}
+
+ /** setValid set the valid inside, can be used for OK buttons
+ @param _bValid true when the using control allows an update
+ */
+ virtual void setValid(bool _bValid) = 0;
+
+ /** notifyConnectionChange is callback which is called when the table selection has changed and a new connection exists
+ @param _pConnectionData the connection which exists between the new tables
+ */
+ virtual void notifyConnectionChange() = 0;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RelationControl.hxx b/dbaccess/source/ui/inc/RelationControl.hxx
new file mode 100644
index 000000000..5d4edee2a
--- /dev/null
+++ b/dbaccess/source/ui/inc/RelationControl.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+#include "JoinTableView.hxx"
+
+namespace dbaui
+{
+ class OTableListBoxControl;
+ class IRelationControlInterface;
+ class ORelationControl;
+
+ class OTableListBoxControl final
+ {
+ std::unique_ptr<weld::ComboBox> m_xLeftTable;
+ std::unique_ptr<weld::ComboBox> m_xRightTable;
+ std::unique_ptr<weld::Container> m_xTable;
+ css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent;
+ VclPtr<ORelationControl> m_xRC_Tables;
+
+ const OJoinTableView::OTableWindowMap* m_pTableMap;
+ IRelationControlInterface* m_pParentDialog;
+ OUString m_strCurrentLeft;
+ OUString m_strCurrentRight;
+ DECL_LINK( OnTableChanged, weld::ComboBox&, void );
+ public:
+ OTableListBoxControl(weld::Builder* _pParent,
+ const OJoinTableView::OTableWindowMap* _pTableMap,
+ IRelationControlInterface* _pParentDialog);
+ ~OTableListBoxControl();
+
+ /** fillListBoxes fills the list boxes with the table windows
+ */
+ void fillListBoxes();
+
+ /** fillAndDisable fill the listboxes only with one entry and then disable them
+ @param _pConnectionData
+ contains the data which should be filled into the listboxes
+ */
+ void fillAndDisable(const TTableConnectionData::value_type& _pConnectionData);
+
+ /** enables the relation control
+ *
+ * \param _bEnable when sal_True enables it, otherwise disable it.
+ */
+ void enableRelation(bool _bEnable);
+
+ /** NotifyCellChange notifies the browse control that the connection data has changed
+ */
+ void NotifyCellChange();
+
+ /** Init is a call through to the control inside this one
+ @param _pConnData
+ the connection data which is used to init the control
+ */
+ void Init(const TTableConnectionData::value_type& _pConnData);
+ void lateUIInit();
+ void lateInit();
+
+ void Disable();
+ void Invalidate();
+
+ void SaveModified();
+
+ TTableWindowData::value_type const & getReferencingTable() const;
+
+ /** getContainer returns the container interface
+ @return the interface of the container
+ */
+ IRelationControlInterface* getContainer() const { return m_pParentDialog; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RelationController.hxx b/dbaccess/source/ui/inc/RelationController.hxx
new file mode 100644
index 000000000..a457f38b8
--- /dev/null
+++ b/dbaccess/source/ui/inc/RelationController.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include <string_view>
+
+#include "JoinController.hxx"
+
+namespace weld
+{
+ class WaitObject;
+}
+
+namespace dbaui
+{
+ class ORelationController : public OJoinController
+ {
+ css::uno::Reference< css::container::XNameAccess > m_xTables;
+ std::unique_ptr<weld::WaitObject> m_xWaitObject;
+ sal_uLong m_nThreadEvent;
+ bool m_bRelationsPossible;
+ protected:
+ // all the features which should be handled by this class
+ virtual void describeSupportedFeatures() override;
+ // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot.
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ // execute a feature
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ void loadData();
+ TTableWindowData::value_type existsTable(std::u16string_view _rComposedTableName) const;
+
+ // load the window positions out of the datasource
+ void loadLayoutInformation();
+ public:
+ ORelationController(const css::uno::Reference< css::uno::XComponentContext >& _rM);
+
+ virtual ~ORelationController() override;
+
+ void mergeData(const TTableConnectionData& _aConnectionData);
+
+ virtual bool Construct(vcl::Window* pParent) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // OJoinController overridables
+ virtual bool allowViews() const override;
+ virtual bool allowQueries() const override;
+
+ private:
+ // ask the user if the design should be saved when it is modified
+ virtual short saveModified() override;
+ virtual void reset() override;
+ virtual void impl_initialize() override;
+ virtual OUString getPrivateTitle( ) const override;
+ DECL_LINK( OnThreadFinished, void*, void );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RelationDesignView.hxx b/dbaccess/source/ui/inc/RelationDesignView.hxx
new file mode 100644
index 000000000..2fba88be0
--- /dev/null
+++ b/dbaccess/source/ui/inc/RelationDesignView.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "JoinDesignView.hxx"
+
+namespace dbaui
+{
+ class ORelationController;
+
+ class ORelationDesignView : public OJoinDesignView
+ {
+ public:
+ ORelationDesignView(vcl::Window* pParent, ORelationController& _rController,const css::uno::Reference< css::uno::XComponentContext >& );
+
+ // set the statement for representation
+ /// late construction
+ virtual void Construct() override;
+ virtual void initialize() override;
+
+
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void GetFocus() override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RelationDlg.hxx b/dbaccess/source/ui/inc/RelationDlg.hxx
new file mode 100644
index 000000000..c4285f04a
--- /dev/null
+++ b/dbaccess/source/ui/inc/RelationDlg.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include <vcl/weld.hxx>
+#include "JoinTableView.hxx"
+#include "RelControliFace.hxx"
+#include "RelationControl.hxx"
+
+namespace dbaui
+{
+ class OJoinTableView;
+ class ORelationDialog final : public weld::GenericDialogController
+ , public IRelationControlInterface
+ {
+ VclPtr<OJoinTableView> m_pParent;
+ TTableConnectionData::value_type m_pConnData;
+ TTableConnectionData::value_type m_pOrigConnData;
+ bool m_bTriedOneUpdate;
+
+ std::unique_ptr<weld::RadioButton> m_xRB_NoCascUpd;
+ std::unique_ptr<weld::RadioButton> m_xRB_CascUpd;
+ std::unique_ptr<weld::RadioButton> m_xRB_CascUpdNull;
+ std::unique_ptr<weld::RadioButton> m_xRB_CascUpdDefault;
+ std::unique_ptr<weld::RadioButton> m_xRB_NoCascDel;
+ std::unique_ptr<weld::RadioButton> m_xRB_CascDel;
+ std::unique_ptr<weld::RadioButton> m_xRB_CascDelNull;
+ std::unique_ptr<weld::RadioButton> m_xRB_CascDelDefault;
+ std::unique_ptr<weld::Button> m_xPB_OK;
+
+ std::unique_ptr<OTableListBoxControl> m_xTableControl;
+
+ public:
+ ORelationDialog(OJoinTableView* pParent,
+ const TTableConnectionData::value_type& pConnectionData,
+ bool bAllowTableSelect = false );
+ virtual ~ORelationDialog() override;
+
+ virtual short run() override;
+
+ /** setValid set the valid inside, can be used for OK buttons
+ @param _bValid true when the using control allows an update
+ */
+ virtual void setValid(bool _bValid) override;
+
+ /** notifyConnectionChange is callback which is called when the table selection has changed and a new connection exists
+ @param _pConnectionData the connection which exists between the new tables
+ */
+ virtual void notifyConnectionChange() override;
+ private:
+ void Init(const TTableConnectionData::value_type& _pConnectionData);
+
+ DECL_LINK(OKClickHdl, weld::Button&, void);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RelationTableView.hxx b/dbaccess/source/ui/inc/RelationTableView.hxx
new file mode 100644
index 000000000..6c178a3de
--- /dev/null
+++ b/dbaccess/source/ui/inc/RelationTableView.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "JoinTableView.hxx"
+#include <comphelper/containermultiplexer.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <rtl/ref.hxx>
+
+namespace dbaui
+{
+ class ORelationDesignView;
+
+ class ORelationTableView : public ::cppu::BaseMutex,
+ public OJoinTableView,
+ public ::comphelper::OContainerListener
+ {
+ VclPtr<OTableConnection> m_pExistingConnection; ///< is set when a connection was dragged on an existing connection
+ TTableConnectionData::value_type m_pCurrentlyTabConnData; ///< set when we creating a connection with more than one keycolumn
+ ::rtl::Reference< comphelper::OContainerListenerAdapter> m_pContainerListener;
+ bool m_bInRemove;
+
+ virtual void ConnDoubleClicked(VclPtr<OTableConnection>& rConnection) override;
+ virtual void AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool bNewTable = false) override;
+
+ virtual VclPtr<OTableWindow> createWindow(const TTableWindowData::value_type& _pData) override;
+
+ /** determines whether the classes Init method should accept a query
+ name, or only table names */
+ virtual bool allowQueries() const override;
+
+ // OContainerListener
+ virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override;
+
+ public:
+ ORelationTableView( vcl::Window* pParent, ORelationDesignView* pView );
+ virtual ~ORelationTableView() override;
+ virtual void dispose() override;
+
+ virtual void RemoveTabWin( OTableWindow* pTabWin ) override;
+ virtual void AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) override;
+ virtual bool RemoveConnection(VclPtr<OTableConnection>& rConn, bool _bDelete) override;
+
+ virtual void ReSync() override;
+
+ /// Creates a dialogue for a completely new relation.
+ void AddNewRelation();
+
+ /// used by AddTabDlg to check if tables can be added
+ virtual bool IsAddAllowed() override;
+
+ virtual void lookForUiActivities() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/RtfReader.hxx b/dbaccess/source/ui/inc/RtfReader.hxx
new file mode 100644
index 000000000..58f6aa26b
--- /dev/null
+++ b/dbaccess/source/ui/inc/RtfReader.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+#include <svtools/parrtf.hxx>
+#include "DExport.hxx"
+
+class SvStream;
+
+namespace dbaui
+{
+ class ORTFReader final : public SvRTFParser , public ODatabaseExport
+ {
+ std::vector<Color> m_vecColor;
+
+ bool CreateTable(int nToken);
+ virtual void NextToken( int nToken ) override; // base class
+ virtual TypeSelectionPageFactory
+ getTypeSelectionPageFactory() override;
+
+ virtual ~ORTFReader() override;
+
+ public:
+ ORTFReader( SvStream& rIn,
+ const SharedConnection& _rxConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ // required for automatic type recognition
+ ORTFReader( SvStream& rIn,
+ sal_Int32 nRows,
+ TPositions&& _rColumnPositions,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const TColumnVector* rList,
+ const OTypeInfoMap* _pInfoMap,
+ bool _bAutoIncrementEnabled);
+
+ virtual SvParserState CallParser() override;// base class
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/SqlNameEdit.hxx b/dbaccess/source/ui/inc/SqlNameEdit.hxx
new file mode 100644
index 000000000..257b18ebb
--- /dev/null
+++ b/dbaccess/source/ui/inc/SqlNameEdit.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svtools/editbrowsebox.hxx>
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+ class OSQLNameChecker
+ {
+ OUString m_sAllowedChars;
+ bool m_bCheck; // true when we should check for invalid chars
+ public:
+ OSQLNameChecker(const OUString& _rAllowedChars)
+ :m_sAllowedChars(_rAllowedChars)
+ ,m_bCheck(true)
+ {
+ }
+
+ void setAllowedChars(const OUString& _rAllowedChars)
+ {
+ m_sAllowedChars = _rAllowedChars;
+ }
+ void setCheck(bool _bCheck)
+ {
+ m_bCheck = _bCheck;
+ }
+ bool checkString(const OUString& _sToCheck,OUString& _rsCorrected);
+ };
+
+ class OSQLNameEditControl : public svt::EditControl
+ , public OSQLNameChecker
+ {
+ public:
+ OSQLNameEditControl(BrowserDataWin* pParent, const OUString& rAllowedChars)
+ : svt::EditControl(pParent)
+ , OSQLNameChecker(rAllowedChars)
+ {
+ m_xWidget->connect_changed(LINK(this, OSQLNameEditControl, ModifyHdl));
+ }
+
+ virtual void connect_changed(const Link<weld::Entry&, void>& rLink) override
+ {
+ m_ChainChangedHdl = rLink;
+ }
+
+ private:
+ DECL_LINK(ModifyHdl, weld::Entry&, void);
+
+ Link<weld::Entry&,void> m_ChainChangedHdl;
+ };
+
+ class OWidgetBase
+ {
+ private:
+ weld::Widget* m_pWidget;
+ public:
+ OWidgetBase(weld::Widget *pWidget)
+ : m_pWidget(pWidget)
+ {
+ }
+
+ void hide() { m_pWidget->hide(); }
+ void show() { m_pWidget->show(); }
+ void set_sensitive(bool bSensitive) { m_pWidget->set_sensitive(bSensitive); }
+
+ weld::Widget* GetWidget() { return m_pWidget; }
+
+ virtual bool get_value_changed_from_saved() const = 0;
+ virtual void save_value() = 0;
+
+ virtual ~OWidgetBase() {}
+ };
+
+ class OSQLNameEntry : public OWidgetBase
+ , public OSQLNameChecker
+ {
+ private:
+ std::unique_ptr<weld::Entry> m_xEntry;
+
+ DECL_LINK(ModifyHdl, weld::Entry&, void);
+
+ public:
+ OSQLNameEntry(std::unique_ptr<weld::Entry> xEntry, const OUString& _rAllowedChars = OUString())
+ : OWidgetBase(xEntry.get())
+ , OSQLNameChecker(_rAllowedChars)
+ , m_xEntry(std::move(xEntry))
+ {
+ m_xEntry->connect_changed(LINK(this, OSQLNameEntry, ModifyHdl));
+ }
+
+ OUString get_text() const { return m_xEntry->get_text(); }
+ void set_text(const OUString& rText) { m_xEntry->set_text(rText); }
+ void set_max_length(int nLen) { m_xEntry->set_max_length(nLen); }
+ virtual void save_value() override { m_xEntry->save_value(); }
+ virtual bool get_value_changed_from_saved() const override
+ {
+ return m_xEntry->get_value_changed_from_saved();
+ }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableConnection.hxx b/dbaccess/source/ui/inc/TableConnection.hxx
new file mode 100644
index 000000000..3c6ce0fdf
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableConnection.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+#include <vcl/window.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include "TableConnectionData.hxx"
+
+class Point;
+namespace tools { class Rectangle; }
+
+namespace dbaui
+{
+ class OTableConnectionData;
+ class OTableWindow;
+ class OJoinTableView;
+ class OConnectionLine;
+
+ class OTableConnection : public vcl::Window
+ {
+ std::vector<std::unique_ptr<OConnectionLine>> m_vConnLine;
+ TTableConnectionData::value_type
+ m_pData;
+ VclPtr<OJoinTableView> m_pParent;
+
+ bool m_bSelected;
+
+ void Init();
+ /** loops through the vector and deletes all lines */
+ void clearLineData();
+
+ public:
+ OTableConnection( OJoinTableView* pContainer, const TTableConnectionData::value_type& pTabConnData );
+ OTableConnection( const OTableConnection& rConn );
+ /** destructor
+
+ @attention Normally a pointer to OTableConnectionData is given but
+ here, however, one has to create an instance (with
+ OTableConnectionDate::NewInstance) which is never deleted
+ (same like in other cases). Thus, the caller is
+ responsible to check and save the data for deleting it
+ eventually.
+ */
+ virtual ~OTableConnection() override;
+ virtual void dispose() override;
+
+ OTableConnection& operator=( const OTableConnection& rConn );
+
+ void Select();
+ void Deselect();
+ bool IsSelected() const { return m_bSelected; }
+ bool CheckHit( const Point& rMousePos ) const;
+ void InvalidateConnection();
+ void UpdateLineList();
+
+ OTableWindow* GetSourceWin() const;
+ OTableWindow* GetDestWin() const;
+
+ void RecalcLines();
+ /** isTableConnection
+
+ @param _pTable the table where we should check if we belong to it
+ @return true when the source or the destination window are equal
+ */
+ bool isTableConnection(const OTableWindow* _pTable)
+ {
+ return (_pTable == GetSourceWin() || _pTable == GetDestWin());
+ }
+
+ tools::Rectangle GetBoundingRect() const;
+
+ const TTableConnectionData::value_type& GetData() const { return m_pData; }
+ const std::vector<std::unique_ptr<OConnectionLine>>& GetConnLineList() const { return m_vConnLine; }
+ OJoinTableView* GetParent() const { return m_pParent; }
+ virtual void Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect);
+ using Window::Draw;
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableConnectionData.hxx b/dbaccess/source/ui/inc/TableConnectionData.hxx
new file mode 100644
index 000000000..38de22894
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableConnectionData.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "ConnectionLineData.hxx"
+#include "TableWindowData.hxx"
+#include <vector>
+#include <memory>
+
+namespace dbaui
+{
+ //===========================================//
+ // ConnData ---------->* ConnLineData //
+ // ^1 ^1 //
+ // | | //
+ // Conn ---------->* ConnLine //
+ //===========================================//
+
+ /** Contains all connection data which exists between two windows */
+ class OTableConnectionData
+ {
+ protected:
+ TTableWindowData::value_type m_pReferencingTable;
+ TTableWindowData::value_type m_pReferencedTable;
+ OUString m_aConnName;
+
+ OConnectionLineDataVec m_vConnLineData;
+
+ void Init();
+
+ OTableConnectionData& operator=( const OTableConnectionData& rConnData );
+ public:
+ OTableConnectionData();
+ OTableConnectionData( const TTableWindowData::value_type& _pReferencingTable,
+ const TTableWindowData::value_type& _pReferencedTable );
+ OTableConnectionData( const OTableConnectionData& rConnData );
+ virtual ~OTableConnectionData();
+
+ /// initialise from a source (more comfortable than a virtual assignment operator)
+ virtual void CopyFrom(const OTableConnectionData& rSource);
+
+ /** deliver a new instance of my own type
+
+ derived classes have to deliver an instance of their own type
+
+ @note does NOT have to be initialised
+ */
+ virtual std::shared_ptr<OTableConnectionData> NewInstance() const;
+
+ void SetConnLine( sal_uInt16 nIndex, const OUString& rSourceFieldName, const OUString& rDestFieldName );
+ bool AppendConnLine( const OUString& rSourceFieldName, const OUString& rDestFieldName );
+ /** Deletes list of ConnLines
+ */
+ void ResetConnLines();
+
+ /** moves the empty lines to the back
+ removes duplicated empty lines
+
+ caller is responsible for repainting them
+
+ @return index of first changed line, or one-past-the-end if no change
+ */
+ OConnectionLineDataVec::size_type normalizeLines();
+
+ const OConnectionLineDataVec& GetConnLineDataList() const { return m_vConnLineData; }
+ OConnectionLineDataVec& GetConnLineDataList() { return m_vConnLineData; }
+
+ const TTableWindowData::value_type& getReferencingTable() const { return m_pReferencingTable; }
+ const TTableWindowData::value_type& getReferencedTable() const { return m_pReferencedTable; }
+
+ void setReferencingTable(const TTableWindowData::value_type& _pTable) { m_pReferencingTable = _pTable; }
+ void setReferencedTable(const TTableWindowData::value_type& _pTable) { m_pReferencedTable = _pTable; }
+
+ /** Update create a new connection
+
+ @return true if successful
+ */
+ virtual bool Update(){ return true; }
+ };
+
+ typedef std::vector< std::shared_ptr<OTableConnectionData> > TTableConnectionData;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableController.hxx b/dbaccess/source/ui/inc/TableController.hxx
new file mode 100644
index 000000000..ce2017b58
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableController.hxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "singledoccontroller.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "TypeInfo.hxx"
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+namespace dbaui
+{
+ class OTableRow;
+ typedef OSingleDocumentController OTableController_BASE;
+ class OTableController final : public OTableController_BASE
+ {
+ private:
+ std::vector< std::shared_ptr<OTableRow> > m_vRowList;
+ OTypeInfoMap m_aTypeInfo;
+ std::vector<OTypeInfoMap::iterator> m_aTypeInfoIndex;
+
+ css::uno::Reference< css::beans::XPropertySet > m_xTable;
+
+ OUString m_sName; // table for update data
+ OUString m_sAutoIncrementValue; // the autoincrement value set in the datasource
+ OUString m_sTypeNames; // these type names are the ones out of the resource file
+ TOTypeInfoSP m_pTypeInfo; // fall back when type is unknown because database driver has a failure
+
+ bool m_bAllowAutoIncrementValue; // no : 1 NO BIT , is true when the datasource has an AutoIncrementValue property in their info property
+ bool m_bNew : 1; // is true when we create a new table
+
+
+ void reSyncRows();
+ void assignTable(); // set the table if a name is given
+ void loadData();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool checkColumns(bool _bNew); // check if we have double column names
+ void appendColumns(css::uno::Reference< css::sdbcx::XColumnsSupplier> const & _rxColSup, bool _bNew, bool _bKeyColumns = false);
+ void appendPrimaryKey(css::uno::Reference< css::sdbcx::XKeysSupplier> const & _rxSup, bool _bNew);
+ void alterColumns();
+ void dropPrimaryKey();
+ css::uno::Reference< css::container::XNameAccess> getKeyColumns() const;
+ OUString createUniqueName(const OUString& _rName);
+
+ void reload();
+
+ // all the features which should be handled by this class
+ virtual void describeSupportedFeatures() override;
+ // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot.
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ // execute a feature
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ virtual void losingConnection( ) override;
+
+ virtual OUString getPrivateTitle( ) const override;
+
+ void doEditIndexes();
+ bool doSaveDoc(bool _bSaveAs);
+
+ virtual ~OTableController() override;
+ public:
+ OTableController(const css::uno::Reference< css::uno::XComponentContext >& _rM);
+
+ const css::uno::Reference< css::beans::XPropertySet >& getTable() const { return m_xTable;}
+
+ bool isAddAllowed() const;
+ bool isDropAllowed() const;
+ bool isAlterAllowed() const;
+ bool isAutoIncrementPrimaryKey() const;
+
+ bool isAutoIncrementValueEnabled() const { return m_bAllowAutoIncrementValue; }
+ const OUString& getAutoIncrementValue() const { return m_sAutoIncrementValue; }
+
+ virtual void impl_onModifyChanged() override;
+
+ std::vector< std::shared_ptr<OTableRow> >& getRows() { return m_vRowList; }
+
+ /// returns the position of the first empty row
+ sal_Int32 getFirstEmptyRowPosition();
+
+ const OTypeInfoMap& getTypeInfo() const { return m_aTypeInfo; }
+
+ TOTypeInfoSP const & getTypeInfo(sal_Int32 _nPos) const { return m_aTypeInfoIndex[_nPos]->second; }
+ TOTypeInfoSP getTypeInfoByType(sal_Int32 _nDataType) const;
+
+ const TOTypeInfoSP& getTypeInfoFallBack() const { return m_pTypeInfo; }
+
+ virtual bool Construct(vcl::Window* pParent) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // css::frame::XController
+ virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override;
+
+ private:
+ void startTableListening();
+ void stopTableListening();
+ virtual void impl_initialize() override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableCopyHelper.hxx b/dbaccess/source/ui/inc/TableCopyHelper.hxx
new file mode 100644
index 000000000..b543dade8
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableCopyHelper.hxx
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "AppElementType.hxx"
+#include "commontypes.hxx"
+#include <svx/dataaccessdescriptor.hxx>
+#include <sot/storage.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+namespace dbaui
+{
+ class OGenericUnoController;
+ /// Functor object for class DataFlavorExVector::value_type returntype is bool
+ struct TAppSupportedSotFunctor
+ {
+ ElementType eEntryType;
+ TAppSupportedSotFunctor(const ElementType& _eEntryType)
+ : eEntryType(_eEntryType)
+ {
+ }
+
+ bool operator()(const DataFlavorExVector::value_type& _aType)
+ {
+ switch (_aType.mnSotId)
+ {
+ case SotClipboardFormatId::RTF: // RTF data descriptions
+ case SotClipboardFormatId::HTML: // HTML data descriptions
+ case SotClipboardFormatId::DBACCESS_TABLE: // table descriptor
+ return (E_TABLE == eEntryType);
+ case SotClipboardFormatId::DBACCESS_QUERY: // query descriptor
+ case SotClipboardFormatId::DBACCESS_COMMAND: // SQL command
+ return E_QUERY == eEntryType;
+ default: break;
+ }
+ return false;
+ }
+ };
+
+ class OTableCopyHelper
+ {
+ private:
+ OGenericUnoController* m_pController;
+ OUString m_sTableNameForAppend;
+
+ public:
+ // is needed to describe the drop target
+ struct DropDescriptor
+ {
+ svx::ODataAccessDescriptor aDroppedData;
+
+ //for transfor the tablename
+ OUString sDefaultTableName;
+
+ OUString aUrl;
+ tools::SvRef<SotTempStream> aHtmlRtfStorage;
+ ElementType nType;
+ std::unique_ptr<weld::TreeIter> xDroppedAt;
+ sal_Int8 nAction;
+ bool bHtml;
+ bool bError;
+
+ DropDescriptor()
+ : nType(E_TABLE)
+ , nAction(DND_ACTION_NONE)
+ , bHtml(false)
+ , bError(false)
+ { }
+ };
+
+ OTableCopyHelper(OGenericUnoController* _pController);
+
+ /** pastes a table into the data source
+ @param _rPasteData
+ The data helper.
+ @param _sDestDataSourceName
+ The name of the dest data source.
+ */
+ void pasteTable( const TransferableDataHelper& _rTransData
+ ,std::u16string_view _sDestDataSourceName
+ ,const SharedConnection& _xConnection);
+
+ /** pastes a table into the data source
+ @param _nFormatId
+ The format which should be copied.
+ @param _rPasteData
+ The data helper.
+ @param _sDestDataSourceName
+ The name of the dest data source.
+ */
+ void pasteTable( SotClipboardFormatId _nFormatId
+ ,const TransferableDataHelper& _rTransData
+ ,std::u16string_view _sDestDataSourceName
+ ,const SharedConnection& _xConnection);
+
+ /** copies a table which was constructed by tags like HTML or RTF
+ @param _rDesc
+ The Drop descriptor
+ @param _bCheck
+ If set to <TRUE/> than the controller checks only if a copy is possible.
+ @param _xConnection
+ The connection
+ */
+ bool copyTagTable( DropDescriptor const & _rDesc,
+ bool _bCheck,
+ const SharedConnection& _xConnection);
+
+ /** copies a table which was constructed by tags like HTML or RTF
+ @param _rDesc
+ The Drop descriptor
+ @param _bCheck
+ If set to <TRUE/> than the controller checks only if a copy is possible.
+ @param _xConnection
+ The connection
+ */
+ void asyncCopyTagTable( DropDescriptor& _rDesc
+ ,std::u16string_view _sDestDataSourceName
+ ,const SharedConnection& _xConnection);
+
+ /** copies a table which was constructed by tags like HTML or RTF
+ @param _aDroppedData
+ The dropped data
+ @param _rDesc
+ IN/OUT parameter
+ @param _xConnection
+ The connection
+ */
+ bool copyTagTable(const TransferableDataHelper& _aDroppedData,
+ DropDescriptor& _rAsyncDrop,
+ const SharedConnection& _xConnection);
+
+ /// returns <TRUE/> if the clipboard supports a table format, otherwise <FALSE/>.
+ static bool isTableFormat(const TransferableDataHelper& _rClipboard);
+
+ void SetTableNameForAppend( const OUString& _rDefaultTableName ) { m_sTableNameForAppend = _rDefaultTableName; }
+ void ResetTableNameForAppend() { SetTableNameForAppend( OUString() ); }
+ const OUString& GetTableNameForAppend() const { return m_sTableNameForAppend ;}
+
+ private:
+ /** pastes a table into the data source
+ @param _rPasteData
+ The data descriptor.
+ @param _sDestDataSourceName
+ The name of the dest data source.
+ */
+ void pasteTable(
+ const svx::ODataAccessDescriptor& _rPasteData,
+ std::u16string_view _sDestDataSourceName,
+ const SharedConnection& _xDestConnection
+ );
+
+ /** insert a table into the data source. The source can either be a table or a query
+ */
+ void insertTable(
+ std::u16string_view i_rSourceDataSource,
+ const css::uno::Reference< css::sdbc::XConnection>& i_rSourceConnection,
+ const OUString& i_rCommand,
+ const sal_Int32 i_nCommandType,
+ const css::uno::Reference< css::sdbc::XResultSet >& i_rSourceRows,
+ const css::uno::Sequence< css::uno::Any >& i_rSelection,
+ const bool i_bBookmarkSelection,
+ std::u16string_view i_rDestDataSource,
+ const css::uno::Reference< css::sdbc::XConnection>& i_rDestConnection
+ );
+
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableDesignControl.hxx b/dbaccess/source/ui/inc/TableDesignControl.hxx
new file mode 100644
index 000000000..89debc9e1
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableDesignControl.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svtools/editbrowsebox.hxx>
+
+#include "IClipBoardTest.hxx"
+#include "TypeInfo.hxx"
+
+namespace dbaui
+{
+ class OTableDesignView;
+
+ class OTableRowView : public ::svt::EditBrowseBox, public IClipboardTest
+ {
+ friend class OTableDesignUndoAct;
+
+ protected:
+ tools::Long m_nDataPos; ///< currently needed row
+ tools::Long m_nCurrentPos; ///< current position of selected column
+
+ private:
+ sal_uInt16 m_nCurUndoActId;
+
+ public:
+ OTableRowView(vcl::Window* pParent);
+
+ virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) = 0;
+ virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rNewData ) = 0;
+ virtual css::uno::Any GetCellData( sal_Int32 nRow, sal_uInt16 nColId ) = 0;
+ virtual void SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText ) = 0;
+
+ virtual OTableDesignView* GetView() const = 0;
+
+ sal_uInt16 GetCurUndoActId() const { return m_nCurUndoActId; }
+
+ // IClipboardTest
+ virtual void cut() override;
+ virtual void copy() override;
+ virtual void paste() override;
+
+ protected:
+ void Paste( sal_Int32 nRow );
+
+ virtual void CopyRows() = 0;
+ virtual void DeleteRows() = 0;
+ virtual void InsertRows( sal_Int32 nRow ) = 0;
+ virtual void InsertNewRows( sal_Int32 nRow ) = 0;
+
+ virtual bool IsPrimaryKeyAllowed() = 0;
+ virtual bool IsInsertNewAllowed( sal_Int32 nRow ) = 0;
+ virtual bool IsDeleteAllowed() = 0;
+
+ virtual RowStatus GetRowStatus(sal_Int32 nRow) const override;
+ virtual void KeyInput(const KeyEvent& rEvt) override;
+ virtual void Command( const CommandEvent& rEvt ) override;
+
+ virtual void Init() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableDesignHelpBar.hxx b/dbaccess/source/ui/inc/TableDesignHelpBar.hxx
new file mode 100644
index 000000000..db4023d36
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableDesignHelpBar.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+#include "IClipBoardTest.hxx"
+
+namespace dbaui
+{
+ class OTableDesignHelpBar final : public IClipboardTest
+ {
+ private:
+ std::unique_ptr<weld::TextView> m_xTextWin;
+
+ public:
+ OTableDesignHelpBar(std::unique_ptr<weld::TextView> xTextWin);
+
+ void SetHelpText( const OUString& rText );
+
+ bool HasFocus() const { return m_xTextWin->has_focus(); }
+
+ void connect_focus_in(const Link<weld::Widget&, void>& rLink)
+ {
+ m_xTextWin->connect_focus_in(rLink);
+ }
+
+ void connect_focus_out(const Link<weld::Widget&, void>& rLink)
+ {
+ m_xTextWin->connect_focus_out(rLink);
+ }
+
+ // IClipboardTest
+ virtual bool isCutAllowed() override;
+ virtual bool isCopyAllowed() override;
+ virtual bool isPasteAllowed() override;
+
+ virtual void copy() override;
+ virtual void cut() override;
+ virtual void paste() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableDesignView.hxx b/dbaccess/source/ui/inc/TableDesignView.hxx
new file mode 100644
index 000000000..077eb211e
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableDesignView.hxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dbaccess/dataview.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/weld.hxx>
+#include "IClipBoardTest.hxx"
+
+namespace dbaui
+{
+ class OTableController;
+ class OTableDesignView;
+ class OTableFieldDescWin;
+ class OTableEditorCtrl;
+
+ class OTableBorderWindow final : public InterimItemWindow
+ {
+ std::unique_ptr<weld::Paned> m_xHorzSplitter;
+ std::unique_ptr<weld::Container> m_xEditorParent;
+ css::uno::Reference<css::awt::XWindow> m_xEditorParentWin;
+ VclPtr<OTableEditorCtrl> m_xEditorCtrl;
+ std::unique_ptr<weld::Container> m_xFieldDescParent;
+ std::unique_ptr<OTableFieldDescWin> m_xFieldDescWin;
+
+ public:
+ OTableBorderWindow(OTableDesignView* pParent);
+ virtual ~OTableBorderWindow() override;
+ // Window overrides
+ virtual void dispose() override;
+
+ virtual void GetFocus() override;
+ virtual void Layout() override;
+
+ OTableEditorCtrl* GetEditorCtrl() const { return m_xEditorCtrl.get(); }
+ OTableFieldDescWin* GetDescWin() const { return m_xFieldDescWin.get(); }
+ };
+
+ class OTableDesignView : public ODataView
+ , public IClipboardTest
+ {
+ enum ChildFocusState
+ {
+ DESCRIPTION,
+ EDITOR,
+ NONE
+ };
+ private:
+ css::lang::Locale m_aLocale;
+ VclPtr<OTableBorderWindow> m_pWin;
+ OTableController& m_rController;
+ ChildFocusState m_eChildFocus;
+
+ IClipboardTest* getActiveChild() const;
+
+ DECL_LINK( FieldDescFocusIn, weld::Widget&, void );
+ protected:
+
+ // return the Rectangle where I can paint myself
+ virtual void resizeDocumentView(tools::Rectangle& rRect) override;
+
+ public:
+ OTableDesignView( vcl::Window* pParent,
+ const css::uno::Reference< css::uno::XComponentContext >&,
+ OTableController& _rController);
+ virtual ~OTableDesignView() override;
+ virtual void dispose() override;
+
+ // Window overrides
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void GetFocus() override;
+
+ OTableEditorCtrl* GetEditorCtrl() const { return m_pWin ? m_pWin->GetEditorCtrl() : nullptr; }
+ OTableFieldDescWin* GetDescWin() const { return m_pWin ? m_pWin->GetDescWin() : nullptr; }
+ OTableController& getController() const { return m_rController; }
+
+ const css::lang::Locale& getLocale() const { return m_aLocale;}
+
+ // IClipboardTest
+ virtual bool isCutAllowed() override;
+ virtual bool isCopyAllowed() override;
+ virtual bool isPasteAllowed() override;
+ virtual void copy() override;
+ virtual void cut() override;
+ virtual void paste() override;
+
+ // set the view readonly or not
+ void setReadOnly(bool _bReadOnly);
+
+ virtual void initialize() override;
+ void reSync(); // resync window data with realdata
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableFieldDescription.hxx b/dbaccess/source/ui/inc/TableFieldDescription.hxx
new file mode 100644
index 000000000..d21ad953a
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableFieldDescription.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+
+#include "QEnumTypes.hxx"
+#include <rtl/ustring.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <rtl/ref.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/window.hxx>
+
+#include <salhelper/simplereferenceobject.hxx>
+
+namespace comphelper
+{
+ class NamedValueCollection;
+}
+
+namespace vcl { class Window; }
+
+namespace dbaui
+{
+ class OTableFieldDesc : public ::salhelper::SimpleReferenceObject
+ {
+ private:
+ std::vector< OUString >
+ m_aCriteria;
+
+ OUString m_aTableName;
+ OUString m_aAliasName; ///< table range
+ OUString m_aFieldName; ///< column
+ OUString m_aFieldAlias; ///< column alias
+ OUString m_aFunctionName;///< contains the function name (only if m_eFunctionType != FKT_NONE)
+
+ VclPtr<vcl::Window> m_pTabWindow;
+
+ sal_Int32 m_eDataType;
+ sal_Int32 m_eFunctionType;
+ ETableFieldType m_eFieldType;
+ EOrderDir m_eOrderDir;
+ sal_Int32 m_nIndex;
+ sal_Int32 m_nColWidth;
+ sal_uInt16 m_nColumnId;
+ bool m_bGroupBy;
+ bool m_bVisible;
+
+ // when adding new fields, please take care of IsEmpty!
+
+ public:
+ OTableFieldDesc();
+ OTableFieldDesc(const OUString& rTable, const OUString& rField );
+ OTableFieldDesc(const OTableFieldDesc& rRS);
+ virtual ~OTableFieldDesc() override;
+
+ inline bool IsEmpty() const;
+
+ OTableFieldDesc& operator=( const OTableFieldDesc& _aField );
+
+ bool IsVisible() const { return m_bVisible;}
+ bool IsGroupBy() const { return m_bGroupBy;}
+
+ void SetVisible( bool bVis=true ) { m_bVisible = bVis; }
+ void SetGroupBy( bool bGb ) { m_bGroupBy = bGb; }
+ void SetTabWindow( vcl::Window* pWin ){ m_pTabWindow = pWin; }
+ void SetField( const OUString& rF ) { m_aFieldName = rF; }
+ void SetFieldAlias( const OUString& rF ) { m_aFieldAlias = rF; }
+ void SetTable( const OUString& rT ) { m_aTableName = rT; }
+ void SetAlias( const OUString& rT ) { m_aAliasName = rT; }
+ void SetFunction( const OUString& rT ) { m_aFunctionName = rT; }
+ void SetOrderDir( EOrderDir eDir ) { m_eOrderDir = eDir; }
+ void SetDataType( sal_Int32 eTyp ) { m_eDataType = eTyp; }
+ void SetFieldType( ETableFieldType eTyp ) { m_eFieldType = eTyp; }
+ void SetCriteria( sal_uInt16 nIdx, const OUString& rCrit );
+ void SetColWidth( sal_Int32 nWidth ) { m_nColWidth = nWidth; }
+ void SetFieldIndex( sal_Int32 nFieldIndex ) { m_nIndex = nFieldIndex; }
+ void SetFunctionType( sal_Int32 eTyp ) { m_eFunctionType = eTyp; }
+ void SetColumnId(sal_uInt16 _nColumnId) { m_nColumnId = _nColumnId; }
+
+ const OUString& GetField() const { return m_aFieldName;}
+ const OUString& GetFieldAlias() const { return m_aFieldAlias;}
+ const OUString& GetTable() const { return m_aTableName;}
+ const OUString& GetAlias() const { return m_aAliasName;}
+ const OUString& GetFunction() const { return m_aFunctionName;}
+ sal_Int32 GetDataType() const { return m_eDataType; }
+ ETableFieldType GetFieldType() const { return m_eFieldType; }
+ EOrderDir GetOrderDir() const { return m_eOrderDir; }
+ OUString GetCriteria( sal_uInt16 nIdx ) const;
+ sal_Int32 GetColWidth() const { return m_nColWidth; }
+ sal_Int32 GetFieldIndex() const { return m_nIndex; }
+ vcl::Window* GetTabWindow() const { return m_pTabWindow;}
+ sal_Int32 GetFunctionType() const { return m_eFunctionType; }
+ sal_uInt16 GetColumnId() const { return m_nColumnId;}
+
+ bool isAggregateFunction() const { return (m_eFunctionType & FKT_AGGREGATE) == FKT_AGGREGATE; }
+ bool isOtherFunction() const { return (m_eFunctionType & FKT_OTHER) == FKT_OTHER; }
+ bool isNumeric() const { return (m_eFunctionType & FKT_NUMERIC) == FKT_NUMERIC; }
+ bool isNoneFunction() const { return m_eFunctionType == FKT_NONE; }
+ bool isCondition() const { return (m_eFunctionType & FKT_CONDITION) == FKT_CONDITION; }
+ bool isNumericOrAggregateFunction() const { return isNumeric() || isAggregateFunction(); }
+
+ bool HasCriteria() const
+ {
+ for (auto const& criteria : m_aCriteria)
+ {
+ if(!criteria.isEmpty())
+ return true;
+ }
+ return false;
+ }
+
+ const std::vector< OUString>& GetCriteria() const { return m_aCriteria; }
+
+ void Load( const css::beans::PropertyValue& i_rSettings, const bool i_bIncludingCriteria );
+ void Save( ::comphelper::NamedValueCollection& o_rSettings, const bool i_bIncludingCriteria );
+ };
+
+ inline bool OTableFieldDesc::IsEmpty() const
+ {
+ bool bEmpty = (m_aTableName.isEmpty() &&
+ m_aAliasName.isEmpty() &&
+ m_aFieldName.isEmpty() &&
+ m_aFieldAlias.isEmpty() &&
+ m_aFunctionName.isEmpty() &&
+ !HasCriteria());
+ return bEmpty;
+ }
+
+ typedef ::rtl::Reference< OTableFieldDesc> OTableFieldDescRef;
+ typedef std::vector<OTableFieldDescRef> OTableFields;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableGrantCtrl.hxx b/dbaccess/source/ui/inc/TableGrantCtrl.hxx
new file mode 100644
index 000000000..74a9fd8b5
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableGrantCtrl.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <svtools/editbrowsebox.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XAuthorizable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+class Edit;
+namespace dbaui
+{
+
+class OTableGrantControl : public ::svt::EditBrowseBox
+{
+ typedef struct
+ {
+ sal_Int32 nRights;
+ sal_Int32 nWithGrant;
+ } TPrivileges;
+
+ typedef std::map<OUString, TPrivileges> TTablePrivilegeMap;
+
+ css::uno::Reference< css::container::XNameAccess > m_xUsers;
+ css::uno::Reference< css::container::XNameAccess > m_xTables;
+ css::uno::Reference< css::uno::XComponentContext> m_xContext;
+ css::uno::Reference< css::sdbcx::XAuthorizable> m_xGrantUser;
+ css::uno::Sequence< OUString> m_aTableNames;
+
+ mutable TTablePrivilegeMap m_aPrivMap;
+ OUString m_sUserName;
+ VclPtr<::svt::CheckBoxControl> m_pCheckCell;
+ VclPtr<::svt::EditControl> m_pEdit;
+ tools::Long m_nDataPos;
+ ImplSVEvent * m_nDeactivateEvent;
+
+public:
+ OTableGrantControl(const css::uno::Reference<css::awt::XWindow> &rParent);
+ virtual ~OTableGrantControl() override;
+ virtual void dispose() override;
+ void UpdateTables();
+ void setUserName(const OUString& _sUserName);
+ void setGrantUser(const css::uno::Reference< css::sdbcx::XAuthorizable>& _xGrantUser);
+
+ void setTablesSupplier(const css::uno::Reference< css::sdbcx::XTablesSupplier >& _xTablesSup);
+ void setComponentContext(const css::uno::Reference< css::uno::XComponentContext>& _rxContext);
+
+ virtual void Init() override;
+
+ // IAccessibleTableProvider
+ /** Creates the accessible object of a data table cell.
+ @param nRow The row index of the cell.
+ @param nColumnId The column ID of the cell.
+ @return The XAccessible interface of the specified cell. */
+ virtual css::uno::Reference<
+ css::accessibility::XAccessible >
+ CreateAccessibleCell( sal_Int32 nRow, sal_uInt16 nColumnId ) override;
+
+protected:
+ virtual bool PreNotify(NotifyEvent& rNEvt ) override;
+
+ virtual bool IsTabAllowed(bool bForward) const override;
+ virtual void InitController( ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) override;
+ virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override;
+ virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override;
+ virtual bool SeekRow( sal_Int32 nRow ) override;
+ virtual bool SaveModified() override;
+ virtual OUString GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const override;
+
+ virtual void CellModified() override;
+
+private:
+ DECL_LINK( AsynchActivate, void*, void );
+ DECL_LINK( AsynchDeactivate, void*, void );
+
+ static bool isAllowed(sal_uInt16 _nColumnId,sal_Int32 _nPrivilege);
+ void fillPrivilege(sal_Int32 _nRow) const;
+ TTablePrivilegeMap::const_iterator findPrivilege(sal_Int32 _nRow) const;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableRow.hxx b/dbaccess/source/ui/inc/TableRow.hxx
new file mode 100644
index 000000000..4f34a94bf
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableRow.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <tools/long.hxx>
+#include "TypeInfo.hxx"
+
+class SvStream;
+
+namespace dbaui
+{
+ class OFieldDescription;
+ class OTableRow
+ {
+ private:
+ OFieldDescription* m_pActFieldDescr;
+ sal_Int32 m_nPos;
+ bool m_bReadOnly;
+ bool m_bOwnsDescriptions;
+
+ protected:
+ public:
+ OTableRow();
+ OTableRow( const OTableRow& rRow, tools::Long nPosition = -1 );
+ ~OTableRow();
+
+ OFieldDescription* GetActFieldDescr() const { return m_pActFieldDescr; }
+ bool isValid() const { return GetActFieldDescr() != nullptr; }
+
+ void SetFieldType( const TOTypeInfoSP& _pType, bool _bForce = false );
+
+ void SetPrimaryKey( bool bSet );
+ bool IsPrimaryKey() const;
+
+ /** returns the current position in the table.
+ @return
+ the current position in the table
+ */
+ sal_Int32 GetPos() const { return m_nPos; }
+ void SetPos(sal_Int32 _nPos) { m_nPos = _nPos; }
+
+ /** set the row readonly
+ @param _bRead
+ if <TRUE/> then the row is readonly, otherwise not
+ */
+ void SetReadOnly( bool _bRead=true ){ m_bReadOnly = _bRead; }
+
+ /** returns if the row is readonly
+ @return
+ <TRUE/> if readonly, otherwise <FALSE/>
+ */
+ bool IsReadOnly() const { return m_bReadOnly; }
+
+ friend SvStream& WriteOTableRow( SvStream& rStr,const OTableRow& _rRow );
+ friend SvStream& ReadOTableRow( SvStream& rStr, OTableRow& _rRow );
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableRowExchange.hxx b/dbaccess/source/ui/inc/TableRowExchange.hxx
new file mode 100644
index 000000000..36e249795
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableRowExchange.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <memory>
+
+namespace dbaui
+{
+ class OTableRow;
+ class OTableRowExchange : public TransferableHelper
+ {
+ std::vector< std::shared_ptr<OTableRow> > m_vTableRow;
+ public:
+ OTableRowExchange(std::vector< std::shared_ptr<OTableRow> >&& _rvTableRow);
+ protected:
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual bool WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& rFlavor ) override;
+ virtual void ObjectReleased() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableWindow.hxx b/dbaccess/source/ui/inc/TableWindow.hxx
new file mode 100644
index 000000000..c3bed06c7
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableWindow.hxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "TableWindowTitle.hxx"
+#include <rtl/ref.hxx>
+#include "TableWindowData.hxx"
+#include "TableWindowListBox.hxx"
+#include <vector>
+#include <vcl/window.hxx>
+
+#include <comphelper/containermultiplexer.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <o3tl/typed_flags_set.hxx>
+
+// Flags for the size adjustment of SbaJoinTabWins
+enum class SizingFlags {
+ NONE = 0x0000,
+ Top = 0x0001,
+ Bottom = 0x0002,
+ Left = 0x0004,
+ Right = 0x0008,
+};
+namespace o3tl {
+ template<> struct typed_flags<SizingFlags> : is_typed_flags<SizingFlags, 0x0f> {};
+}
+
+
+namespace dbaui
+{
+ class OJoinDesignView;
+ class OJoinTableView;
+ class OTableWindowAccess;
+
+ class OTableWindow : public ::cppu::BaseMutex
+ ,public ::comphelper::OContainerListener
+ ,public vcl::Window
+ {
+ friend class OTableWindowTitle;
+ friend class OTableWindowListBox;
+ protected:
+ // and the table itself (needed for me as I want to lock it as long as the window is alive)
+ VclPtr<OTableWindowTitle> m_xTitle;
+ VclPtr<OTableWindowListBox> m_xListBox;
+
+ private:
+ TTableWindowData::value_type
+ m_pData;
+ ::rtl::Reference< comphelper::OContainerListenerAdapter>
+ m_pContainerListener;
+ sal_Int32 m_nMoveCount; // how often the arrow keys was pressed
+ sal_Int32 m_nMoveIncrement; // how many pixel we should move
+ SizingFlags m_nSizingFlags;
+
+ // OContainerListener
+ virtual void _elementInserted( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementRemoved( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void _elementReplaced( const css::container::ContainerEvent& _rEvent ) override;
+
+ protected:
+ virtual void Resize() override;
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+ virtual void MouseMove( const MouseEvent& rEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rEvt ) override;
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+
+ // called at FIRST Init
+ void FillListBox();
+ // called at EACH Init
+
+ virtual void OnEntryDoubleClicked(weld::TreeIter& /*rEntry*/) { }
+ // called from the DoubleClickHdl of the ListBox
+
+ /** delete the user data with the equal type as created within createUserData
+ @param _pUserData
+ The user data store in the listbox entries. Created with a call to createUserData.
+ _pUserData may be <NULL/>. _pUserData will be set to <NULL/> after call.
+ */
+ virtual void deleteUserData(void*& _pUserData);
+
+ /** creates user information that will be append at the ListBoxentry
+ @param _xColumn
+ The corresponding column, can be <NULL/>.
+ @param _bPrimaryKey
+ <TRUE/> when the column belongs to the primary key
+ @return
+ the user data which will be append at the listbox entry, may be <NULL/>
+ */
+ virtual void* createUserData(const css::uno::Reference<
+ css::beans::XPropertySet>& _xColumn,
+ bool _bPrimaryKey);
+
+ /** updates image
+ */
+ void impl_updateImage();
+
+ OTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData );
+
+ public:
+ virtual ~OTableWindow() override;
+ virtual void dispose() override;
+
+ // late Constructor, see also CreateListbox and FillListbox
+ virtual bool Init();
+
+ OJoinTableView* getTableView();
+ const OJoinTableView* getTableView() const;
+ OJoinDesignView* getDesignView();
+ void SetPosPixel( const Point& rNewPos ) override;
+ void SetSizePixel( const Size& rNewSize ) override;
+ void SetPosSizePixel( const Point& rNewPos, const Size& rNewSize ) override;
+
+ OUString getTitle() const;
+ void SetBoldTitle( bool bBold );
+ void setActive(bool _bActive = true);
+
+ void Remove();
+
+ OUString const & GetTableName() const { return m_pData->GetTableName(); }
+ OUString const & GetWinName() const { return m_pData->GetWinName(); }
+ OUString const & GetComposedName() const { return m_pData->GetComposedName(); }
+ const VclPtr<OTableWindowListBox>& GetListBox() const { return m_xListBox; }
+ const TTableWindowData::value_type& GetData() const { return m_pData; }
+ const VclPtr<OTableWindowTitle>& GetTitleCtrl() const { return m_xTitle; }
+
+ /** returns the name which should be used when displaying join or relations
+ @return
+ The composed name or the window name.
+ */
+ virtual OUString GetName() const = 0;
+
+ css::uno::Reference< css::container::XNameAccess > GetOriginalColumns() const { return m_pData->getColumns(); }
+ css::uno::Reference< css::beans::XPropertySet > GetTable() const { return m_pData->getTable(); }
+
+ /** set the sizing flag to the direction
+ @param _rPos
+ The EndPosition after resizing.
+ */
+ void setSizingFlag(const Point& _rPos);
+
+ /** returns the new sizing
+ */
+ tools::Rectangle getSizingRect(const Point& _rPos,const Size& _rOutputSize) const;
+
+ // window override
+ virtual void StateChanged( StateChangedType nStateChange ) override;
+ virtual void GetFocus() override;
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void Command(const CommandEvent& rEvt) override;
+
+ // Accessibility
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ // do I have connections to the outside?
+ bool ExistsAConn() const;
+
+ void EnumValidFields(std::vector< OUString>& arrstrFields);
+
+ /** clears the listbox inside. Must be called be the dtor is called.
+ */
+ void clearListBox();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableWindowAccess.hxx b/dbaccess/source/ui/inc/TableWindowAccess.hxx
new file mode 100644
index 000000000..b51e4c80f
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableWindowAccess.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TableWindow.hxx"
+#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
+#include <cppuhelper/implbase2.hxx>
+#include <toolkit/awt/vclxaccessiblecomponent.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace dbaui
+{
+ typedef ::cppu::ImplHelper2< css::accessibility::XAccessibleRelationSet,
+ css::accessibility::XAccessible
+ > OTableWindowAccess_BASE;
+ class OTableWindow;
+ /** the class OTableWindowAccess represents the accessible object for table windows
+ like they are used in the QueryDesign and the RelationDesign
+ */
+ class OTableWindowAccess : public VCLXAccessibleComponent
+ , public OTableWindowAccess_BASE
+ {
+ VclPtr<OTableWindow> m_pTable; // the window which I should give accessibility to
+
+ css::uno::Reference< css::accessibility::XAccessible > getParentChild(sal_Int32 _nIndex);
+ protected:
+ /** this function is called upon disposing the component
+ */
+ virtual void SAL_CALL disposing() override;
+
+ virtual void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override;
+ public:
+ OTableWindowAccess( OTableWindow* _pTable);
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override
+ { // here inline is allowed because we do not use this class outside this dll
+ VCLXAccessibleComponent::acquire( );
+ }
+ virtual void SAL_CALL release( ) noexcept override
+ { // here inline is allowed because we do not use this class outside this dll
+ VCLXAccessibleComponent::release( );
+ }
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+
+ // XAccessibleComponent
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ // XAccessibleExtendedComponent
+ virtual OUString SAL_CALL getTitledBorderText( ) override;
+
+ // XAccessibleRelationSet
+ virtual sal_Int32 SAL_CALL getRelationCount( ) override;
+ virtual css::accessibility::AccessibleRelation SAL_CALL getRelation( sal_Int32 nIndex ) override;
+ virtual sal_Bool SAL_CALL containsRelation( sal_Int16 aRelationType ) override;
+ virtual css::accessibility::AccessibleRelation SAL_CALL getRelationByType( sal_Int16 aRelationType ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableWindowData.hxx b/dbaccess/source/ui/inc/TableWindowData.hxx
new file mode 100644
index 000000000..f7aea00b9
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableWindowData.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <tools/gen.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <unotools/eventlisteneradapter.hxx>
+#include <memory>
+#include <vector>
+
+namespace dbaui
+{
+ class OTableWindowData : public ::utl::OEventListenerAdapter
+ {
+ mutable ::osl::Mutex m_aMutex;
+
+ void listen();
+ protected:
+ // the columns of the table
+ css::uno::Reference< css::beans::XPropertySet > m_xTable; // can either be a table or a query
+ css::uno::Reference< css::container::XIndexAccess> m_xKeys;
+ css::uno::Reference< css::container::XNameAccess > m_xColumns;
+
+ OUString m_aTableName;
+ OUString m_aWinName;
+ OUString m_sComposedName;
+ Point m_aPosition;
+ Size m_aSize;
+ bool m_bShowAll;
+ bool m_bIsQuery;
+ bool m_bIsValid;
+
+ public:
+ explicit OTableWindowData( const css::uno::Reference< css::beans::XPropertySet>& _xTable
+ ,const OUString& _rComposedName
+ ,const OUString& strTableName
+ ,const OUString& rWinName );
+ virtual ~OTableWindowData() override;
+
+ /** late constructor
+ *
+ * \param _xConnection
+ * \param _bAllowQueries when true, queries are allowed
+ * \return false if the table was unaccessible otherwise true
+ */
+ bool init(const css::uno::Reference< css::sdbc::XConnection >& _xConnection
+ ,bool _bAllowQueries);
+
+ const OUString& GetComposedName() const { return m_sComposedName; }
+ const OUString& GetTableName() const { return m_aTableName; }
+ const OUString& GetWinName() const { return m_aWinName; }
+ const Point& GetPosition() const { return m_aPosition; }
+ const Size& GetSize() const { return m_aSize; }
+ bool IsShowAll() const { return m_bShowAll; }
+ bool isQuery() const { return m_bIsQuery; }
+ bool isValid() const { return m_bIsValid; } // it is either a table or query but it is known
+ bool HasPosition() const;
+ bool HasSize() const;
+
+ void SetWinName( const OUString& rWinName ) { m_aWinName = rWinName; }
+ void SetPosition( const Point& rPos ) { m_aPosition=rPos; }
+ void SetSize( const Size& rSize ) { m_aSize = rSize; }
+ void ShowAll( bool bAll ) { m_bShowAll = bAll; }
+
+ css::uno::Reference< css::beans::XPropertySet> getTable() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xTable; }
+ css::uno::Reference< css::container::XIndexAccess> getKeys() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xKeys; }
+ css::uno::Reference< css::container::XNameAccess > getColumns() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xColumns; }
+
+ // OEventListenerAdapter
+ virtual void _disposing( const css::lang::EventObject& _rSource ) override;
+ };
+
+ typedef std::vector< std::shared_ptr<OTableWindowData> > TTableWindowData;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableWindowListBox.hxx b/dbaccess/source/ui/inc/TableWindowListBox.hxx
new file mode 100644
index 000000000..cdad4947c
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableWindowListBox.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include "callbacks.hxx"
+
+struct AcceptDropEvent;
+struct ExecuteDropEvent;
+namespace dbaui
+{
+ class OTableWindowListBox;
+ struct OJoinExchangeData
+ {
+ public:
+ VclPtr<OTableWindowListBox> pListBox; // the ListBox inside the same (you can get the TabWin and the WinName out of it)
+ int nEntry; // the entry, which was dragged or to which was dropped on
+
+ OJoinExchangeData(OTableWindowListBox* pBox);
+ OJoinExchangeData() : pListBox(nullptr), nEntry(-1) { }
+ };
+
+ struct OJoinDropData
+ {
+ OJoinExchangeData aSource;
+ OJoinExchangeData aDest;
+ };
+
+ class OJoinExchObj;
+ class OTableWindow;
+ class TableWindowListBoxHelper;
+
+ class OTableWindowListBox
+ : public InterimItemWindow
+ , public IDragTransferableListener
+ {
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ std::unique_ptr<TableWindowListBoxHelper> m_xDragDropTargetHelper;
+
+ DECL_LINK( OnDoubleClick, weld::TreeView&, bool );
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+ DECL_LINK( DropHdl, void*, void );
+ DECL_LINK( LookForUiHdl, void*, void );
+ DECL_LINK( DragBeginHdl, bool&, bool );
+ DECL_LINK( ScrollHdl, weld::TreeView&, void );
+
+ rtl::Reference<OJoinExchObj> m_xHelper;
+
+ VclPtr<OTableWindow> m_pTabWin;
+ ImplSVEvent * m_nDropEvent;
+ ImplSVEvent * m_nUiEvent;
+ OJoinDropData m_aDropInfo;
+
+ protected:
+ virtual void LoseFocus() override;
+ virtual void GetFocus() override;
+
+ virtual void dragFinished( ) override;
+
+ public:
+ OTableWindowListBox(OTableWindow* pParent);
+ virtual ~OTableWindowListBox() override;
+ virtual void dispose() override;
+
+ const weld::TreeView& get_widget() const { return *m_xTreeView; }
+ weld::TreeView& get_widget() { return *m_xTreeView; }
+
+ // DnD stuff
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
+
+ // window
+ virtual void Command(const CommandEvent& rEvt) override;
+
+ OTableWindow* GetTabWin(){ return m_pTabWin; }
+ int GetEntryFromText( std::u16string_view rEntryText );
+ };
+
+ class TableWindowListBoxHelper final : public DropTargetHelper
+ {
+ private:
+ OTableWindowListBox& m_rParent;
+
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
+ {
+ return m_rParent.AcceptDrop(rEvt);
+ }
+
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
+ {
+ return m_rParent.ExecuteDrop(rEvt);
+ }
+
+ public:
+ TableWindowListBoxHelper(OTableWindowListBox& rParent, const css::uno::Reference<css::datatransfer::dnd::XDropTarget>& rDropTarget)
+ : DropTargetHelper(rDropTarget)
+ , m_rParent(rParent)
+ {
+ }
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TableWindowTitle.hxx b/dbaccess/source/ui/inc/TableWindowTitle.hxx
new file mode 100644
index 000000000..0a3779bd8
--- /dev/null
+++ b/dbaccess/source/ui/inc/TableWindowTitle.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+
+namespace dbaui
+{
+ class OTableWindow;
+ class OTableWindowTitle final : public InterimItemWindow
+ {
+ VclPtr<OTableWindow> m_pTabWin;
+ std::unique_ptr<weld::Label> m_xLabel;
+ std::unique_ptr<weld::Image> m_xImage;
+
+ DECL_LINK(MousePressHdl, const MouseEvent&, bool);
+
+ public:
+ OTableWindowTitle( OTableWindow* pParent );
+ virtual ~OTableWindowTitle() override;
+ virtual void dispose() override;
+
+ weld::Label& GetLabel() { return *m_xLabel; }
+ weld::Image& GetImage() { return *m_xImage; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TablesSingleDlg.hxx b/dbaccess/source/ui/inc/TablesSingleDlg.hxx
new file mode 100644
index 000000000..c75fa1eb3
--- /dev/null
+++ b/dbaccess/source/ui/inc/TablesSingleDlg.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/basedlgs.hxx>
+#include "IItemSetHelper.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <memory>
+
+namespace com::sun::star {
+ namespace beans {
+ class XPropertySet;
+ }
+ namespace uno {
+ class XComponentContext;
+ }
+}
+
+namespace dbaui
+{
+class ODbDataSourceAdministrationHelper;
+ // OTableSubscriptionDialog
+ class OTableSubscriptionDialog : public SfxSingleTabDialogController, public IItemSetHelper
+ {
+ std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl;
+ bool m_bStopExecution; // set when the dialog should not be executed
+
+ std::unique_ptr<SfxItemSet> m_pOutSet;
+ public:
+
+ OTableSubscriptionDialog(weld::Window* pParent
+ ,const SfxItemSet* _pItems
+ ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ ,const css::uno::Any& _aDataSourceName
+ );
+ virtual ~OTableSubscriptionDialog() override;
+
+ // forwards from ODbDataSourceAdministrationHelper
+ void successfullyConnected();
+ bool getCurrentSettings(css::uno::Sequence< css::beans::PropertyValue >& _rDriverParams);
+ void clearPassword();
+ css::uno::Reference< css::beans::XPropertySet > const & getCurrentDataSource();
+ void endExecution() { m_bStopExecution = true; }
+
+ virtual const SfxItemSet* getOutputSet() const override;
+ virtual SfxItemSet* getWriteOutputSet() override;
+
+ virtual short run() override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TokenWriter.hxx b/dbaccess/source/ui/inc/TokenWriter.hxx
new file mode 100644
index 000000000..82e36240f
--- /dev/null
+++ b/dbaccess/source/ui/inc/TokenWriter.hxx
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "commontypes.hxx"
+
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <vcl/weld.hxx>
+
+namespace com::sun::star {
+ namespace sdbc{
+ class XRowUpdate;
+ }
+}
+
+class SvStream;
+
+namespace dbaui
+{
+ // ODatabaseImportExport base class for import/export
+ class ODatabaseExport;
+ class ODatabaseImportExport : public ::cppu::WeakImplHelper< css::lang::XEventListener>
+ {
+ protected:
+ css::uno::Sequence< css::uno::Any> m_aSelection;
+ bool m_bBookmarkSelection;
+ SvStream* m_pStream;
+ css::awt::FontDescriptor m_aFont;
+ css::uno::Reference< css::beans::XPropertySet > m_xObject; // table/query
+ SharedConnection m_xConnection;
+ css::uno::Reference< css::sdbc::XResultSet > m_xResultSet;
+ css::uno::Reference< css::sdbc::XRow > m_xRow;
+ css::uno::Reference< css::sdbcx::XRowLocate > m_xRowLocate;
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xResultSetMetaData;
+ css::uno::Reference< css::container::XIndexAccess > m_xRowSetColumns;
+ css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ OUString m_sName;
+
+ //for transfor the tablename
+ OUString m_sDefaultTableName;
+
+ OUString m_sDataSourceName;
+ sal_Int32 m_nCommandType;
+ bool m_bNeedToReInitialize;
+
+ rtl_TextEncoding m_eDestEnc;
+ bool m_bInInitialize;
+ bool m_bCheckOnly;
+
+ // export data
+ ODatabaseImportExport( const svx::ODataAccessDescriptor& _aDataDescriptor,
+ const css::uno::Reference< css::uno::XComponentContext >& _rM,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF);
+
+ // import data
+ ODatabaseImportExport( const SharedConnection& _rxConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rM);
+
+ virtual ~ODatabaseImportExport() override;
+
+ virtual void initialize();
+ public:
+ void setStream(SvStream* _pStream){ m_pStream = _pStream; }
+
+ //for set the tablename
+ void setSTableName(const OUString &_sTableName){ m_sDefaultTableName = _sTableName; }
+
+ virtual bool Write(); // Export
+ virtual bool Read(); // Import
+
+ void initialize(const svx::ODataAccessDescriptor& _aDataDescriptor);
+ void dispose();
+
+ void enableCheckOnly() { m_bCheckOnly = true; }
+ bool isCheckEnabled() const { return m_bCheckOnly; }
+
+ private:
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ void impl_initFromDescriptor( const svx::ODataAccessDescriptor& _aDataDescriptor, bool _bPlusDefaultInit );
+ };
+
+ // RTF Import and Export
+
+ class ORTFImportExport : public ODatabaseImportExport
+ {
+ void appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk);
+ public:
+ // export data
+ ORTFImportExport( const svx::ODataAccessDescriptor& _aDataDescriptor,
+ const css::uno::Reference< css::uno::XComponentContext >& _rM,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF)
+ : ODatabaseImportExport(_aDataDescriptor,_rM,_rxNumberF) {};
+
+ // import data
+ ORTFImportExport( const SharedConnection& _rxConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rM)
+ : ODatabaseImportExport(_rxConnection,_rxNumberF,_rM)
+ {}
+
+ virtual bool Write() override;
+ virtual bool Read() override;
+ };
+ // HTML Import and Export
+ #define SBA_HTML_FONTSIZES 7
+ const sal_Int16 nIndentMax = 23;
+ class OHTMLImportExport : public ODatabaseImportExport
+ {
+ static const sal_Int16 nCellSpacing;
+ static const char sIndentSource[];
+ char sIndent[nIndentMax+1];
+ sal_Int16 m_nIndent;
+ #if OSL_DEBUG_LEVEL > 0
+ bool m_bCheckFont;
+ #endif
+
+ void WriteHeader();
+ void WriteBody();
+ void WriteTables();
+ void WriteCell( sal_Int32 nFormat,sal_Int32 nWidthPixel,sal_Int32 nHeightPixel,const char* pChar,const OUString& rValue,const char* pHtmlTag);
+ void IncIndent( sal_Int16 nVal );
+ const char* GetIndentStr() const { return sIndent; }
+ void FontOn();
+ inline void FontOff();
+
+ public:
+ // export data
+ OHTMLImportExport( const svx::ODataAccessDescriptor& _aDataDescriptor,
+ const css::uno::Reference< css::uno::XComponentContext >& _rM,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF);
+ // import data
+ OHTMLImportExport( const SharedConnection& _rxConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rM)
+ : ODatabaseImportExport(_rxConnection,_rxNumberF,_rM)
+ , m_nIndent(0)
+ {}
+
+ virtual bool Write() override;
+ virtual bool Read() override;
+
+ };
+ // normal RowSet Import and Export
+
+ class ORowSetImportExport : public ODatabaseImportExport
+ {
+ std::vector<sal_Int32> m_aColumnMapping;
+ std::vector<sal_Int32> m_aColumnTypes;
+ css::uno::Reference< css::sdbc::XResultSetUpdate > m_xTargetResultSetUpdate;
+ css::uno::Reference< css::sdbc::XRowUpdate > m_xTargetRowUpdate;
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xTargetResultSetMetaData;
+ weld::Window* m_pParent;
+ bool m_bAlreadyAsked;
+
+ bool insertNewRow();
+ protected:
+ virtual void initialize() override;
+
+ public:
+ // export data
+ ORowSetImportExport(weld::Window* pParent,
+ const css::uno::Reference< css::sdbc::XResultSetUpdate >& xResultSetUpdate,
+ const svx::ODataAccessDescriptor& aDataDescriptor,
+ const css::uno::Reference< css::uno::XComponentContext >& rM);
+
+ virtual bool Write() override;
+ virtual bool Read() override;
+
+ private:
+ using ODatabaseImportExport::initialize;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/TypeInfo.hxx b/dbaccess/source/ui/inc/TypeInfo.hxx
new file mode 100644
index 000000000..e9958e8e8
--- /dev/null
+++ b/dbaccess/source/ui/inc/TypeInfo.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <map>
+#include <memory>
+
+namespace dbaui
+{
+// Based on these ids the language dependent OUString are fetched from the resource
+const sal_uInt16 TYPE_UNKNOWN = 0;
+const sal_uInt16 TYPE_TEXT = 1;
+const sal_uInt16 TYPE_NUMERIC = 2;
+const sal_uInt16 TYPE_DATETIME = 3;
+const sal_uInt16 TYPE_DATE = 4;
+const sal_uInt16 TYPE_TIME = 5;
+const sal_uInt16 TYPE_BOOL = 6;
+const sal_uInt16 TYPE_CURRENCY = 7;
+const sal_uInt16 TYPE_MEMO = 8;
+const sal_uInt16 TYPE_COUNTER = 9;
+const sal_uInt16 TYPE_IMAGE = 10;
+const sal_uInt16 TYPE_CHAR = 11;
+const sal_uInt16 TYPE_DECIMAL = 12;
+const sal_uInt16 TYPE_BINARY = 13;
+const sal_uInt16 TYPE_VARBINARY = 14;
+const sal_uInt16 TYPE_BIGINT = 15;
+const sal_uInt16 TYPE_DOUBLE = 16;
+const sal_uInt16 TYPE_FLOAT = 17;
+const sal_uInt16 TYPE_REAL = 18;
+const sal_uInt16 TYPE_INTEGER = 19;
+const sal_uInt16 TYPE_SMALLINT = 20;
+const sal_uInt16 TYPE_TINYINT = 21;
+const sal_uInt16 TYPE_SQLNULL = 22;
+const sal_uInt16 TYPE_OBJECT = 23;
+const sal_uInt16 TYPE_DISTINCT = 24;
+const sal_uInt16 TYPE_STRUCT = 25;
+const sal_uInt16 TYPE_ARRAY = 26;
+const sal_uInt16 TYPE_BLOB = 27;
+const sal_uInt16 TYPE_CLOB = 28;
+const sal_uInt16 TYPE_REF = 29;
+const sal_uInt16 TYPE_OTHER = 30;
+const sal_uInt16 TYPE_BIT = 31;
+
+ class OTypeInfo
+ {
+ public:
+ OUString aUIName; // the name which is the user see (a combination of resource text and aTypeName)
+ OUString aTypeName; // name of type in database
+ OUString aCreateParams; // parameter for creation
+ OUString aLocalTypeName;
+
+ sal_Int32 nPrecision; // length of type
+ sal_Int32 nNumPrecRadix; // indicating the radix, which is usually 2 or 10
+ sal_Int32 nType; // database type
+
+ sal_Int16 nMaximumScale; // decimal places after decimal point
+ sal_Int16 nMinimumScale; // min decimal places after decimal point
+
+ sal_Int16 nSearchType; // if it is possible to search for type
+
+ bool bCurrency : 1, // currency
+ bAutoIncrement : 1, // if automatic incrementing field
+ bNullable : 1; // if field can be NULL
+
+ OTypeInfo()
+ :nPrecision(0)
+ ,nNumPrecRadix(10)
+ ,nType(css::sdbc::DataType::OTHER)
+ ,nMaximumScale(0)
+ ,nMinimumScale(0)
+ ,nSearchType(css::sdbc::ColumnSearch::FULL)
+ ,bCurrency(false)
+ ,bAutoIncrement(false)
+ ,bNullable(true)
+ {}
+ const OUString& getDBName() const { return aTypeName; }
+
+ };
+
+ typedef std::shared_ptr<OTypeInfo> TOTypeInfoSP;
+ typedef std::multimap<sal_Int32,TOTypeInfoSP> OTypeInfoMap;
+ /** return the most suitable typeinfo for a requested type
+ @param _rTypeInfo contains a map of type to typeinfo
+ @param _nType the requested type
+ @param _sTypeName the typename
+ @param _sCreateParams the create params
+ @param _nPrecision the precision
+ @param _nScale the scale
+ @param _bAutoIncrement if it is an auto increment
+ @param _brForceToType true when type was found which has some differences
+ */
+ TOTypeInfoSP getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo,
+ sal_Int32 _nType,
+ const OUString& _sTypeName,
+ const OUString& _sCreateParams,
+ sal_Int32 _nPrecision,
+ sal_Int32 _nScale,
+ bool _bAutoIncrement,
+ bool& _brForceToType);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/UITools.hxx b/dbaccess/source/ui/inc/UITools.hxx
new file mode 100644
index 000000000..c622c73f6
--- /dev/null
+++ b/dbaccess/source/ui/inc/UITools.hxx
@@ -0,0 +1,396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/dbexception.hxx>
+#include <comphelper/stl_types.hxx>
+#include "TypeInfo.hxx"
+#include <editeng/svxenum.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <connectivity/dbtools.hxx>
+#include <unotools/resmgr.hxx>
+
+#include <memory>
+#include <string_view>
+
+#define RET_ALL 100
+
+// we only need forward decl here
+namespace com::sun::star {
+
+ namespace beans { class XPropertySet;}
+ namespace container
+ {
+ class XNameAccess;
+ class XHierarchicalNameContainer;
+ }
+ namespace lang
+ {
+ class XEventListener;
+ }
+ namespace awt
+ {
+ struct FontDescriptor;
+ class XWindow;
+ }
+ namespace sdbc
+ {
+ class XDatabaseMetaData;
+ class XConnection;
+ }
+ namespace util
+ {
+ struct URL;
+ class XNumberFormatter;
+ }
+ namespace ucb { class XContent; }
+ namespace uno { class XComponentContext; }
+}
+
+namespace svt
+{
+ class EditBrowseBox;
+}
+
+namespace vcl { class Window; }
+namespace weld {
+ class Widget;
+ class Window;
+}
+class ToolBox;
+namespace vcl { class Font; }
+class SvNumberFormatter;
+class SfxFilter;
+
+namespace dbaui
+{
+
+ /** creates a new connection and appends the eventlistener
+ @param _rsDataSourceName name of the datasource
+ @param _xDatabaseContext the database context
+ @param _rxContext the UNO component context
+ @param _rEvtLst the eventlistener which will be added to the new created connection
+ @param _rOUTConnection this parameter will be filled with the new created connection
+ @return SQLExceptionInfo contains a SQLException, SQLContext or a SQLWarning when they araised else .isValid() will return false
+ */
+ ::dbtools::SQLExceptionInfo createConnection(
+ const OUString& _rsDataSourceName,
+ const css::uno::Reference< css::container::XNameAccess >& _xDatabaseContext,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ css::uno::Reference< css::lang::XEventListener> const & _rEvtLst,
+ css::uno::Reference< css::sdbc::XConnection>& _rOUTConnection );
+ /** creates a new connection and appends the eventlistener
+ @param _xDataSource the datasource
+ @param _rxContext the UNO component context
+ @param _rEvtLst the eventlistener which will be added to the new created connection
+ @param _rOUTConnection this parameter will be filled with the new created connection
+ @return SQLExceptionInfo contains a SQLException, SQLContext or a SQLWarning when they araised else .isValid() will return false
+ */
+ ::dbtools::SQLExceptionInfo createConnection(
+ const css::uno::Reference< css::beans::XPropertySet >& _xDataSource,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ css::uno::Reference< css::lang::XEventListener> const & _rEvtLst,
+ css::uno::Reference< css::sdbc::XConnection>& _rOUTConnection );
+
+ /** fills a map and a vector with localized type names
+ @param _rxConnection the connection to access the metadata
+ @param _rsTypeNames a list of localized type names separated with ';'
+ @param _rTypeInfoMap the filled map with the type names
+ @param _rTypeInfoIters the vector filled with map iterators
+ */
+ void fillTypeInfo( const css::uno::Reference< css::sdbc::XConnection>& _rxConnection,
+ std::u16string_view _rsTypeNames,
+ OTypeInfoMap& _rTypeInfoMap,
+ std::vector<OTypeInfoMap::iterator>& _rTypeInfoIters);
+
+ /** fill a column with data of a field description
+ @param _rxColumn the column which should be filled
+ @param _pFieldDesc the source of the data
+ */
+ class OFieldDescription;
+ void setColumnProperties( const css::uno::Reference< css::beans::XPropertySet>& _rxColumn,
+ const OFieldDescription* _pFieldDesc);
+
+ OUString createDefaultName( const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData,
+ const css::uno::Reference< css::container::XNameAccess>& _xTables,
+ const OUString& _sName);
+
+ /** checks if the given name exists in the database context
+ */
+ bool checkDataSourceAvailable( const OUString& _sDataSourceName,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ /** maps SvxCellHorJustify to css::awt::TextAlign
+ @param SvxCellHorJustify& _eAlignment
+ @return the corresponding css::awt::TextAlign
+ */
+ sal_Int32 mapTextAlign(const SvxCellHorJustify& _eAlignment);
+
+ /** retrieves a data source given by name or URL, and displays an error if this fails
+
+ Any <type scope="css::sdbc">SQLException</type>s which occur will be displayed.
+ Additionally, and Exceptions which indicate a data source name pointing to a non-existent database
+ URL will also be denoted. Yet more additionally, and other exceptions will be forwarded to
+ a <type scope="css::sdb">InteractionHandler</type>.
+
+ @param _rDataSourceName
+ the URL of the database document, or the name of a registered data source
+ @param _pErrorMessageParent
+ the window to use as parent for error messages
+ @param _rxContext
+ a service factory to use for components to be created
+ @param _pErrorInfo
+ takes the error info in case of failure. If <NULL/>, the error is displayed to the user.
+ */
+ css::uno::Reference< css::sdbc::XDataSource >
+ getDataSourceByName(
+ const OUString& _rDataSourceName,
+ weld::Window* _pErrorMessageParent,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ ::dbtools::SQLExceptionInfo* _pErrorInfo
+ );
+
+ /** returns either the model when data source is given as parameter,
+ or returns a data source when a model is given.
+ @param _xObject Either a data source or a model.
+ */
+ css::uno::Reference< css::uno::XInterface > getDataSourceOrModel(const css::uno::Reference< css::uno::XInterface >& _xObject);
+
+ /** maps css::awt::TextAlign to SvxCellHorJustify
+ @param css::awt::TextAlign& _nAlignment
+ @return the corresponding SvxCellHorJustify
+ */
+ SvxCellHorJustify mapTextJustify(sal_Int32 _nAlignment);
+
+ /** call the format dialog and set the selected format at the column
+ @param _xAffectedCol Font to be converted
+ @param _xField Font to be converted
+ */
+ void callColumnFormatDialog(const css::uno::Reference< css::beans::XPropertySet>& _xAffectedCol,
+ const css::uno::Reference< css::beans::XPropertySet>& _xField,
+ SvNumberFormatter* _pFormatter,
+ weld::Widget* _pParent);
+
+ /** second variant of the function before
+ */
+ bool callColumnFormatDialog(weld::Widget* _pParent,
+ SvNumberFormatter* _pFormatter,
+ sal_Int32 _nDataType,
+ sal_Int32& _nFormatKey,
+ SvxCellHorJustify& _eJustify,
+ bool _bHasFormat);
+ /** append a name to tablefilter of a datasource
+ @param xConnection the connection is need to get the datasource
+ @param rName the name which should be appended
+ @param rxContext needed to check if datasource is available
+ @param pParent needed when an error must be shown
+ @return false when datsource is not available otherwise true
+ */
+ bool appendToFilter(const css::uno::Reference< css::sdbc::XConnection>& xConnection,
+ const OUString& rName,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ weld::Window* pParent);
+
+ /** notifySystemWindow adds or remove the given window _pToRegister at the Systemwindow found when search _pWindow.
+ @param _pWindow
+ The window which is used to search for the SystemWindow.
+ @param _pToRegister
+ The window which should be added or removed on the TaskPaneList.
+ @param _rMemFunc
+ The member function which should be called at the SystemWindow when found.
+ Possible values are:
+ ::comphelper::mem_fun(&TaskPaneList::AddWindow)
+ ::comphelper::mem_fun(&TaskPaneList::RemoveWindow)
+ */
+ void notifySystemWindow(vcl::Window const * _pWindow,
+ vcl::Window* _pToRegister,
+ const ::comphelper::mem_fun1_t<TaskPaneList,vcl::Window*>& _rMemFunc);
+
+ void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId );
+
+ /** check if SQL92 name checking is enabled
+ @param _xConnection
+ Used to get the datasource as parent from the connection.
+ @return
+ <TRUE/> if so otherwise <FALSE/>
+ */
+ bool isSQL92CheckEnabled(const css::uno::Reference< css::sdbc::XConnection>& _xConnection);
+
+ /** check if the alias name of the table should be added at select statements
+ @param _xConnection
+ Used to get the datasource as parent from the connection.
+ @return
+ <TRUE/> if so otherwise <FALSE/>
+ */
+ bool isAppendTableAliasEnabled(const css::uno::Reference< css::sdbc::XConnection>& _xConnection);
+
+ /** determines whether when generating SQL statements, AS should be placed before a table alias
+ */
+ bool generateAsBeforeTableAlias( const css::uno::Reference< css::sdbc::XConnection>& _rxConnection );
+
+ /** fills the bool and string value with information out of the datasource info property
+ @param _xDatasource
+ Asked for the properties.
+ @param _rAutoIncrementValueEnabled
+ <OUT/> Set to sal_True when the property was set in the datasource.
+ @param _rsAutoIncrementValue
+ <OUT/> Set to the value when the property was set in the datasource.
+ */
+ void fillAutoIncrementValue(const css::uno::Reference< css::beans::XPropertySet>& _xDatasource
+ ,bool& _rAutoIncrementValueEnabled
+ ,OUString& _rsAutoIncrementValue);
+
+ /** fills the bool and string value with information out of the datasource info property
+ @param _xConnection
+ Used to get the datasource as parent from the connection.
+ @param _rAutoIncrementValueEnabled
+ <OUT/> Set to sal_True when the property was set in the datasource.
+ @param _rsAutoIncrementValue
+ <OUT/> Set to the value when the property was set in the datasource.
+ */
+ void fillAutoIncrementValue(const css::uno::Reference< css::sdbc::XConnection>& _xConnection
+ ,bool& _rAutoIncrementValueEnabled
+ ,OUString& _rsAutoIncrementValue);
+
+ /** set the evaluation flag at the number formatter
+ @param _rxFormatter
+ */
+ void setEvalDateFormatForFormatter(css::uno::Reference< css::util::XNumberFormatter > const & _rxFormatter);
+
+ /** query for a type info which can be used to create a primary key column
+ @param _rTypeInfo
+ The map which contains all available types.
+ @return
+ The type info which can be used to create a primary key column.
+ */
+ TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo);
+
+ /** query for a specific type.
+ @param _nDataType
+ The type we are searching.
+ @param _rTypeInfo
+ The map which contains all available types.
+ @return
+ The type or <NULL/> if we can't find it.
+ */
+ TOTypeInfoSP queryTypeInfoByType(sal_Int32 _nDataType,const OTypeInfoMap& _rTypeInfo);
+
+ /** returns the configuration node name of user defined drivers.
+ @return
+ the configuration node name of user defined drivers.
+ */
+
+ /** returns the result of the user action when view the query dialog.
+ @param pParent
+ The parent of the dialog
+ @param pTitle
+ A string resource id for the text which will be displayed as title.
+ @param pText
+ A string resource id for the text which will be displayed above the buttons.
+ When the string contains a #1. This will be replaced by the name.
+ @param bAll
+ When set to <TRUE/>, the all button will be appended.
+ @param rName
+ The name of the object to ask for.
+ @return
+ RET_YES, RET_NO, RET_ALL
+ */
+ sal_Int32 askForUserAction(weld::Window* pParent, TranslateId pTitle, TranslateId pText, bool bAll, std::u16string_view rName);
+
+ /** creates a new view from a query or table
+ @param _sName
+ The name of the view to be created.
+ @param _xConnection
+ The source connection.
+ @param _xSourceObject
+ The object for which a view should be created.
+ @return
+ The created view.
+ */
+ css::uno::Reference< css::beans::XPropertySet> createView( const OUString& _sName
+ ,const css::uno::Reference< css::sdbc::XConnection >& _xConnection
+ ,const css::uno::Reference< css::beans::XPropertySet>& _xSourceObject);
+
+ /** creates a view with the given command
+ */
+ css::uno::Reference< css::beans::XPropertySet> createView(
+ const OUString& _rName,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const OUString& _rCommand
+ );
+
+ /** returns the stripped database name.
+ @param _xDataSource
+ The data source
+ @param _rsDatabaseName
+ Will be filled with the original data source if it is empty.
+ @return
+ The stripped database name either the registered name or if it is a file url the last segment.
+ */
+ OUString getStrippedDatabaseName(const css::uno::Reference< css::beans::XPropertySet>& _xDataSource
+ ,OUString& _rsDatabaseName);
+
+ /** returns the standard database filter
+ @return
+ the filter
+ */
+ std::shared_ptr<const SfxFilter> getStandardDatabaseFilter();
+
+ /** opens a save dialog to store a form or report folder in the current hierarchy.
+ @param _pParent
+ The parent of the dialog.
+ @param _rxContext
+ a multi service factory which can be used to instantiate usual global services
+ @param _xNames
+ Where to insert the new object.
+ @param _sParentFolder
+ The name of the parent folder.
+ @param _bForm
+ <TRUE/> if a form should be inserted
+ @param _bCollection
+ A folder should be inserted
+ @param _xContent
+ The content which should be copied.
+ @param _bMove
+ if <TRUE/> the name of the content must be inserted without any change, otherwise not.
+ @return
+ <TRUE/> if the insert operation was successful, otherwise <FALSE/>.
+ */
+ bool insertHierarchyElement(
+ weld::Window* pParent,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const css::uno::Reference< css::container::XHierarchicalNameContainer>& _xNames,
+ const OUString& _sParentFolder,
+ bool _bForm,
+ bool _bCollection = true,
+ const css::uno::Reference< css::ucb::XContent>& _xContent = nullptr,
+ bool _bMove = false
+ );
+
+ /** creates a number formatter
+ @param _rxConnection
+ The connection is needed to create the formatter
+ @param _rxContext
+ The multi service factory
+ */
+ css::uno::Reference< css::util::XNumberFormatter > getNumberFormatter(const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,const css::uno::Reference< css::uno::XComponentContext >& _rxContext );
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/UserAdminDlg.hxx b/dbaccess/source/ui/inc/UserAdminDlg.hxx
new file mode 100644
index 000000000..941eab5fa
--- /dev/null
+++ b/dbaccess/source/ui/inc/UserAdminDlg.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+#include "IItemSetHelper.hxx"
+#include <memory>
+
+namespace com::sun::star {
+ namespace sdbc {
+ class XConnection;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+}
+
+namespace dbaui
+{
+ class ODbDataSourceAdministrationHelper;
+ // OUserAdminDlg
+
+ /** implements the user admin dialog
+ */
+ class OUserAdminDlg : public SfxTabDialogController, public IItemSetHelper, public IDatabaseSettingsDialog
+ {
+ weld::Window* m_pParent;
+ std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl;
+ SfxItemSet* m_pItemSet;
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ bool m_bOwnConnection;
+ protected:
+ virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override;
+ public:
+ OUserAdminDlg(weld::Window* pParent, SfxItemSet* pItems,
+ const css::uno::Reference< css::uno::XComponentContext >& rxORB,
+ const css::uno::Any& rDataSourceName,
+ const css::uno::Reference< css::sdbc::XConnection>& rConnection);
+
+ virtual ~OUserAdminDlg() override;
+
+ virtual const SfxItemSet* getOutputSet() const override;
+ virtual SfxItemSet* getWriteOutputSet() override;
+
+ virtual short run() override;
+
+ // forwards to ODbDataSourceAdministrationHelper
+ virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override;
+ virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override;
+ virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override;
+ virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override;
+ virtual void clearPassword() override;
+ virtual void saveDatasource() override;
+ virtual void setTitle(const OUString& _sTitle) override;
+ virtual void enableConfirmSettings( bool _bEnable ) override;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/WCPage.hxx b/dbaccess/source/ui/inc/WCPage.hxx
new file mode 100644
index 000000000..69dc96f14
--- /dev/null
+++ b/dbaccess/source/ui/inc/WCPage.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "WTabPage.hxx"
+
+namespace dbaui
+{
+ class OWizColumnSelect;
+ class OWizNormalExtend;
+ class OCopyTable final : public OWizardPage
+ {
+ bool m_bPKeyAllowed;
+ bool m_bUseHeaderAllowed;
+ sal_Int16 m_nOldOperation;
+
+ std::unique_ptr<weld::Entry> m_xEdTableName;
+ std::unique_ptr<weld::RadioButton> m_xRB_DefData;
+ std::unique_ptr<weld::RadioButton> m_xRB_Def;
+ std::unique_ptr<weld::RadioButton> m_xRB_View;
+ std::unique_ptr<weld::RadioButton> m_xRB_AppendData;
+ std::unique_ptr<weld::CheckButton> m_xCB_UseHeaderLine;
+ std::unique_ptr<weld::CheckButton> m_xCB_PrimaryColumn;
+ std::unique_ptr<weld::Label> m_xFT_KeyName;
+ std::unique_ptr<weld::Entry> m_xEdKeyName;
+
+ DECL_LINK( RadioChangeHdl, weld::Toggleable&, void );
+ DECL_LINK( KeyClickHdl, weld::Toggleable&, void );
+
+ bool checkAppendData();
+ void SetAppendDataRadio();
+
+ public:
+ virtual void Reset() override;
+ virtual void Activate() override;
+ virtual bool LeavePage() override;
+ virtual OUString GetTitle() const override ;
+
+ OCopyTable(weld::Container* pParent, OCopyTableWizard* pWizard);
+ virtual ~OCopyTable() override;
+
+ bool IsOptionDefData() const { return m_xRB_DefData->get_active(); }
+ bool IsOptionDef() const { return m_xRB_Def->get_active(); }
+ bool IsOptionView() const { return m_xRB_View->get_active(); }
+ OUString GetKeyName() const { return m_xEdKeyName->get_text(); }
+
+ void setCreateStyleAction();
+ void disallowViews()
+ {
+ m_xRB_View->set_sensitive(false);
+ }
+ void disallowUseHeaderLine()
+ {
+ m_bUseHeaderAllowed = false;
+ m_xCB_UseHeaderLine->set_sensitive(false);
+ }
+
+ void setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/WColumnSelect.hxx b/dbaccess/source/ui/inc/WColumnSelect.hxx
new file mode 100644
index 000000000..38b1317fd
--- /dev/null
+++ b/dbaccess/source/ui/inc/WColumnSelect.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "WTabPage.hxx"
+#include "WCopyTable.hxx"
+
+#include <comphelper/stl_types.hxx>
+
+namespace dbaui
+{
+ class OFieldDescription;
+
+ // Wizard Page: OWizColumnSelect
+
+ class OWizColumnSelect : public OWizardPage
+ {
+ std::unique_ptr<weld::TreeView> m_xOrgColumnNames; // left side
+ std::unique_ptr<weld::Button> m_xColumn_RH;
+ std::unique_ptr<weld::Button> m_xColumns_RH;
+ std::unique_ptr<weld::Button> m_xColumn_LH;
+ std::unique_ptr<weld::Button> m_xColumns_LH;
+ std::unique_ptr<weld::TreeView> m_xNewColumnNames; // right side
+
+ DECL_LINK( ButtonClickHdl, weld::Button&, void );
+ DECL_LINK( ListDoubleClickHdl, weld::TreeView&, bool );
+
+ static void clearListBox(weld::TreeView& _rListBox);
+ static void fillColumns(weld::TreeView const * pRight,
+ std::vector< OUString> &_rRightColumns);
+
+ void createNewColumn( weld::TreeView* _pListbox,
+ OFieldDescription const * _pSrcField,
+ std::vector< OUString>& _rRightColumns,
+ const OUString& _sColumnName,
+ std::u16string_view _sExtraChars,
+ sal_Int32 _nMaxNameLen,
+ const ::comphelper::UStringMixEqual& _aCase);
+
+ void moveColumn( weld::TreeView* _pRight,
+ weld::TreeView const * _pLeft,
+ std::vector< OUString>& _rRightColumns,
+ const OUString& _sColumnName,
+ std::u16string_view _sExtraChars,
+ sal_Int32 _nMaxNameLen,
+ const ::comphelper::UStringMixEqual& _aCase);
+
+ void enableButtons();
+
+ sal_Int32 adjustColumnPosition(weld::TreeView const * _pLeft,
+ std::u16string_view _sColumnName,
+ ODatabaseExport::TColumnVector::size_type nCurrentPos,
+ const ::comphelper::UStringMixEqual& _aCase);
+
+ public:
+ virtual void Reset ( ) override;
+ virtual void Activate() override;
+ virtual bool LeavePage() override;
+ virtual OUString GetTitle() const override ;
+
+ OWizColumnSelect(weld::Container* pParent, OCopyTableWizard* pWizard);
+ virtual ~OWizColumnSelect() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/WCopyTable.hxx b/dbaccess/source/ui/inc/WCopyTable.hxx
new file mode 100644
index 000000000..613311283
--- /dev/null
+++ b/dbaccess/source/ui/inc/WCopyTable.hxx
@@ -0,0 +1,413 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/stl_types.hxx>
+#include "TypeInfo.hxx"
+#include <vcl/roadmapwizard.hxx>
+#include "DExport.hxx"
+#include "WTabPage.hxx"
+#include "FieldDescriptions.hxx"
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <map>
+#include <algorithm>
+
+namespace dbaui
+{
+
+ class TColumnFindFunctor
+ {
+ public:
+ virtual bool operator()(const OUString& _sColumnName) const = 0;
+
+ protected:
+ ~TColumnFindFunctor() {}
+ };
+
+ class TExportColumnFindFunctor : public TColumnFindFunctor
+ {
+ ODatabaseExport::TColumns* m_pColumns;
+ public:
+ TExportColumnFindFunctor(ODatabaseExport::TColumns* _pColumns)
+ {
+ m_pColumns = _pColumns;
+ }
+
+ virtual ~TExportColumnFindFunctor() {}
+
+ bool operator()(const OUString& _sColumnName) const override
+ {
+ return m_pColumns->find(_sColumnName) != m_pColumns->end();
+ }
+ };
+
+ class TMultiListBoxEntryFindFunctor : public TColumnFindFunctor
+ {
+ ::comphelper::UStringMixEqual m_aCase;
+ std::vector< OUString>* m_pVector;
+ public:
+ TMultiListBoxEntryFindFunctor(std::vector< OUString>* _pVector,
+ const ::comphelper::UStringMixEqual& _aCase)
+ :m_aCase(_aCase)
+ ,m_pVector(_pVector)
+ {
+ }
+
+ virtual ~TMultiListBoxEntryFindFunctor() {}
+
+ bool operator()(const OUString& _sColumnName) const override
+ {
+ return std::any_of(m_pVector->begin(),m_pVector->end(),
+ [this, &_sColumnName](const OUString& lhs)
+ { return m_aCase(lhs, _sColumnName); });
+ }
+ };
+
+ // ICopyTableSourceObject
+ /** interface to an object to copy to another DB, using the OCopyTableWizard
+
+ when the wizard is used to copy an object to another DB, it usually requires
+ a sdbcx-level or sdb-level object (a css.sdbcx.Table or css.sdb.Query, that is).
+
+ However, to also support copying tables from sdbc-level connections, we allow to
+ work with the object name only. This implies some less features (like copying the
+ UI settings of a table is not done), but still allows to copy definition and data.
+ */
+ class ICopyTableSourceObject
+ {
+ public:
+ /// retrieves the fully qualified name of the object to copy
+ virtual OUString getQualifiedObjectName() const = 0;
+ /// determines whether the object is a view
+ virtual bool isView() const = 0;
+ /** copies the UI settings of the object to the given target object. Might be
+ ignored by implementations which do not have Ui settings.
+ */
+ virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const = 0;
+ /// retrieves the column names of the to-be-copied object
+ virtual css::uno::Sequence< OUString >
+ getColumnNames() const = 0;
+ /// retrieves the names of the primary keys of the to-be-copied object
+ virtual css::uno::Sequence< OUString >
+ getPrimaryKeyColumnNames() const = 0;
+ /// creates a OFieldDescription for the given column of the to-be-copied object
+ virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const = 0;
+ /// returns the SELECT statement which can be used to retrieve the data of the to-be-copied object
+ virtual OUString getSelectStatement() const = 0;
+
+ /** copies the filter and sorting
+ *
+ * \return
+ */
+ virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const = 0;
+
+ /** returns the prepared statement which can be used to retrieve the data of the to-be-copied object
+
+ The default implementation of this method will simply prepare a statement with the return value
+ of ->getSelectStatement.
+ */
+ virtual ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement >
+ getPreparedSelectStatement() const = 0;
+
+ virtual ~ICopyTableSourceObject();
+ };
+
+ // ObjectCopySource
+ class ObjectCopySource : public ICopyTableSourceObject
+ {
+ private:
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ css::uno::Reference< css::beans::XPropertySet > m_xObject;
+ css::uno::Reference< css::beans::XPropertySetInfo > m_xObjectPSI;
+ css::uno::Reference< css::container::XNameAccess > m_xObjectColumns;
+
+ public:
+ ObjectCopySource(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxObject
+ );
+
+ // ICopyTableSourceObject overridables
+ virtual OUString getQualifiedObjectName() const override;
+ virtual bool isView() const override;
+ virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
+ virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
+ virtual css::uno::Sequence< OUString >
+ getColumnNames() const override;
+ virtual css::uno::Sequence< OUString >
+ getPrimaryKeyColumnNames() const override;
+ virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override;
+ virtual OUString getSelectStatement() const override;
+ virtual ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement >
+ getPreparedSelectStatement() const override;
+ };
+
+ // NamedTableCopySource
+ class NamedTableCopySource : public ICopyTableSourceObject
+ {
+ private:
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ OUString m_sTableName;
+ OUString m_sTableCatalog;
+ OUString m_sTableSchema;
+ OUString m_sTableBareName;
+ std::vector< OFieldDescription > m_aColumnInfo;
+ ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > m_xStatement;
+
+ public:
+ NamedTableCopySource(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const OUString& _rTableName
+ );
+
+ // ICopyTableSourceObject overridables
+ virtual OUString getQualifiedObjectName() const override;
+ virtual bool isView() const override;
+ virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
+ virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
+ virtual css::uno::Sequence< OUString >
+ getColumnNames() const override;
+ virtual css::uno::Sequence< OUString >
+ getPrimaryKeyColumnNames() const override;
+ virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override;
+ virtual OUString getSelectStatement() const override;
+ virtual ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement >
+ getPreparedSelectStatement() const override;
+
+ private:
+ void impl_ensureColumnInfo_throw();
+ ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > const &
+ impl_ensureStatement_throw();
+ };
+
+ // Wizard Dialog
+ class OCopyTableWizard : public vcl::RoadmapWizardMachine
+ {
+ friend class OWizColumnSelect;
+ friend class OWizTypeSelect;
+ friend class OWizTypeSelectControl;
+ friend class OCopyTable;
+ friend class OWizNameMatching;
+
+ public:
+ typedef std::map<OUString, OUString, ::comphelper::UStringMixLess> TNameMapping;
+
+ enum Wizard_Button_Style
+ {
+ WIZARD_NEXT,
+ WIZARD_PREV,
+ WIZARD_FINISH,
+
+ WIZARD_NONE
+ };
+
+ private:
+ ODatabaseExport::TColumns m_vDestColumns; // contains the columns
+ ODatabaseExport::TColumnVector m_aDestVec; // the order to insert the columns
+ ODatabaseExport::TColumns m_vSourceColumns;
+ ODatabaseExport::TColumnVector m_vSourceVec;
+
+ OTypeInfoMap m_aTypeInfo;
+ std::vector<OTypeInfoMap::iterator> m_aTypeInfoIndex;
+ OTypeInfoMap m_aDestTypeInfo;
+ std::vector<OTypeInfoMap::iterator> m_aDestTypeInfoIndex;
+ TNameMapping m_mNameMapping;
+
+ ODatabaseExport::TPositions m_vColumnPositions;
+ std::vector<sal_Int32> m_vColumnTypes;
+
+ css::uno::Reference< css::sdbc::XConnection > m_xDestConnection;
+
+ const ICopyTableSourceObject& m_rSourceObject;
+
+ css::uno::Reference< css::util::XNumberFormatter > m_xFormatter;
+ css::uno::Reference< css::uno::XComponentContext> m_xContext;
+ css::uno::Reference< css::task::XInteractionHandler> m_xInteractionHandler;
+
+ OUString m_sTypeNames; // these type names are the ones out of the resource file
+ sal_uInt32 m_nPageCount;
+ bool m_bDeleteSourceColumns;
+ bool m_bInterConnectionCopy; // are we copying between different connections?
+
+ css::lang::Locale m_aLocale;
+ OUString m_sName; // for a table the name is composed
+ OUString m_sSourceName;
+ OUString m_aKeyName;
+ TOTypeInfoSP m_pTypeInfo; // default type
+ bool m_bAddPKFirstTime;
+ sal_Int16 m_nOperation;
+ Wizard_Button_Style m_ePressed;
+ bool m_bCreatePrimaryKeyColumn;
+ bool m_bUseHeaderLine;
+
+ private:
+ DECL_LINK( ImplPrevHdl, weld::Button&, void );
+ DECL_LINK( ImplNextHdl, weld::Button&, void);
+ DECL_LINK( ImplOKHdl, weld::Button&, void );
+ bool CheckColumns(sal_Int32& _rnBreakPos);
+ void loadData( const ICopyTableSourceObject& _rSourceObject,
+ ODatabaseExport::TColumns& _rColumns,
+ ODatabaseExport::TColumnVector& _rColVector );
+ void construct();
+ // need for table creation
+ static void appendColumns( css::uno::Reference< css::sdbcx::XColumnsSupplier> const & _rxColSup, const ODatabaseExport::TColumnVector* _pVec, bool _bKeyColumns = false );
+ static void appendKey(css::uno::Reference< css::sdbcx::XKeysSupplier> const & _rxSup,const ODatabaseExport::TColumnVector* _pVec);
+ // checks if the type is supported in the destination database
+ bool supportsType(sal_Int32 _nDataType,sal_Int32& _rNewDataType);
+
+ virtual std::unique_ptr<BuilderPage> createPage(vcl::WizardTypes::WizardState /*nState*/) override
+ {
+ assert(false);
+ return nullptr;
+ }
+
+ virtual void ActivatePage() override;
+
+ sal_uInt16 GetCurLevel() const { return getCurrentState(); }
+
+ weld::Container* CreatePageContainer();
+
+ public:
+ // used for copy tables or queries
+ OCopyTableWizard(
+ weld::Window * pParent,
+ const OUString& _rDefaultName,
+ sal_Int16 _nOperation,
+ const ICopyTableSourceObject& _rSourceObject,
+ const css::uno::Reference< css::sdbc::XConnection >& _xSourceConnection,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const css::uno::Reference< css::task::XInteractionHandler>& _xInteractionHandler
+ );
+
+ // used for importing rtf/html sources
+ OCopyTableWizard(
+ weld::Window* pParent,
+ const OUString& _rDefaultName,
+ sal_Int16 _nOperation,
+ ODatabaseExport::TColumns&& _rDestColumns,
+ const ODatabaseExport::TColumnVector& _rSourceColVec,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _xFormatter,
+ TypeSelectionPageFactory _pTypeSelectionPageFactory,
+ SvStream& _rTypeSelectionPageArg,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext
+ );
+
+ virtual ~OCopyTableWizard() override;
+
+ virtual bool DeactivatePage() override;
+ weld::Button& GetOKButton() { return *m_xFinish; }
+ Wizard_Button_Style GetPressedButton() const { return m_ePressed; }
+ void EnableNextButton(bool bEnable);
+ void AddWizardPage(std::unique_ptr<OWizardPage> xPage); // delete page from OCopyTableWizard
+ void CheckButtons(); // checks which button can be disabled, enabled
+
+ // returns a vector where the position of a column and if the column is in the selection
+ // when not the value is COLUMN_POSITION_NOT_FOUND.
+ const ODatabaseExport::TPositions& GetColumnPositions() const { return m_vColumnPositions; }
+ const std::vector<sal_Int32>& GetColumnTypes() const { return m_vColumnTypes; }
+ bool UseHeaderLine() const { return m_bUseHeaderLine; }
+ void setUseHeaderLine(bool _bUseHeaderLine) { m_bUseHeaderLine = _bUseHeaderLine; }
+
+ void insertColumn(sal_Int32 _nPos,OFieldDescription* _pField);
+
+ /** replaces a field description with another one. The name must not be known so far.
+ @param _nPos
+ The pos inside the vector, 0 based.
+ @param _pField
+ The field to set.
+ @param _sOldName
+ The name of column to be replaced.
+ */
+ void replaceColumn(sal_Int32 _nPos,OFieldDescription* _pField,const OUString& _sOldName);
+
+ /** returns whether a primary key should be created in the target database
+ */
+ bool shouldCreatePrimaryKey() const { return m_bCreatePrimaryKeyColumn;}
+ void setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName );
+
+ static bool supportsPrimaryKey( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection );
+ bool supportsPrimaryKey() const { return supportsPrimaryKey( m_xDestConnection ); }
+
+ static bool supportsViews( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection );
+ bool supportsViews() const { return supportsViews( m_xDestConnection ); }
+
+ /** returns the name of the primary key
+ @return
+ The name of the primary key.
+ */
+ const OUString& getPrimaryKeyName() const { return m_aKeyName; }
+
+ const OTypeInfoMap& getTypeInfo() const { return m_aTypeInfo; }
+
+ TOTypeInfoSP const & getDestTypeInfo(sal_Int32 _nPos) const { return m_aDestTypeInfoIndex[_nPos]->second; }
+ const OTypeInfoMap& getDestTypeInfo() const { return m_aDestTypeInfo; }
+
+ const css::lang::Locale& GetLocale() const { return m_aLocale; }
+ const css::uno::Reference< css::util::XNumberFormatter >& GetFormatter() const { return m_xFormatter; }
+ const css::uno::Reference< css::uno::XComponentContext>& GetComponentContext() const { return m_xContext; }
+
+ const ODatabaseExport::TColumns& getSourceColumns() const{ return m_vSourceColumns; }
+ const ODatabaseExport::TColumnVector& getSrcVector() const { return m_vSourceVec; }
+ ODatabaseExport::TColumns& getDestColumns() { return m_vDestColumns; }
+ const ODatabaseExport::TColumnVector& getDestVector() const { return m_aDestVec; }
+ const OUString& getName() const { return m_sName; }
+
+ /** clears the dest vectors
+ */
+ void clearDestColumns();
+
+ css::uno::Reference< css::beans::XPropertySet > returnTable();
+ css::uno::Reference< css::beans::XPropertySet > getTable() const;
+ css::uno::Reference< css::beans::XPropertySet > createTable();
+ css::uno::Reference< css::beans::XPropertySet > createView() const;
+ sal_Int32 getMaxColumnNameLength() const;
+
+ void setOperation( const sal_Int16 _nOperation );
+ sal_Int16 getOperation() const { return m_nOperation;}
+
+ OUString convertColumnName( const TColumnFindFunctor& _rCmpFunctor,
+ const OUString& _sColumnName,
+ std::u16string_view _sExtraChars,
+ sal_Int32 _nMaxNameLen);
+ TOTypeInfoSP convertType(const TOTypeInfoSP&_pType, bool& _bNotConvert);
+
+ OUString createUniqueName(const OUString& _sName);
+
+ // displays an error message that a column type is not supported
+ void showColumnTypeNotSupported(std::u16string_view _rColumnName);
+
+ void removeColumnNameFromNameMap(const OUString& _sName);
+ void showError(const OUString& _sErrorMessage);
+ void showError(const css::uno::Any& _aError);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/WExtendPages.hxx b/dbaccess/source/ui/inc/WExtendPages.hxx
new file mode 100644
index 000000000..7d75f2cc1
--- /dev/null
+++ b/dbaccess/source/ui/inc/WExtendPages.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "WTypeSelect.hxx"
+
+class SvStream;
+namespace dbaui
+{
+ class OCopyTableWizard;
+
+ // Wizard Page: OWizHTMLExtend
+ class OWizHTMLExtend : public OWizTypeSelect
+ {
+ protected:
+ virtual void createReaderAndCallParser(sal_Int32 _nRows) override;
+ public:
+ OWizHTMLExtend(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rStream)
+ : OWizTypeSelect(pPage, pWizard, &rStream)
+ {
+ }
+
+ static std::unique_ptr<OWizTypeSelect> Create(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rInput ) { return std::make_unique<OWizHTMLExtend>(pPage, pWizard, rInput); }
+ };
+ // Wizard Page: OWizRTFExtend
+ class OWizRTFExtend : public OWizTypeSelect
+ {
+ protected:
+ virtual void createReaderAndCallParser(sal_Int32 _nRows) override;
+ public:
+ OWizRTFExtend(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rStream)
+ : OWizTypeSelect(pPage, pWizard, &rStream)
+ {
+ }
+
+ static std::unique_ptr<OWizTypeSelect> Create(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rInput) { return std::make_unique<OWizRTFExtend>(pPage, pWizard, rInput); }
+ };
+
+ // Wizard Page: OWizNormalExtend
+ class OWizNormalExtend : public OWizTypeSelect
+ {
+ protected:
+ virtual void createReaderAndCallParser(sal_Int32 _nRows) override;
+ public:
+ OWizNormalExtend(weld::Container* pPage, OCopyTableWizard* pWizard)
+ : OWizTypeSelect(pPage, pWizard)
+ {
+ EnableAuto(false);
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/WNameMatch.hxx b/dbaccess/source/ui/inc/WNameMatch.hxx
new file mode 100644
index 000000000..d108c043c
--- /dev/null
+++ b/dbaccess/source/ui/inc/WNameMatch.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "WTabPage.hxx"
+#include "DExport.hxx"
+#include "WCopyTable.hxx"
+
+namespace dbaui
+{
+ // Wizard Page: OWizNameMatching
+ // Name matching for data appending
+ class OWizNameMatching : public OWizardPage
+ {
+ std::unique_ptr<weld::Label> m_xTABLE_LEFT;
+ std::unique_ptr<weld::Label> m_xTABLE_RIGHT;
+ std::unique_ptr<weld::TreeView> m_xCTRL_LEFT; // left side
+ std::unique_ptr<weld::TreeView> m_xCTRL_RIGHT; // right side
+ std::unique_ptr<weld::Button> m_xColumn_up;
+ std::unique_ptr<weld::Button> m_xColumn_down;
+ std::unique_ptr<weld::Button> m_xColumn_up_right;
+ std::unique_ptr<weld::Button> m_xColumn_down_right;
+ std::unique_ptr<weld::Button> m_xAll;
+ std::unique_ptr<weld::Button> m_xNone;
+ OUString m_sSourceText;
+ OUString m_sDestText;
+
+ DECL_LINK( ButtonClickHdl, weld::Button&, void );
+ DECL_LINK( RightButtonClickHdl, weld::Button&, void );
+ DECL_LINK( AllNoneClickHdl, weld::Button&, void );
+ DECL_LINK( TableListClickHdl, weld::TreeView&, void );
+ DECL_LINK( TableListRightSelectHdl, weld::TreeView&, void );
+
+ static void FillListBox(weld::TreeView& rTreeView, const ODatabaseExport::TColumnVector& rList, bool bCheckButtons);
+
+ public:
+ virtual void Reset ( ) override;
+ virtual void Activate() override;
+ virtual bool LeavePage() override;
+ virtual OUString GetTitle() const override ;
+
+ OWizNameMatching(weld::Container* pPage, OCopyTableWizard* pWizard);
+ virtual ~OWizNameMatching() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/WTabPage.hxx b/dbaccess/source/ui/inc/WTabPage.hxx
new file mode 100644
index 000000000..cc7564cba
--- /dev/null
+++ b/dbaccess/source/ui/inc/WTabPage.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/wizardmachine.hxx>
+
+namespace dbaui
+{
+ // Wizard Page
+ class OCopyTableWizard;
+ class OWizardPage : public ::vcl::OWizardPage
+ {
+ protected:
+ OCopyTableWizard* m_pParent;
+ bool m_bFirstTime; // Page is called the first time; should be set in the reset method
+
+ OWizardPage(weld::Container* pPage, OCopyTableWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID);
+
+ public:
+ virtual ~OWizardPage() override;
+ virtual void Reset ( ) = 0;
+ virtual bool LeavePage() = 0;
+ virtual OUString GetTitle() const = 0;
+
+ bool IsFirstTime() const { return m_bFirstTime; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/WTypeSelect.hxx b/dbaccess/source/ui/inc/WTypeSelect.hxx
new file mode 100644
index 000000000..8a953302a
--- /dev/null
+++ b/dbaccess/source/ui/inc/WTypeSelect.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "FieldDescControl.hxx"
+#include "TypeInfo.hxx"
+#include "WTabPage.hxx"
+
+class SvStream;
+
+namespace dbaui
+{
+ class OWizTypeSelect;
+ class OTableDesignHelpBar;
+ // OWizTypeSelectControl
+ class OWizTypeSelectControl final : public OFieldDescControl
+ {
+ OWizTypeSelect* m_pParentTabPage;
+ virtual void ActivateAggregate( EControlType eType ) override;
+ virtual void DeactivateAggregate( EControlType eType ) override;
+
+ virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) override;
+
+ virtual css::lang::Locale GetLocale() const override;
+ virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const override;
+ virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) override;
+ virtual const OTypeInfoMap* getTypeInfo() const override;
+ virtual bool isAutoIncrementValueEnabled() const override;
+ virtual OUString getAutoIncrementValue() const override;
+
+ public:
+ OWizTypeSelectControl(weld::Container* pPage, OWizTypeSelect* pParentTabPage);
+ virtual ~OWizTypeSelectControl() override;
+
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override;
+ virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override;
+ };
+
+ // Wizard Page: OWizTypeSelectList
+ // just defines the css::ucb::Command for the Contextmenu
+ class OWizTypeSelectList
+ {
+ std::unique_ptr<weld::TreeView> m_xControl;
+ bool m_bPKey;
+ bool IsPrimaryKeyAllowed() const;
+ void setPrimaryKey( OFieldDescription* _pFieldDescr,
+ sal_uInt16 _nPos,
+ bool _bSet = false);
+
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+
+ Link<weld::TreeView&, void> m_aChangeHdl;
+
+ public:
+ OWizTypeSelectList(std::unique_ptr<weld::TreeView> xControl);
+ void SetPKey(bool bPKey) { m_bPKey = bPKey; }
+ weld::TreeView* GetWidget() { return m_xControl.get(); }
+ OUString get_selected_id() const { return m_xControl->get_selected_id(); }
+ void clear() { m_xControl->clear(); }
+ void append(const OUString& rId, const OUString& rStr)
+ {
+ m_xControl->append(rId, rStr);
+ }
+ void set_image(int nRow, const OUString& rImage)
+ {
+ m_xControl->set_image(nRow, rImage);
+ }
+ void set_selection_mode(SelectionMode eMode) { m_xControl->set_selection_mode(eMode); }
+ int count_selected_rows() const { return m_xControl->count_selected_rows(); }
+ void select(int pos) { m_xControl->select(pos); }
+ void connect_changed(const Link<weld::TreeView&, void>& rLink)
+ {
+ m_aChangeHdl = rLink;
+ m_xControl->connect_changed(rLink);
+ }
+ };
+
+ // Wizard Page: OWizTypeSelect
+ // Serves as base class for different copy properties.
+ // Calls FillColumnList, when button AUTO is triggered
+ class OWizTypeSelect : public OWizardPage
+ {
+ friend class OWizTypeSelectControl;
+ friend class OWizTypeSelectList;
+
+ DECL_LINK( ColumnSelectHdl, weld::TreeView&, void );
+ DECL_LINK( ButtonClickHdl, weld::Button&, void );
+ protected:
+ std::unique_ptr<OWizTypeSelectList> m_xColumnNames;
+ std::unique_ptr<weld::Label> m_xColumns;
+ std::unique_ptr<weld::Container> m_xControlContainer;
+ std::unique_ptr<OWizTypeSelectControl> m_xTypeControl;
+ std::unique_ptr<weld::Label> m_xAutoType;
+ std::unique_ptr<weld::Label> m_xAutoFt;
+ std::unique_ptr<weld::SpinButton> m_xAutoEt;
+ std::unique_ptr<weld::Button> m_xAutoPb;
+
+ SvStream* m_pParserStream; // stream to read the tokens from or NULL
+ OUString m_sAutoIncrementValue;
+ sal_Int32 m_nDisplayRow;
+ bool m_bAutoIncrementEnabled;
+ bool m_bDuplicateName;
+
+ virtual void createReaderAndCallParser(sal_Int32 _nRows) = 0;
+
+ void EnableAuto(bool bEnable);
+ public:
+ virtual void Reset ( ) override;
+ virtual void Activate( ) override;
+ virtual bool LeavePage() override;
+ virtual OUString GetTitle() const override;
+
+ OWizTypeSelect(weld::Container* pParent, OCopyTableWizard* pWizard, SvStream* pStream = nullptr);
+ virtual ~OWizTypeSelect() override;
+
+ void setDisplayRow(sal_Int32 _nRow) { m_nDisplayRow = _nRow - 1; }
+ void setDuplicateName(bool _bDuplicateName) { m_bDuplicateName = _bDuplicateName; }
+ };
+
+ typedef std::unique_ptr<OWizTypeSelect> (*TypeSelectionPageFactory)(weld::Container*, OCopyTableWizard*, SvStream&);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/adtabdlg.hxx b/dbaccess/source/ui/inc/adtabdlg.hxx
new file mode 100644
index 000000000..5fe1d7c1d
--- /dev/null
+++ b/dbaccess/source/ui/inc/adtabdlg.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <vcl/weld.hxx>
+#include "tabletree.hxx"
+
+namespace dbaui
+{
+ /** unifies the access to a list of table/query objects
+ */
+ class TableObjectListFacade
+ {
+ public:
+ virtual void updateTableObjectList( bool _bAllowViews ) = 0;
+ virtual OUString getSelectedName( OUString& _out_rAliasName ) const = 0;
+ virtual bool isLeafSelected() const = 0;
+
+ virtual ~TableObjectListFacade();
+ };
+
+ class IAddTableDialogContext
+ {
+ public:
+ virtual css::uno::Reference< css::sdbc::XConnection >
+ getConnection() const = 0;
+ virtual bool allowViews() const = 0;
+ virtual bool allowQueries() const = 0;
+ virtual bool allowAddition() const = 0;
+ virtual void addTableWindow( const OUString& _rQualifiedTableName, const OUString& _rAliasName ) = 0;
+ virtual void onWindowClosing() = 0;
+
+ protected:
+ ~IAddTableDialogContext() {}
+ };
+
+ class OAddTableDlg : public weld::GenericDialogController
+ {
+ IAddTableDialogContext& m_rContext;
+ std::unique_ptr< TableObjectListFacade > m_xCurrentList;
+
+ std::unique_ptr<weld::RadioButton> m_xCaseTables;
+ std::unique_ptr<weld::RadioButton> m_xCaseQueries;
+
+ std::unique_ptr<OTableTreeListBox> m_xTableList;
+ std::unique_ptr<weld::TreeView> m_xQueryList;
+
+ std::unique_ptr<weld::Button> m_xAddButton;
+ std::unique_ptr<weld::Button> m_xCloseButton;
+
+ DECL_LINK( AddClickHdl, weld::Button&, void );
+ DECL_LINK( CloseClickHdl, weld::Button&, void);
+ DECL_LINK( TableListDoubleClickHdl, weld::TreeView&, bool );
+ DECL_LINK( TableListSelectHdl, weld::TreeView&, void );
+ DECL_LINK( OnTypeSelected, weld::Toggleable&, void );
+
+ public:
+ OAddTableDlg(weld::Window* _pParent,
+ IAddTableDialogContext& _rContext);
+ virtual ~OAddTableDlg() override;
+
+ void Update();
+ void OnClose();
+
+ static OUString getDialogTitleForContext(
+ IAddTableDialogContext const & _rContext );
+
+ private:
+ bool impl_isAddAllowed();
+
+ enum ObjectList
+ {
+ Tables,
+ Queries
+ };
+ void impl_switchTo( ObjectList _eList );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/advancedsettingsdlg.hxx b/dbaccess/source/ui/inc/advancedsettingsdlg.hxx
new file mode 100644
index 000000000..b28fe5ce3
--- /dev/null
+++ b/dbaccess/source/ui/inc/advancedsettingsdlg.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "IItemSetHelper.hxx"
+#include <sfx2/tabdlg.hxx>
+#include <memory>
+
+namespace dbaui
+{
+
+ // AdvancedSettingsDialog
+ class ODbDataSourceAdministrationHelper;
+ /** implements the advanced page dlg of the data source properties.
+ */
+ class AdvancedSettingsDialog : public SfxTabDialogController
+ , public IItemSetHelper
+ , public IDatabaseSettingsDialog
+ {
+ std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl;
+
+ protected:
+ virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override;
+ virtual short Ok() override;
+
+ public:
+ AdvancedSettingsDialog(weld::Window* pParent,
+ SfxItemSet* _pItems,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ const css::uno::Any& _aDataSourceName);
+
+ virtual ~AdvancedSettingsDialog() override;
+
+ /// determines whether or not the given data source type has any advanced setting
+ static bool doesHaveAnyAdvancedSettings( const OUString& _sURL );
+
+ virtual const SfxItemSet* getOutputSet() const override;
+ virtual SfxItemSet* getWriteOutputSet() override;
+
+ // forwards to ODbDataSourceAdministrationHelper
+ virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override;
+ virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override;
+ virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override;
+ virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override;
+ virtual void clearPassword() override;
+ virtual void saveDatasource() override;
+ virtual void setTitle(const OUString& _sTitle) override;
+ virtual void enableConfirmSettings( bool _bEnable ) override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/asyncmodaldialog.hxx b/dbaccess/source/ui/inc/asyncmodaldialog.hxx
new file mode 100644
index 000000000..483dfb7c1
--- /dev/null
+++ b/dbaccess/source/ui/inc/asyncmodaldialog.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+
+namespace dbaui
+{
+
+ // AsyncDialogExecutor
+ /** helper class for executing (UNO) dialogs modal, but asynchronously
+ */
+ class AsyncDialogExecutor
+ {
+ public:
+ /** executes the given dialog asynchronously, but still modal
+
+ @throws IllegalArgumentException
+ if the given dialog is <NULL/>
+ @todo
+ allow for a callback for the result
+ */
+ static void executeModalDialogAsync(
+ const css::uno::Reference< css::ui::dialogs::XExecutableDialog >& _rxDialog
+ );
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/browserids.hxx b/dbaccess/source/ui/inc/browserids.hxx
new file mode 100644
index 000000000..0c510497d
--- /dev/null
+++ b/dbaccess/source/ui/inc/browserids.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svx/svxids.hrc>
+#include <dbaccess_slotid.hrc>
+
+#define ID_BROWSER_COPY SID_COPY
+#define ID_BROWSER_CUT SID_CUT
+#define ID_BROWSER_EDITDOC SID_EDITDOC
+#define ID_BROWSER_UNDORECORD SID_FM_RECORD_UNDO
+#define ID_BROWSER_SAVERECORD SID_FM_RECORD_SAVE
+#define ID_BROWSER_PASTE SID_PASTE
+#define ID_BROWSER_CLIPBOARD_FORMAT_ITEMS SID_CLIPBOARD_FORMAT_ITEMS
+#define ID_BROWSER_REDO SID_REDO
+#define ID_BROWSER_SAVEDOC SID_SAVEDOC
+#define ID_BROWSER_SAVEASDOC SID_SAVEASDOC
+#define ID_BROWSER_TITLE SID_DOCINFO_TITLE
+#define ID_BROWSER_UNDO SID_UNDO
+#define ID_BROWSER_INSERTCOLUMNS SID_SBA_BRW_INSERT
+#define ID_BROWSER_FORMLETTER SID_SBA_BRW_MERGE
+#define ID_BROWSER_INSERTCONTENT SID_SBA_BRW_UPDATE
+
+#define ID_BROWSER_SEARCH SID_FM_SEARCH
+#define ID_BROWSER_SORTUP SID_FM_SORTUP
+#define ID_BROWSER_SORTDOWN SID_FM_SORTDOWN
+#define ID_BROWSER_AUTOFILTER SID_FM_AUTOFILTER
+#define ID_BROWSER_FILTERCRIT SID_FM_FILTERCRIT
+#define ID_BROWSER_ORDERCRIT SID_FM_ORDERCRIT
+#define ID_BROWSER_REMOVEFILTER SID_FM_REMOVE_FILTER_SORT
+#define ID_BROWSER_FILTERED SID_FM_FORM_FILTERED
+#define ID_BROWSER_REFRESH SID_FM_REFRESH
+#define ID_BROWSER_COLATTRSET 10020 // column formatting
+#define ID_BROWSER_COLWIDTH 10021 // column width
+#define ID_BROWSER_TABLEATTR 10022 // table format attributes
+#define ID_BROWSER_ROWHEIGHT 10023 // row height
+#define ID_BROWSER_ADDTABLE SID_FM_ADDTABLE
+#define ID_BROWSER_EXPLORER SID_DSBROWSER_EXPLORER
+#define ID_BROWSER_DOCUMENT_DATASOURCE SID_DOCUMENT_DATA_SOURCE
+
+// The following ids are local to special components (e.g. menus), so they don't need to be unique
+// overall. Please have this in mind when changing anything
+#define ID_TREE_EDIT_DATABASE 1
+#define ID_TREE_CLOSE_CONN 2
+ // FREE
+#define ID_TREE_ADMINISTRATE 4
+
+#define ID_REPORT_NEW_TEXT 14
+#define ID_FORM_NEW_TEXT 15
+#define ID_FORM_NEW_CALC 16
+#define ID_FORM_NEW_IMPRESS 17
+#define ID_NEW_QUERY_DESIGN 20
+#define ID_EDIT_QUERY_DESIGN 21
+#define ID_NEW_QUERY_SQL 22
+#define ID_EDIT_QUERY_SQL 23
+#define ID_NEW_TABLE_DESIGN 25
+#define ID_NEW_VIEW_DESIGN 28
+#define ID_DIRECT_SQL 32
+#define ID_BROWSER_REFRESH_REBUILD 34
+#define ID_INDEX_NEW 36
+#define ID_INDEX_DROP 37
+#define ID_INDEX_RENAME 38
+#define ID_INDEX_SAVE 39
+#define ID_INDEX_RESET 40
+#define ID_DOCUMENT_CREATE_REPWIZ 41
+#define ID_BROWSER_SQL 42
+
+#define ID_APP_NEW_QUERY_AUTO_PILOT 44
+#define ID_NEW_TABLE_DESIGN_AUTO_PILOT 45
+#define ID_NEW_VIEW_DESIGN_AUTO_PILOT 46
+
+
+// other
+#define ID_BROWSER_QUERY_EXECUTE SID_FM_EXECUTE
+
+#define ID_BROWSER_CLOSE SID_CLOSEWIN
+#define ID_BROWSER_ESCAPEPROCESSING SID_FM_NATIVESQL
+
+#define ID_BROWSER_INSERT_ROW (SID_SBA_START + 46) // insert row
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/brwctrlr.hxx b/dbaccess/source/ui/inc/brwctrlr.hxx
new file mode 100644
index 000000000..e5e1db401
--- /dev/null
+++ b/dbaccess/source/ui/inc/brwctrlr.hxx
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <dbaccess/genericcontroller.hxx>
+#include "brwview.hxx"
+#include "sbagrid.hxx"
+
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/sdb/XSQLErrorListener.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/form/XResetListener.hpp>
+#include <com/sun/star/form/XDatabaseParameterListener.hpp>
+#include <com/sun/star/form/XConfirmDeleteListener.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/frame/XModule.hpp>
+
+#include <vcl/timer.hxx>
+#include <vcl/transfer.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <svtools/cliplistener.hxx>
+
+struct FmFoundRecordInformation;
+struct FmSearchContext;
+
+namespace dbtools
+{
+ class SQLExceptionInfo;
+}
+
+namespace dbaui
+{
+
+ typedef ::cppu::ImplInheritanceHelper < OGenericUnoController
+ , css::sdb::XSQLErrorListener
+ , css::form::XDatabaseParameterListener
+ , css::form::XConfirmDeleteListener
+ , css::form::XLoadListener
+ , css::form::XResetListener
+ , css::awt::XFocusListener
+ , css::container::XContainerListener
+ , css::beans::XPropertyChangeListener
+ , css::frame::XModule
+ > SbaXDataBrowserController_Base;
+
+ class SbaXDataBrowserController :public SbaXDataBrowserController_Base
+ ,public SbaGridListener
+ {
+ // attributes
+ private:
+ // for implementing the XFormController
+ class FormControllerImpl;
+ friend class FormControllerImpl;
+
+ css::uno::Reference< css::sdbc::XRowSet > m_xRowSet; // our rowset
+ css::uno::Reference< css::sdbcx::XColumnsSupplier > m_xColumnsSupplier; // queried from the rowset member
+ css::uno::Reference< css::form::XLoadable > m_xLoadable; // queried from the rowset member as well
+ css::uno::Reference< css::form::XFormComponent > m_xGridModel; // the model of our grid
+ css::uno::Reference< css::util::XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier
+ mutable css::uno::Reference< css::sdb::XSingleSelectQueryComposer >
+ m_xParser; // for sorting 'n filtering
+
+ sal_Int32 m_nRowSetPrivileges; // cached Privileges property of m_xRowSet
+
+ AutoTimer m_aInvalidateClipboard; // for testing the state of the CUT/COPY/PASTE-slots
+
+ TransferableDataHelper m_aSystemClipboard; // content of the clipboard
+ rtl::Reference<TransferableClipboardListener>
+ m_pClipboardNotifier; // notifier for changes in the clipboard
+
+ OAsynchronousLink m_aAsyncGetCellFocus;
+ OAsynchronousLink m_aAsyncDisplayError;
+ ::dbtools::SQLExceptionInfo m_aCurrentError;
+
+ OUString m_sStateSaveRecord;
+ OUString m_sStateUndoRecord;
+ OUString m_sModuleIdentifier;
+
+ // members for asynchronous load operations
+ rtl::Reference<FormControllerImpl> m_xFormControllerImpl; // implementing the XFormController
+
+ sal_uInt16 m_nFormActionNestingLevel; // see enter-/leaveFormAction
+
+ bool m_bLoadCanceled : 1; // the load was canceled somehow
+ bool m_bCannotSelectUnfiltered : 1; // received a DATA_CANNOT_SELECT_UNFILTERED error
+
+ protected:
+ class FormErrorHelper final
+ {
+ SbaXDataBrowserController* m_pOwner;
+ public:
+ FormErrorHelper(SbaXDataBrowserController* pOwner) : m_pOwner(pOwner) { m_pOwner->enterFormAction(); }
+ ~FormErrorHelper() { m_pOwner->leaveFormAction(); }
+ };
+ friend class FormErrorHelper;
+
+ // attribute access
+ protected:
+ const css::uno::Reference< css::sdbc::XRowSet >& getRowSet() const { return m_xRowSet; }
+ const css::uno::Reference< css::form::XLoadable >& getLoadable() const { return m_xLoadable; }
+
+ const css::uno::Reference< css::form::XFormComponent >& getFormComponent() const { return m_xGridModel; }
+ css::uno::Reference< css::awt::XControlModel > getControlModel() const { return css::uno::Reference< css::awt::XControlModel > (m_xGridModel, css::uno::UNO_QUERY); }
+ const css::uno::Reference< css::util::XNumberFormatter >& getNumberFormatter()const { return m_xFormatter; }
+
+ bool isValid() const { return m_xRowSet.is() && m_xGridModel.is(); }
+ bool isValidCursor() const; // checks the css::data::XDatabaseCursor-interface of m_xRowSet
+ bool isLoaded() const;
+ bool loadingCancelled() const { return m_bLoadCanceled; }
+ void onStartLoading( const css::uno::Reference< css::form::XLoadable >& _rxLoadable );
+ void setLoadingCancelled() { m_bLoadCanceled = true; }
+
+ public:
+ SbaXDataBrowserController(const css::uno::Reference< css::uno::XComponentContext >& _rM);
+
+ UnoDataBrowserView* getBrowserView() const { return static_cast< UnoDataBrowserView*>(getView()); }
+ // late construction
+ virtual bool Construct(vcl::Window* pParent) override;
+
+ // UNO
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // css::util::XModifyListener
+ virtual void SAL_CALL modified(const css::lang::EventObject& aEvent) override;
+
+ // css::container::XContainerListener
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& Event) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XModule
+ virtual void SAL_CALL setIdentifier( const OUString& Identifier ) override;
+ virtual OUString SAL_CALL getIdentifier( ) override;
+
+ // css::awt::XFocusListener
+ virtual void SAL_CALL focusGained(const css::awt::FocusEvent& e) override;
+ virtual void SAL_CALL focusLost(const css::awt::FocusEvent& e) override;
+
+ // css::frame::XController
+ virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL disposing() override;
+
+ // css::frame::XFrameActionListener
+ virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent& aEvent) override;
+
+ // css::sdb::XSQLErrorListener
+ virtual void SAL_CALL errorOccured(const css::sdb::SQLErrorEvent& aEvent) override;
+
+ // css::form::XDatabaseParameterListener
+ virtual sal_Bool SAL_CALL approveParameter(const css::form::DatabaseParameterEvent& aEvent) override;
+
+ // css::form::XConfirmDeleteListener
+ virtual sal_Bool SAL_CALL confirmDelete(const css::sdb::RowChangeEvent& aEvent) override;
+
+ // css::form::XLoadListener
+ virtual void SAL_CALL loaded(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL unloading(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL unloaded(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL reloading(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL reloaded(const css::lang::EventObject& aEvent) override;
+
+ // css::form::XResetListener
+ virtual sal_Bool SAL_CALL approveReset(const css::lang::EventObject& rEvent) override;
+ virtual void SAL_CALL resetted(const css::lang::EventObject& rEvent) override;
+
+ // SbaGridListener
+ virtual void RowChanged() override;
+ virtual void ColumnChanged() override;
+ virtual void SelectionChanged() override;
+ virtual void CellActivated() override;
+ virtual void CellDeactivated() override;
+ virtual void BeforeDrop() override;
+ virtual void AfterDrop() override;
+
+ public:
+
+ protected:
+ virtual ~SbaXDataBrowserController() override;
+
+ // all the features which should be handled by this class
+ virtual void describeSupportedFeatures() override;
+ // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot.
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ // execute a feature
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ virtual void startFrameListening( const css::uno::Reference< css::frame::XFrame >& _rxFrame ) override;
+ virtual void stopFrameListening( const css::uno::Reference< css::frame::XFrame >& _rxFrame ) override;
+
+ virtual css::uno::Reference< css::sdbc::XRowSet > CreateForm();
+ // our default implementation simply instantiates a stardiv.one.form.component.Form service
+ // (probably this needs not to be overridden, but you may return anything you want as long as it
+ // supports the css::form::DatabaseForm service. For instance you may want to create an adapter here which
+ // is synchronized with a foreign css::form::DatabaseForm you got elsewhere)
+ virtual bool InitializeForm(
+ const css::uno::Reference< css::beans::XPropertySet >& i_formProperties ) = 0;
+ // called immediately after a successful CreateForm
+ // do any initialization (data source etc.) here. the form should be fully functional after that.
+ // return sal_False if you didn't succeed (don't throw exceptions, they won't be caught)
+
+ css::uno::Reference< css::form::XFormComponent > CreateGridModel();
+ // our default implementation simply instantiates a stardiv.one.form.component.Grid service
+ // you most probably don't want to override this behavior
+
+ // the default implementation of disposing distributes the events to the following disposingXXX functions
+ void disposingFormModel(const css::lang::EventObject& Source);
+ void disposingColumnModel(const css::lang::EventObject& Source);
+
+ // want to be a listener to the grid control ? use this !
+ void addControlListeners(const css::uno::Reference< css::awt::XControl > & _xGridControl);
+ void removeControlListeners(const css::uno::Reference< css::awt::XControl > & _xGridControl);
+
+ // want to be a listener to the grid model ? use this !
+ virtual void addModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel);
+ virtual void removeModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel);
+
+ // want to be a listener grid columns ? use this !
+ virtual void AddColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol);
+ virtual void RemoveColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol);
+
+ // call after "major changes" (e.g. the completion of the async load).
+ // invalidates all toolbox slots and all supported features.
+
+ virtual bool LoadForm();
+ // load the form
+ // the default implementation does a direct load or starts a load thread, depending on the multithread capabilities
+ // of the data source.
+ // the default implementation also calls LoadFinished after a synchronous load, so be sure to do the same if you override
+ // this method and don't call the base class' method
+
+ virtual void LoadFinished(bool bWasSynch);
+ // called if the loading (the _complete_ loading process) is done (no matter if synchron or asynchron).
+
+ virtual void criticalFail();
+ // called whenever a reload operation on the rowset failed
+ // (an "operation" is not only a simple reload: if the user sets a filter, and reloading the form
+ // after setting this filter fails, the filter is reset and the form is reloaded, again. Only the
+ // whole process (_both_ XLoadable::reload calls _together_) form the "reload operation"
+
+ // empty the frame where our view resides
+ bool CommitCurrent();
+ // commit the current column (i.e. cell)
+ bool SaveModified(bool bAskFor = true);
+ // save the modified record
+
+ css::uno::Reference< css::beans::XPropertySet > getBoundField() const;
+ // a PropertySet corresponding to the cursor field a column is bound to.
+ // The field for the current column will be retrieved.
+
+ void enterFormAction();
+ void leaveFormAction();
+
+ // init the formatter if form changes
+ void initFormatter();
+
+ /// loads or reloads the form
+ bool reloadForm(const css::uno::Reference< css::form::XLoadable >& _rxLoadable);
+
+ virtual bool preReloadForm(){ return false; }
+ virtual void postReloadForm(){}
+
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer >
+ createParser_nothrow();
+
+ private:
+ void setCurrentModified( bool _bSet );
+
+ // execute the filter or sort slot
+ void ExecuteFilterSortCrit(bool bFilter);
+
+ // execute the search slot
+ void ExecuteSearch();
+
+ void initializeParser() const; // changes the mutable member m_xParser
+ void applyParserFilter(const OUString& _rOldFilter, bool _bOldFilterApplied,const ::OUString& _sOldHaving,const css::uno::Reference< css::sdb::XSingleSelectQueryComposer >& _xParser);
+ void applyParserOrder(const OUString& _rOldOrder,const css::uno::Reference< css::sdb::XSingleSelectQueryComposer >& _xParser);
+
+ sal_Int16 getCurrentColumnPosition() const;
+ void setCurrentColumnPosition( sal_Int16 _nPos );
+ void addColumnListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel);
+
+ void impl_checkForCannotSelectUnfiltered( const ::dbtools::SQLExceptionInfo& _rError );
+
+ // time to check the CUT/COPY/PASTE-slot-states
+ DECL_LINK( OnInvalidateClipboard, Timer*, void );
+ DECL_LINK( OnClipboardChanged, TransferableDataHelper*, void );
+
+ // search callbacks
+ DECL_LINK(OnSearchContextRequest, FmSearchContext&, sal_uInt32);
+ DECL_LINK(OnFoundData, FmFoundRecordInformation&, void);
+ DECL_LINK(OnCanceledNotFound, FmFoundRecordInformation&, void);
+
+ DECL_LINK( OnAsyncGetCellFocus, void*, void );
+ DECL_LINK( OnAsyncDisplayError, void*, void );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/brwview.hxx b/dbaccess/source/ui/inc/brwview.hxx
new file mode 100644
index 000000000..0933861b8
--- /dev/null
+++ b/dbaccess/source/ui/inc/brwview.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/window.hxx>
+
+#include <dbaccess/dataview.hxx>
+#include <unotools/eventlisteneradapter.hxx>
+#include "dbtreelistbox.hxx"
+
+namespace com::sun::star::awt {
+ class XControl;
+ class XControlContainer;
+ class XControlModel;
+}
+
+class Splitter;
+
+namespace dbaui
+{
+ class SbaGridControl;
+
+ class UnoDataBrowserView final : public ODataView, public ::utl::OEventListenerAdapter
+ {
+ css::uno::Reference< css::awt::XControl > m_xGrid; // our grid's UNO representation
+ css::uno::Reference< css::awt::XControlContainer > m_xMe; // our own UNO representation
+ VclPtr<InterimDBTreeListBox> m_pTreeView;
+ VclPtr<Splitter> m_pSplitter;
+ mutable VclPtr<SbaGridControl> m_pVclControl; // our grid's VCL representation
+
+ DECL_LINK( SplitHdl, Splitter*, void );
+ // attribute access
+ public:
+ const css::uno::Reference< css::awt::XControl >& getGridControl() const { return m_xGrid; }
+ SbaGridControl* getVclControl() const;
+
+ UnoDataBrowserView( vcl::Window* pParent,
+ IController& _rController,
+ const css::uno::Reference< css::uno::XComponentContext >& );
+ virtual ~UnoDataBrowserView() override;
+ virtual void dispose() override;
+
+ /// late construction
+ void Construct(const css::uno::Reference< css::awt::XControlModel >& xModel);
+
+ /** as columns may be hidden there is a difference between a columns model pos and its view pos
+ so we you may use these translation function
+ */
+ sal_uInt16 View2ModelPos(sal_uInt16 nPos) const;
+ /// for the same reason the view column count isn't the same as the model column count
+
+ void setSplitter(Splitter* pSplitter);
+ void setTreeView(InterimDBTreeListBox* pTreeView);
+
+ void showStatus( const OUString& _rStatus );
+ void hideStatus();
+
+ const css::uno::Reference< css::awt::XControlContainer >& getContainer() const { return m_xMe; }
+
+ private:
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void GetFocus() override;
+ virtual void resizeDocumentView(tools::Rectangle& rRect) override;
+ virtual void _disposing( const css::lang::EventObject& _rSource ) override;
+
+ using ODataView::Construct;
+ };
+
+ class BrowserViewStatusDisplay final
+ {
+ VclPtr<UnoDataBrowserView> m_pView;
+
+ public:
+ BrowserViewStatusDisplay( UnoDataBrowserView* _pView, const OUString& _rStatus );
+ ~BrowserViewStatusDisplay( );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/callbacks.hxx b/dbaccess/source/ui/inc/callbacks.hxx
new file mode 100644
index 000000000..e380b2671
--- /dev/null
+++ b/dbaccess/source/ui/inc/callbacks.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sot/exchange.hxx>
+
+class Point;
+struct AcceptDropEvent;
+struct ExecuteDropEvent;
+
+namespace comphelper { class OInterfaceContainerHelper2; }
+
+namespace vcl
+{
+ class Window;
+}
+
+namespace weld
+{
+ class TreeIter;
+ class TreeView;
+}
+
+namespace dbaui
+{
+
+ class IController;
+ // IControlActionListener
+ class SAL_NO_VTABLE IControlActionListener
+ {
+ public:
+ /** requests a quick help text to display
+ @return <FALSE/> if the default quick help text should be used
+ */
+ virtual bool requestQuickHelp(const void* pUserData, OUString& rText) const = 0;
+
+ /** handler for StartDrag requests
+ @return <TRUE/> if a drag operation was started
+ */
+ virtual bool requestDrag(const weld::TreeIter& rEntry) = 0;
+
+ /** check whether or not a drop request should be accepted
+ */
+ virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) = 0;
+
+ /** execute a drop request
+ */
+ virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) = 0;
+
+ protected:
+ ~IControlActionListener() {}
+ };
+
+ // IContextMenuProvider
+ class SAL_NO_VTABLE IContextMenuProvider
+ {
+ public:
+ /** returns the context menu resource name for the control
+
+ Supposed to be a valid name from uiconfig/<module>/popupmenu folder.
+ */
+ virtual OUString getContextMenuResourceName() const = 0;
+
+ /** returns the controller which is responsible for providing states of certain features,
+ and executing them.
+ */
+ virtual IController& getCommandController() = 0;
+
+ /** returns the container of registered context menu interceptors, or NULL if the implementation
+ does not support context menu interception
+ */
+ virtual ::comphelper::OInterfaceContainerHelper2*
+ getContextMenuInterceptors() = 0;
+
+ /** returns the current selection in the given control
+
+ This selection is used for filling a ContextMenuExecuteEvent event for the given
+ control.
+ */
+ virtual css::uno::Any getCurrentSelection(weld::TreeView& rControl) const = 0;
+
+ virtual vcl::Window* getMenuParent() const = 0;
+
+ /** adjust rPos which is initially relative to rControl to be relative to
+ the window of getMenuParent
+ */
+ virtual void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const = 0;
+
+ protected:
+ ~IContextMenuProvider() {}
+ };
+
+ // IDragTransferableListener
+ class SAL_NO_VTABLE IDragTransferableListener
+ {
+ public:
+ /// called when a drag operation done with a Transferable has been finished
+ virtual void dragFinished( ) = 0;
+
+ protected:
+ ~IDragTransferableListener() {}
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/charsetlistbox.hxx b/dbaccess/source/ui/inc/charsetlistbox.hxx
new file mode 100644
index 000000000..aedfb6ec5
--- /dev/null
+++ b/dbaccess/source/ui/inc/charsetlistbox.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include "charsets.hxx"
+
+class SfxItemSet;
+
+namespace dbaui
+{
+ // CharSetListBox
+ class CharSetListBox
+ {
+ public:
+ CharSetListBox(std::unique_ptr<weld::ComboBox> xControl);
+
+ void SelectEntryByIanaName( const OUString& _rIanaName );
+ bool StoreSelectedCharSet( SfxItemSet& _rSet, const sal_uInt16 _nItemId );
+
+ weld::ComboBox* get_widget() { return m_xControl.get(); }
+ void connect_changed(const Link<weld::ComboBox&, void>& rLink) { m_xControl->connect_changed(rLink); }
+ void show() { m_xControl->show(); }
+
+ private:
+ OCharsetDisplay m_aCharSets;
+ std::unique_ptr<weld::ComboBox> m_xControl;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/charsets.hxx b/dbaccess/source/ui/inc/charsets.hxx
new file mode 100644
index 000000000..ed1f88d7b
--- /dev/null
+++ b/dbaccess/source/ui/inc/charsets.hxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/dbcharset.hxx>
+#include <rtl/ustring.hxx>
+
+namespace dbaui
+{
+
+ // OCharsetDisplay
+ typedef ::dbtools::OCharsetMap OCharsetDisplay_Base;
+ class OCharsetDisplay final : protected OCharsetDisplay_Base
+ {
+ private:
+ OUString m_aSystemDisplayName;
+
+ public:
+ class ExtendedCharsetIterator;
+ friend class OCharsetDisplay::ExtendedCharsetIterator;
+
+ typedef ExtendedCharsetIterator iterator;
+ typedef ExtendedCharsetIterator const_iterator;
+
+ OCharsetDisplay();
+
+ // various find operations
+ const_iterator findEncoding(const rtl_TextEncoding _eEncoding) const;
+ const_iterator findIanaName(const OUString& _rIanaName) const;
+ const_iterator findDisplayName(const OUString& _rDisplayName) const;
+
+ /// get access to the first element of the charset collection
+ const_iterator begin() const;
+ /// get access to the (last + 1st) element of the charset collection
+ const_iterator end() const;
+
+ private:
+ virtual bool approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const override;
+
+ using OCharsetDisplay_Base::find;
+ };
+
+ //- CharsetDisplayDerefHelper
+ typedef ::dbtools::CharsetIteratorDerefHelper CharsetDisplayDerefHelper_Base;
+ class CharsetDisplayDerefHelper final : protected CharsetDisplayDerefHelper_Base
+ {
+ friend class OCharsetDisplay::ExtendedCharsetIterator;
+
+ OUString m_sDisplayName;
+
+ public:
+ CharsetDisplayDerefHelper(const CharsetDisplayDerefHelper& _rSource);
+
+ OUString const & getIanaName() const { return CharsetDisplayDerefHelper_Base::getIanaName(); }
+ const OUString& getDisplayName() const { return m_sDisplayName; }
+
+ private:
+ CharsetDisplayDerefHelper(const ::dbtools::CharsetIteratorDerefHelper& _rBase, const OUString& _rDisplayName);
+ };
+
+ //- OCharsetDisplay::ExtendedCharsetIterator
+ class OCharsetDisplay::ExtendedCharsetIterator
+ {
+ friend class OCharsetDisplay;
+
+ friend bool operator==(const ExtendedCharsetIterator& lhs, const ExtendedCharsetIterator& rhs);
+ friend bool operator!=(const ExtendedCharsetIterator& lhs, const ExtendedCharsetIterator& rhs) { return !(lhs == rhs); }
+
+ typedef ::dbtools::OCharsetMap container;
+ typedef container::CharsetIterator base_iterator;
+
+ protected:
+ const OCharsetDisplay* m_pContainer;
+ base_iterator m_aPosition;
+
+ public:
+ CharsetDisplayDerefHelper operator*() const;
+
+ /// prefix increment
+ const ExtendedCharsetIterator& operator++();
+
+ protected:
+ ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, const base_iterator& _rPosition );
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/commontypes.hxx b/dbaccess/source/ui/inc/commontypes.hxx
new file mode 100644
index 000000000..50c567010
--- /dev/null
+++ b/dbaccess/source/ui/inc/commontypes.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <unotools/sharedunocomponent.hxx>
+
+namespace com::sun::star {
+ namespace sdbc {
+ class XConnection;
+ }
+}
+
+namespace dbaui
+{
+
+ typedef ::utl::SharedUNOComponent< css::sdbc::XConnection > SharedConnection;
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/curledit.hxx b/dbaccess/source/ui/inc/curledit.hxx
new file mode 100644
index 000000000..a99c2c3af
--- /dev/null
+++ b/dbaccess/source/ui/inc/curledit.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <dsntypes.hxx>
+
+namespace dbaui
+{
+
+class OConnectionURLEdit
+{
+ OUString m_sSavedValue;
+
+ ::dbaccess::ODsnTypeCollection* m_pTypeCollection;
+ OUString m_sSaveValueNoPrefix;
+ bool m_bShowPrefix; // when <TRUE> the prefix will be visible, otherwise not
+
+ std::unique_ptr<weld::Entry> m_xEntry;
+ std::unique_ptr<weld::Label> m_xForcedPrefix;
+
+public:
+ OConnectionURLEdit(std::unique_ptr<weld::Entry> xEntry, std::unique_ptr<weld::Label> xForcedPrefix);
+ ~OConnectionURLEdit();
+
+public:
+ bool get_visible() const { return m_xEntry->get_visible(); }
+ void connect_changed(const Link<weld::Entry&, void>& rLink) { m_xEntry->connect_changed(rLink); }
+ void set_help_id(const OString& rName) { m_xEntry->set_help_id(rName); }
+ void hide()
+ {
+ m_xEntry->hide();
+ if (m_bShowPrefix)
+ m_xForcedPrefix->hide();
+ }
+ void show()
+ {
+ m_xEntry->show();
+ if (m_bShowPrefix)
+ m_xForcedPrefix->show();
+ }
+ void save_value() { m_sSavedValue = GetText(); }
+ bool get_value_changed_from_saved() const { return m_sSavedValue != GetText(); }
+ void grab_focus()
+ {
+ m_xEntry->grab_focus();
+ }
+ void set_sensitive(bool bSensitive)
+ {
+ m_xEntry->set_sensitive(bSensitive);
+ if (m_bShowPrefix)
+ m_xForcedPrefix->set_sensitive(bSensitive);
+ }
+ void connect_focus_in(const Link<weld::Widget&, void>& rLink)
+ {
+ m_xEntry->connect_focus_in(rLink);
+ }
+ void connect_focus_out(const Link<weld::Widget&, void>& rLink)
+ {
+ m_xEntry->connect_focus_out(rLink);
+ }
+
+ // Edit overridables
+ void SetText(const OUString& _rStr);
+ void SetText(const OUString& _rStr, const Selection& _rNewSelection);
+ OUString GetText() const;
+
+ /** Shows the Prefix
+ @param _bShowPrefix
+ If <TRUE/> than the prefix will be visible, otherwise not.
+ */
+ void ShowPrefix(bool _bShowPrefix);
+ /// get the currently set text, excluding the prefix indicating the type
+ OUString GetTextNoPrefix() const;
+ /// set a new text, leave the current prefix unchanged
+ void SetTextNoPrefix(const OUString& _rText);
+
+ void SaveValueNoPrefix() { m_sSaveValueNoPrefix = GetTextNoPrefix(); }
+ const OUString& GetSavedValueNoPrefix() const { return m_sSaveValueNoPrefix; }
+ void SetTypeCollection(::dbaccess::ODsnTypeCollection* _pTypeCollection) { m_pTypeCollection = _pTypeCollection; }
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/databaseobjectview.hxx b/dbaccess/source/ui/inc/databaseobjectview.hxx
new file mode 100644
index 000000000..d6b23878a
--- /dev/null
+++ b/dbaccess/source/ui/inc/databaseobjectview.hxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+
+namespace dbaui
+{
+ /** encapsulates access to the view of a database object.
+
+ @todo
+ this is to be merged with the OLinkedDocumentAccess class
+ */
+ class DatabaseObjectView
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xORB;
+ css::uno::Reference< css::frame::XFrame >
+ m_xParentFrame;
+ css::uno::Reference< css::frame::XComponentLoader >
+ m_xFrameLoader;
+ css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >
+ m_xApplication;
+ OUString m_sComponentURL;
+
+ private:
+ css::uno::Reference< css::lang::XComponent >
+ doDispatch(
+ const ::comphelper::NamedValueCollection& i_rDispatchArgs
+ );
+
+ protected:
+ /** creates the desired view
+
+ The default implementation will call <member>fillDispatchArgs</member>, followed
+ by <member>doDispatch</member>.
+
+ @param _rDataSource
+ the data source, as passed to the <member>createNew</member> or <member>openExisting</member> method.
+ @param _rObjectName
+ the name of the object for which the view is to be opened,
+ or an empty string if a view for a new object should be created.
+ @param _rCreationArgs
+ the arguments for the view's creation
+ */
+ virtual css::uno::Reference< css::lang::XComponent > doCreateView(
+ const css::uno::Any& _rDataSource,
+ const OUString& _rObjectName,
+ const ::comphelper::NamedValueCollection& i_rCreationArgs
+ );
+
+ virtual void fillDispatchArgs(
+ ::comphelper::NamedValueCollection& i_rDispatchArgs,
+ const css::uno::Any& _rDataSource,
+ const OUString& _rObjectName
+ );
+
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >&
+ getApplicationUI() const { return m_xApplication; }
+ css::uno::Reference< css::sdbc::XConnection >
+ getConnection() const;
+
+ public:
+ DatabaseObjectView(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication,
+ const css::uno::Reference< css::frame::XFrame >& _rxParentFrame,
+ const OUString& _rComponentURL
+ );
+ virtual ~DatabaseObjectView(){}
+
+ /** sets the target frame into which the view should be loaded.
+
+ By default, the view is loaded into a top-level frame not being part of the
+ Desktop.
+ */
+ void setTargetFrame( const css::uno::Reference< css::frame::XFrame >& _rxFrame )
+ {
+ m_xFrameLoader.set( _rxFrame, css::uno::UNO_QUERY );
+ }
+
+ /** opens a view for a to-be-created object
+
+ @param _xDataSource
+ the data source for which a new object is to be created
+ @return
+ the controller of the newly created document
+ */
+ css::uno::Reference< css::lang::XComponent >
+ createNew(
+ const css::uno::Reference< css::sdbc::XDataSource >& _xDataSource,
+ const ::comphelper::NamedValueCollection& i_rDispatchArgs = ::comphelper::NamedValueCollection()
+ );
+
+ /** opens a view for an existent object
+
+ @param _xDataSource
+ the data source for which a new object is to be created
+ @param _rObjectName
+ the name of the object to be edited
+ @param _rArgs
+ Additional settings which should be forwarded to the frame
+ @return
+ the frame into which the view has been loaded
+ */
+ css::uno::Reference< css::lang::XComponent >
+ openExisting(
+ const css::uno::Any& _aDataSource,
+ const OUString& _rName,
+ const ::comphelper::NamedValueCollection& i_rDispatchArgs
+ );
+ };
+
+ // QueryDesigner
+ class QueryDesigner final : public DatabaseObjectView
+ {
+ sal_Int32 m_nCommandType;
+
+ virtual void fillDispatchArgs(
+ ::comphelper::NamedValueCollection& i_rDispatchArgs,
+ const css::uno::Any& _aDataSource,
+ const OUString& _rObjectName
+ ) override;
+
+ public:
+ QueryDesigner(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication,
+ const css::uno::Reference< css::frame::XFrame >& _rxParentFrame,
+ bool _bCreateView
+ );
+ };
+
+ // TableDesigner
+ class TableDesigner : public DatabaseObjectView
+ {
+ protected:
+ virtual void fillDispatchArgs(
+ ::comphelper::NamedValueCollection& i_rDispatchArgs,
+ const css::uno::Any& _aDataSource,
+ const OUString& _rObjectName
+ ) override;
+
+ virtual css::uno::Reference< css::lang::XComponent > doCreateView(
+ const css::uno::Any& _rDataSource,
+ const OUString& _rObjectName,
+ const ::comphelper::NamedValueCollection& i_rCreationArgs
+ ) override;
+
+ public:
+ TableDesigner(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication,
+ const css::uno::Reference< css::frame::XFrame >& _rxParentFrame
+ );
+
+ private:
+ /** retrieves the table designer component as provided by the connection, if any
+ @param _rTableName
+ the name of the table for which a designer is to be obtained
+ @return
+ the designer component, as provided by the connection, or <NULL/>, if the connection
+ does not provide a specialized designer.
+ @see css::sdb::application::XTableUIProvider
+ */
+ css::uno::Reference< css::uno::XInterface >
+ impl_getConnectionProvidedDesigner_nothrow( const OUString& _rTableName );
+ };
+
+ // ResultSetBrowser
+ class ResultSetBrowser : public DatabaseObjectView
+ {
+ private:
+ bool m_bTable;
+
+ protected:
+ virtual void fillDispatchArgs(
+ ::comphelper::NamedValueCollection& i_rDispatchArgs,
+ const css::uno::Any& _aDataSource,
+ const OUString& _rQualifiedName
+ ) override;
+
+ public:
+ ResultSetBrowser(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication,
+ const css::uno::Reference< css::frame::XFrame >& _rxParentFrame,
+ bool _bTable
+ );
+
+ };
+ // RelationDesigner
+ class RelationDesigner : public DatabaseObjectView
+ {
+ public:
+ RelationDesigner(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication,
+ const css::uno::Reference< css::frame::XFrame >& _rxParentFrame
+ );
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/datasourceconnector.hxx b/dbaccess/source/ui/inc/datasourceconnector.hxx
new file mode 100644
index 000000000..541c49607
--- /dev/null
+++ b/dbaccess/source/ui/inc/datasourceconnector.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+
+namespace dbtools
+{
+ class SQLExceptionInfo;
+}
+
+namespace weld { class Window; }
+namespace dbaui
+{
+
+ // ODatasourceConnector
+ class ODatasourceConnector final
+ {
+ weld::Window* m_pErrorMessageParent;
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+ OUString m_sContextInformation;
+
+ public:
+ ODatasourceConnector(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ weld::Window* _pMessageParent
+ );
+ ODatasourceConnector(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ weld::Window* _pMessageParent,
+ const OUString& _rContextInformation
+ );
+
+ /// returns <TRUE/> if the object is able to create data source connections
+ bool isValid() const { return m_xContext.is(); }
+
+ /** creates a connection to the data source, displays the possible error to the user, or returns it
+ */
+ css::uno::Reference< css::sdbc::XConnection >
+ connect(
+ const OUString& _rDataSourceName,
+ ::dbtools::SQLExceptionInfo* _pErrorInfo
+ ) const;
+
+ /** creates a connection to the data source, displays the possible error to the user, or returns it
+ */
+ css::uno::Reference< css::sdbc::XConnection >
+ connect(
+ const css::uno::Reference< css::sdbc::XDataSource>& _xDataSource,
+ ::dbtools::SQLExceptionInfo* _pErrorInfo
+ ) const;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dbadmin.hxx b/dbaccess/source/ui/inc/dbadmin.hxx
new file mode 100644
index 000000000..8caf3c129
--- /dev/null
+++ b/dbaccess/source/ui/inc/dbadmin.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+#include <dsntypes.hxx>
+#include "IItemSetHelper.hxx"
+#include <unotools/resmgr.hxx>
+#include <memory>
+
+namespace com::sun::star {
+ namespace beans {
+ class XPropertySet;
+ }
+ namespace sdbc {
+ class XConnection;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+}
+
+namespace dbaui
+{
+
+// ODbAdminDialog
+class ODbDataSourceAdministrationHelper;
+/** tab dialog for administrating the office wide registered data sources
+*/
+class ODbAdminDialog final : public SfxTabDialogController, public IItemSetHelper, public IDatabaseSettingsDialog
+{
+private:
+ std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl;
+
+ OString m_sMainPageID;
+
+public:
+ /** ctor. The itemset given should have been created by <method>createItemSet</method> and should be destroyed
+ after the dialog has been destroyed
+ */
+ ODbAdminDialog(weld::Window* pParent, SfxItemSet const * _pItems,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+ virtual ~ODbAdminDialog() override;
+
+ /** create and return an item set for use with the dialog.
+ @param _pTypeCollection pointer to an <type>ODatasourceMap</type>. May be NULL, in this case
+ the pool will not contain a typecollection default.
+ */
+ static void createItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults, ::dbaccess::ODsnTypeCollection* _pTypeCollection);
+ /** destroy and item set / item pool / pool defaults previously created by <method>createItemSet</method>
+ */
+ static void destroyItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Reference<SfxItemPool>& _rpPool, std::vector<SfxPoolItem*>*& _rpDefaults);
+
+ /** selects the DataSource
+ @param _rName
+ The name of the data source
+ */
+ void selectDataSource(const css::uno::Any& _aDataSourceName);
+
+ virtual const SfxItemSet* getOutputSet() const override;
+ virtual SfxItemSet* getWriteOutputSet() override;
+
+ // forwards to ODbDataSourceAdministrationHelper
+ virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override;
+ virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override;
+ virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override;
+ virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override;
+ virtual void clearPassword() override;
+ virtual void saveDatasource() override;
+ virtual void setTitle(const OUString& _sTitle) override;
+ virtual void enableConfirmSettings( bool _bEnable ) override;
+
+private:
+ // adds a new detail page and remove all the old ones
+ void addDetailPage(const OString& rPageId, TranslateId pTextId, CreateTabPage pCreateFunc);
+
+ virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override;
+ virtual short Ok() override;
+
+ /// select a datasource with a given name, adjust the item set accordingly, and everything like that ..
+ void impl_selectDataSource(const css::uno::Any& _aDataSourceName);
+ /// reset the tag pages according to m_sCurrentDatasource and <arg>_rxDatasource</arg>
+ void impl_resetPages(const css::uno::Reference< css::beans::XPropertySet >& _rxDatasource);
+
+ enum ApplyResult
+ {
+ AR_LEAVE_MODIFIED, // something was modified and has successfully been committed
+ AR_KEEP // don't leave the page (e.g. because an error occurred)
+ };
+ /** apply all changes made
+ */
+ ApplyResult implApplyChanges();
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dbexchange.hxx b/dbaccess/source/ui/inc/dbexchange.hxx
new file mode 100644
index 000000000..7fb0c6ee0
--- /dev/null
+++ b/dbaccess/source/ui/inc/dbexchange.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TokenWriter.hxx"
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <svx/dbaexchange.hxx>
+
+#include <rtl/ref.hxx>
+
+namespace com::sun::star::uno {
+ class XComponentContext;
+}
+
+namespace dbaui
+{
+
+ class ORTFImportExport;
+ class OHTMLImportExport;
+
+ class ODataClipboard : public svx::ODataAccessObjectTransferable
+
+ {
+ ::rtl::Reference< OHTMLImportExport > m_pHtml;
+ ::rtl::Reference< ORTFImportExport > m_pRtf;
+
+ public:
+ ODataClipboard();
+
+ ODataClipboard(
+ const css::uno::Reference< css::beans::XPropertySet >& i_rAliveForm,
+ const css::uno::Sequence< css::uno::Any >& i_rSelectedRows,
+ const bool i_bBookmarkSelection,
+ const css::uno::Reference< css::uno::XComponentContext >& i_rORB
+ );
+
+ void Update(
+ const OUString& _rDatasource,
+ const sal_Int32 _nCommandType,
+ const OUString& _rCommand,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxFormatter,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ );
+
+ void Update(
+ const OUString& _rDatasource,
+ const sal_Int32 _nCommandType,
+ const OUString& _rCommand,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxFormatter,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ );
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ protected:
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual void ObjectReleased() override;
+ virtual bool WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& rFlavor ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dbtreelistbox.hxx b/dbaccess/source/ui/inc/dbtreelistbox.hxx
new file mode 100644
index 000000000..7682841a2
--- /dev/null
+++ b/dbaccess/source/ui/inc/dbtreelistbox.hxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+namespace dbaui
+{
+ class IEntryFilter
+ {
+ public:
+ virtual bool includeEntry(const void* pUserData) const = 0;
+
+ protected:
+ ~IEntryFilter() {}
+ };
+
+ class IControlActionListener;
+ class IContextMenuProvider;
+
+ class TreeListBox;
+
+ class TreeListBoxDropTarget : public DropTargetHelper
+ {
+ private:
+ TreeListBox& m_rTreeView;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ public:
+ TreeListBoxDropTarget(TreeListBox& rTreeView);
+ };
+
+ class TreeListBox
+ {
+ protected:
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ TreeListBoxDropTarget m_aDropTargetHelper;
+
+ std::unique_ptr<weld::TreeIter> m_xDragedEntry;
+ IControlActionListener* m_pActionListener;
+ IContextMenuProvider* m_pContextMenuProvider;
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString);
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+ DECL_LINK(DragBeginHdl, bool&, bool);
+
+ private:
+ Timer m_aTimer; // is needed for table updates
+ rtl::Reference<TransferDataContainer> m_xHelper;
+
+ Link<LinkParamNone*,void> m_aSelChangeHdl; // handler to be called (asynchronously) when the selection changes in any way
+ Link<LinkParamNone*,void> m_aCopyHandler; // called when someone press CTRL+C
+ Link<LinkParamNone*,void> m_aPasteHandler; // called when someone press CTRL+V
+ Link<LinkParamNone*,void> m_aDeleteHandler; // called when someone press DELETE Key
+
+ DECL_LINK(OnTimeOut, Timer*, void);
+
+ protected:
+ void implStopSelectionTimer();
+ void implStartSelectionTimer();
+
+ virtual bool DoChildKeyInput(const KeyEvent& rKEvt);
+
+ public:
+ TreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bSQLType);
+ virtual ~TreeListBox();
+
+ std::unique_ptr<weld::TreeIter> GetEntryPosByName(std::u16string_view rName,
+ const weld::TreeIter* pStart = nullptr,
+ const IEntryFilter* pFilter = nullptr) const;
+
+ std::unique_ptr<weld::TreeIter> GetRootLevelParent(const weld::TreeIter* pEntry) const;
+
+ void setControlActionListener(IControlActionListener* pListener) { m_pActionListener = pListener; }
+ void setContextMenuProvider(IContextMenuProvider* pContextMenuProvider) { m_pContextMenuProvider = pContextMenuProvider; }
+
+ weld::TreeView& GetWidget() { return *m_xTreeView; }
+ const weld::TreeView& GetWidget() const { return *m_xTreeView; }
+
+ TransferDataContainer& GetDataTransfer() { return *m_xHelper; }
+
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
+
+ void SetSelChangeHdl( const Link<LinkParamNone*,void>& _rHdl ) { m_aSelChangeHdl = _rHdl; }
+ void setCopyHandler(const Link<LinkParamNone*,void>& _rHdl) { m_aCopyHandler = _rHdl; }
+ void setPasteHandler(const Link<LinkParamNone*,void>& _rHdl) { m_aPasteHandler = _rHdl; }
+ void setDeleteHandler(const Link<LinkParamNone*,void>& _rHdl) { m_aDeleteHandler = _rHdl; }
+ };
+
+ class InterimDBTreeListBox : public InterimItemWindow
+ , public TreeListBox
+ {
+ private:
+ std::unique_ptr<weld::Label> m_xStatusBar;
+ public:
+ InterimDBTreeListBox(vcl::Window* pParent);
+ virtual void dispose() override;
+ weld::Label& GetStatusBar() { return *m_xStatusBar; }
+ virtual ~InterimDBTreeListBox() override;
+ void show_container() { m_xContainer->show(); }
+ protected:
+ virtual bool DoChildKeyInput(const KeyEvent& rKEvt) override;
+ };
+
+ class DBTreeViewBase
+ {
+ protected:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<TreeListBox> m_xTreeListBox;
+ public:
+ DBTreeViewBase(weld::Container* pContainer);
+ virtual ~DBTreeViewBase();
+
+ weld::TreeView& GetWidget() { return m_xTreeListBox->GetWidget(); }
+ const weld::TreeView& GetWidget() const { return m_xTreeListBox->GetWidget(); }
+
+ TreeListBox& getListBox() const { return *m_xTreeListBox; }
+
+ void hide() { m_xContainer->hide(); }
+ void show() { m_xContainer->show(); }
+ bool get_visible() const { return m_xContainer->get_visible(); }
+ };
+
+ class DBTreeView final : public DBTreeViewBase
+ {
+ public:
+ DBTreeView(weld::Container* pContainer, bool bSQLType);
+ };
+
+ class DBTableTreeView final : public DBTreeViewBase
+ {
+ public:
+ DBTableTreeView(weld::Container* pContainer);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dbu_dlg.hxx b/dbaccess/source/ui/inc/dbu_dlg.hxx
new file mode 100644
index 000000000..ed97c4c93
--- /dev/null
+++ b/dbaccess/source/ui/inc/dbu_dlg.hxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#define WIZARD_PAGE_X 56
+#define WIZARD_PAGE_Y 30
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dbwiz.hxx b/dbaccess/source/ui/inc/dbwiz.hxx
new file mode 100644
index 000000000..0c51ab1a9
--- /dev/null
+++ b/dbaccess/source/ui/inc/dbwiz.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <dsntypes.hxx>
+#include "IItemSetHelper.hxx"
+#include <vcl/wizardmachine.hxx>
+#include <memory>
+
+namespace com::sun::star {
+ namespace beans {
+ class XPropertySet;
+ }
+ namespace sdbc {
+ class XConnection;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+}
+
+using vcl::WizardTypes::WizardState;
+using vcl::WizardTypes::CommitPageReason;
+
+namespace dbaccess
+{
+ class ODsnTypeCollection;
+}
+namespace dbaui
+{
+
+// ODbTypeWizDialog
+class OGeneralPage;
+class ODbDataSourceAdministrationHelper;
+/** tab dialog for administrating the office wide registered data sources
+*/
+class ODbTypeWizDialog : public vcl::WizardMachine , public IItemSetHelper, public IDatabaseSettingsDialog
+{
+private:
+ std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl;
+ std::unique_ptr<SfxItemSet> m_pOutSet;
+ ::dbaccess::ODsnTypeCollection*
+ m_pCollection; /// the DSN type collection instance
+ OUString m_eType;
+
+public:
+ /** ctor. The itemset given should have been created by <method>createItemSet</method> and should be destroyed
+ after the dialog has been destroyed
+ */
+ ODbTypeWizDialog(weld::Window* pParent
+ ,SfxItemSet const * _pItems
+ ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ ,const css::uno::Any& _aDataSourceName
+ );
+ virtual ~ODbTypeWizDialog() override;
+
+ virtual const SfxItemSet* getOutputSet() const override;
+ virtual SfxItemSet* getWriteOutputSet() override;
+
+ // forwards to ODbDataSourceAdministrationHelper
+ virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override;
+ virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override;
+ virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override;
+ virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override;
+ virtual void clearPassword() override;
+ virtual void saveDatasource() override;
+ virtual void setTitle(const OUString& _sTitle) override;
+ virtual void enableConfirmSettings( bool _bEnable ) override;
+
+protected:
+ /// to override to create new pages
+ virtual std::unique_ptr<BuilderPage> createPage(WizardState _nState) override;
+ virtual WizardState determineNextState(WizardState _nCurrentState) const override;
+ virtual bool leaveState(WizardState _nState) override;
+ virtual ::vcl::IWizardPageController* getPageController(BuilderPage* pCurrentPage) const override;
+ virtual bool onFinish() override;
+
+private:
+ DECL_LINK(OnTypeSelected, OGeneralPage&, void);
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dbwizsetup.hxx b/dbaccess/source/ui/inc/dbwizsetup.hxx
new file mode 100644
index 000000000..0829b328d
--- /dev/null
+++ b/dbaccess/source/ui/inc/dbwizsetup.hxx
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <dsntypes.hxx>
+#include "IItemSetHelper.hxx"
+#include <tools/urlobj.hxx>
+#include <memory>
+#include <vcl/roadmapwizard.hxx>
+
+namespace com::sun::star {
+ namespace beans {
+ class XPropertySet;
+ }
+ namespace sdbc {
+ class XConnection;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+}
+
+using vcl::WizardTypes::WizardState;
+using vcl::WizardTypes::CommitPageReason;
+using vcl::RoadmapWizardTypes::PathId;
+
+namespace dbaui
+{
+
+class OGenericAdministrationPage;
+
+// ODbTypeWizDialogSetup
+class OGeneralPage;
+class OGeneralPageWizard;
+class ODbDataSourceAdministrationHelper;
+/** tab dialog for administrating the office wide registered data sources
+*/
+class OMySQLIntroPageSetup;
+class OFinalDBPageSetup;
+
+class ODbTypeWizDialogSetup final : public vcl::RoadmapWizardMachine, public IItemSetHelper, public IDatabaseSettingsDialog
+{
+private:
+ std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl;
+ std::unique_ptr<SfxItemSet> m_pOutSet;
+ OUString m_sURL;
+ OUString m_sOldURL;
+ bool m_bIsConnectable : 1;
+ OUString m_sRM_IntroText;
+ OUString m_sRM_dBaseText;
+ OUString m_sRM_TextText;
+ OUString m_sRM_MSAccessText;
+ OUString m_sRM_LDAPText;
+ OUString m_sRM_ADOText;
+ OUString m_sRM_JDBCText;
+ OUString m_sRM_MySQLNativePageTitle;
+ OUString m_sRM_OracleText;
+ OUString m_sRM_MySQLText;
+ OUString m_sRM_ODBCText;
+ OUString m_sRM_DocumentOrSpreadSheetText;
+ OUString m_sRM_AuthentificationText;
+ OUString m_sRM_FinalText;
+ INetURLObject m_aDocURL;
+ OUString m_sWorkPath;
+ OGeneralPageWizard* m_pGeneralPage;
+ OMySQLIntroPageSetup* m_pMySQLIntroPage;
+ OFinalDBPageSetup* m_pFinalPage;
+
+ ::dbaccess::ODsnTypeCollection*
+ m_pCollection; /// the DSN type collection instance
+
+public:
+ /** ctor. The itemset given should have been created by <method>createItemSet</method> and should be destroyed
+ after the dialog has been destroyed
+ */
+ ODbTypeWizDialogSetup(weld::Window* pParent
+ ,SfxItemSet const * _pItems
+ ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ ,const css::uno::Any& _aDataSourceName
+ );
+ virtual ~ODbTypeWizDialogSetup() override;
+
+ virtual const SfxItemSet* getOutputSet() const override;
+ virtual SfxItemSet* getWriteOutputSet() override;
+
+ // forwards to ODbDataSourceAdministrationHelper
+ virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override;
+ virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override;
+ virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override;
+ virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override;
+ virtual void clearPassword() override;
+ virtual void setTitle(const OUString& _sTitle) override;
+ virtual void enableConfirmSettings( bool _bEnable ) override;
+ virtual void saveDatasource() override;
+ virtual OUString getStateDisplayName( WizardState _nState ) const override;
+
+ /** returns <TRUE/> if the database should be opened, otherwise <FALSE/>.
+ */
+ bool IsDatabaseDocumentToBeOpened() const;
+
+ /** returns <TRUE/> if the table wizard should be opened, otherwise <FALSE/>.
+ */
+ bool IsTableWizardToBeStarted() const;
+
+ void SetIntroPage(OMySQLIntroPageSetup* pPage);
+ void SetGeneralPage(OGeneralPageWizard* pPage);
+ void SetFinalPage(OFinalDBPageSetup* pPage);
+
+private:
+ /// to override to create new pages
+ virtual std::unique_ptr<BuilderPage> createPage(WizardState _nState) override;
+ virtual bool leaveState(WizardState _nState) override;
+ virtual void enterState(WizardState _nState) override;
+ virtual ::vcl::IWizardPageController* getPageController(BuilderPage* pCurrentPage) const override;
+ virtual bool onFinish() override;
+
+ void resetPages(const css::uno::Reference< css::beans::XPropertySet >& _rxDatasource);
+
+ /** declares a path with or without authentication, as indicated by the database type
+
+ @param _sURL
+ the data source type for which the path is declared. If this
+ data source type does not support authentication, the PAGE_DBSETUPWIZARD_AUTHENTIFICATION
+ state will be stripped from the sequence of states.
+ @param _nPathId
+ the ID of the path
+ @path
+ the first state in this path, following by an arbitrary number of others, as in
+ RoadmapWizard::declarePath.
+ */
+ void declareAuthDepPath( const OUString& _sURL, PathId _nPathId, const vcl::RoadmapWizardTypes::WizardPath& _rPaths);
+
+ void RegisterDataSourceByLocation(std::u16string_view sPath);
+ bool SaveDatabaseDocument();
+ void activateDatabasePath();
+ OUString createUniqueFileName(const INetURLObject& rURL);
+ void CreateDatabase();
+ void createUniqueFolderName(INetURLObject* pURL);
+ ::dbaccess::DATASOURCE_TYPE VerifyDataSourceType(const ::dbaccess::DATASOURCE_TYPE DatabaseType) const;
+
+ void updateTypeDependentStates();
+ bool callSaveAsDialog();
+ DECL_LINK(OnTypeSelected, OGeneralPage&, void);
+ DECL_LINK(OnChangeCreationMode, OGeneralPageWizard&, void);
+ DECL_LINK(OnRecentDocumentSelected, OGeneralPageWizard&, void);
+ DECL_LINK(OnSingleDocumentChosen, OGeneralPageWizard&, void);
+ DECL_LINK(ImplClickHdl, OMySQLIntroPageSetup*, void);
+ DECL_LINK(ImplModifiedHdl, OGenericAdministrationPage const *, void);
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/defaultobjectnamecheck.hxx b/dbaccess/source/ui/inc/defaultobjectnamecheck.hxx
new file mode 100644
index 000000000..59705fe61
--- /dev/null
+++ b/dbaccess/source/ui/inc/defaultobjectnamecheck.hxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "objectnamecheck.hxx"
+
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <memory>
+
+namespace dbaui
+{
+
+ // HierarchicalNameCheck
+ struct HierarchicalNameCheck_Impl;
+ /** class implementing the IObjectNameCheck interface, and checking given object names
+ against a hierarchical name container
+ */
+ class HierarchicalNameCheck :public IObjectNameCheck
+ {
+ private:
+ std::unique_ptr< HierarchicalNameCheck_Impl > m_pImpl;
+
+ public:
+ /** constructs a HierarchicalNameCheck instance
+ @param _rxNames
+ the hierarchical container of named objects, against which given names should be
+ checked
+ @param _rRelativeRoot
+ the root in the hierarchy against which given names should be checked
+ @throws css::lang::IllegalArgumentException
+ if the given container is <NULL/>
+ */
+ HierarchicalNameCheck(
+ const css::uno::Reference< css::container::XHierarchicalNameAccess >& _rxNames,
+ const OUString& _rRelativeRoot
+ );
+
+ virtual ~HierarchicalNameCheck() override;
+
+ HierarchicalNameCheck(const HierarchicalNameCheck&) = delete;
+ const HierarchicalNameCheck& operator=(const HierarchicalNameCheck&) = delete;
+
+ // IObjectNameCheck overridables
+ virtual bool isNameValid(
+ const OUString& _rObjectName,
+ ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay
+ ) const override;
+ };
+
+ // DynamicTableOrQueryNameCheck
+ struct DynamicTableOrQueryNameCheck_Impl;
+ /** class implementing the IObjectNameCheck interface, and checking a given name
+ for being valid as either a query or a table name.
+
+ The class can be parametrized to act as either table name or query name validator.
+
+ For databases which support queries in queries, the name check is implicitly extended
+ to both queries and tables, no matter which category is checked. This prevents, for
+ such databases, that users can create a query with the name of an existing table,
+ or vice versa.
+
+ @seealso dbtools::DatabaseMetaData::supportsSubqueriesInFrom
+ @seealso css::sdb::tools::XObjectNames::checkNameForCreate
+ */
+ class DynamicTableOrQueryNameCheck :public IObjectNameCheck
+ {
+ private:
+ std::unique_ptr< DynamicTableOrQueryNameCheck_Impl > m_pImpl;
+
+ public:
+ /** constructs a DynamicTableOrQueryNameCheck instance
+ @param _rxSdbLevelConnection
+ a connection supporting the css.sdb.Connection service, in other word, it
+ does expose the XTablesSupplier and XQueriesSupplier interfaces.
+ @param _nCommandType
+ specifies whether table names or query names should be checked. Only valid values
+ are CommandType::TABLE and CommandType::QUERY.
+ @throws css::lang::IllegalArgumentException
+ if the given connection is <NULL/>, or the given command type is neither
+ CommandType::TABLE nor CommandType::QUERY.
+ */
+ DynamicTableOrQueryNameCheck(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxSdbLevelConnection,
+ sal_Int32 _nCommandType
+ );
+
+ virtual ~DynamicTableOrQueryNameCheck() override;
+
+ DynamicTableOrQueryNameCheck(const DynamicTableOrQueryNameCheck&) = delete;
+ const DynamicTableOrQueryNameCheck& operator=(const DynamicTableOrQueryNameCheck&) = delete;
+
+ // IObjectNameCheck overridables
+ virtual bool isNameValid(
+ const OUString& _rObjectName,
+ ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay
+ ) const override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/directsql.hxx b/dbaccess/source/ui/inc/directsql.hxx
new file mode 100644
index 000000000..bfe8195fc
--- /dev/null
+++ b/dbaccess/source/ui/inc/directsql.hxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vcl/weld.hxx>
+#include <deque>
+#include <string_view>
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <unotools/eventlisteneradapter.hxx>
+#include <osl/mutex.hxx>
+
+#include "sqledit.hxx"
+
+struct ImplSVEvent;
+
+namespace dbaui
+{
+ // DirectSQLDialog
+ class DirectSQLDialog final
+ : public weld::GenericDialogController
+ , public ::utl::OEventListenerAdapter
+ {
+ ::osl::Mutex m_aMutex;
+
+ std::unique_ptr<weld::Button> m_xExecute;
+ std::unique_ptr<weld::ComboBox> m_xSQLHistory;
+ std::unique_ptr<weld::TextView> m_xStatus;
+ std::unique_ptr<weld::CheckButton> m_xDirectSQL;
+ std::unique_ptr<weld::CheckButton> m_xShowOutput;
+ std::unique_ptr<weld::TextView> m_xOutput;
+ std::unique_ptr<weld::Button> m_xClose;
+ std::unique_ptr<SQLEditView> m_xSQL;
+ std::unique_ptr<weld::CustomWeld> m_xSQLEd;
+
+ typedef std::deque< OUString > StringQueue;
+ StringQueue m_aStatementHistory; // previous statements
+ StringQueue m_aNormalizedHistory; // previous statements, normalized to be used in the list box
+
+ sal_Int32 m_nStatusCount;
+
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xConnection;
+
+ ImplSVEvent* m_pClosingEvent;
+
+ public:
+ DirectSQLDialog(
+ weld::Window* _pParent,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn);
+ virtual ~DirectSQLDialog() override;
+
+ /// number of history entries
+ sal_Int32 getHistorySize() const;
+
+ private:
+ void executeCurrent();
+ void switchToHistory(sal_Int32 _nHistoryPos);
+
+ // OEventListenerAdapter
+ virtual void _disposing( const css::lang::EventObject& _rSource ) override;
+
+ DECL_LINK( OnExecute, weld::Button&, void );
+ DECL_LINK( OnClose, void*, void );
+ DECL_LINK( OnCloseClick, weld::Button&, void );
+ DECL_LINK( OnListEntrySelected, weld::ComboBox&, void );
+ DECL_LINK( OnStatementModified, LinkParamNone*, void );
+
+ /// adds a statement to the statement history
+ void implAddToStatementHistory(const OUString& _rStatement);
+
+ /// ensures that our history has at most m_nHistoryLimit entries
+ void implEnsureHistoryLimit();
+
+ /// executes the statement given, adds the status to the status list
+ void implExecuteStatement(const OUString& _rStatement);
+
+ /// adds a status text to the status list
+ void addStatusText(std::u16string_view _rMessage);
+
+ /// adds a status text to the output list
+ void addOutputText(std::u16string_view _rMessage);
+
+ /// displays resultset
+ void display(const css::uno::Reference< css::sdbc::XResultSet >& xRS);
+
+#ifdef DBG_UTIL
+ const char* impl_CheckInvariants() const;
+#endif
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dlgattr.hxx b/dbaccess/source/ui/inc/dlgattr.hxx
new file mode 100644
index 000000000..6c3a00f95
--- /dev/null
+++ b/dbaccess/source/ui/inc/dlgattr.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+class SvxNumberInfoItem;
+class SfxItemSet;
+class SvNumberFormatter;
+namespace dbaui
+{
+
+ class SbaSbAttrDlg : public SfxTabDialogController
+ {
+ std::unique_ptr<SvxNumberInfoItem> pNumberInfoItem;
+
+ public:
+ SbaSbAttrDlg(weld::Widget* pParent, const SfxItemSet*, SvNumberFormatter*, bool bHasFormat);
+ virtual ~SbaSbAttrDlg() override;
+
+ virtual void PageCreated(const OString& rPageId, SfxTabPage& rTabPage) override;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dlgsave.hxx b/dbaccess/source/ui/inc/dlgsave.hxx
new file mode 100644
index 000000000..d56fc6ade
--- /dev/null
+++ b/dbaccess/source/ui/inc/dlgsave.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <o3tl/typed_flags_set.hxx>
+#include <vcl/weld.hxx>
+#include <memory>
+
+namespace com::sun::star {
+ namespace sdbc {
+ class XConnection;
+ }
+}
+
+enum class SADFlags {
+ NONE = 0x0000,
+ AdditionalDescription = 0x0001,
+ TitlePasteAs = 0x0100,
+ TitleRename = 0x0200,
+};
+namespace o3tl {
+ template<> struct typed_flags<SADFlags> : is_typed_flags<SADFlags, 0x0301> {};
+}
+
+namespace dbaui
+{
+ class OSaveAsDlgImpl;
+ class IObjectNameCheck;
+ class OSaveAsDlg : public weld::GenericDialogController
+ {
+ private:
+ std::unique_ptr<OSaveAsDlgImpl> m_pImpl;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ public:
+ OSaveAsDlg( weld::Window * pParent, sal_Int32 _rType,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const OUString& rDefault,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags);
+
+ OSaveAsDlg( weld::Window* _pParent,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const OUString& _rDefault,
+ const OUString& _sLabel,
+ const IObjectNameCheck& _rObjectNameCheck,
+ SADFlags _nFlags);
+ virtual ~OSaveAsDlg() override;
+
+ const OUString& getName() const;
+ OUString getCatalog() const;
+ OUString getSchema() const;
+ private:
+ DECL_LINK(ButtonClickHdl, weld::Button&, void);
+ DECL_LINK(EditModifyHdl, weld::Entry&, void);
+
+ void implInitOnlyTitle(const OUString& _rLabel);
+ void implInit();
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dlgsize.hxx b/dbaccess/source/ui/inc/dlgsize.hxx
new file mode 100644
index 000000000..5a673d712
--- /dev/null
+++ b/dbaccess/source/ui/inc/dlgsize.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+
+ class DlgSize final : public weld::GenericDialogController
+ {
+ private:
+ sal_Int32 m_nPrevValue;
+ void SetValue( sal_Int32 nVal );
+
+ DECL_LINK(CbClickHdl, weld::Toggleable&, void);
+
+ std::unique_ptr<weld::MetricSpinButton> m_xMF_VALUE;
+ std::unique_ptr<weld::CheckButton> m_xCB_STANDARD;
+
+ public:
+ DlgSize(weld::Window * pParent, sal_Int32 nVal, bool bRow, sal_Int32 _nAlternativeStandard = -1);
+ virtual ~DlgSize() override;
+ sal_Int32 GetValue() const;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dsitems.hxx b/dbaccess/source/ui/inc/dsitems.hxx
new file mode 100644
index 000000000..09410d31b
--- /dev/null
+++ b/dbaccess/source/ui/inc/dsitems.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+typedef sal_Int32 ItemID;
+
+// item ids for the data source administration dialog
+
+#define DSID_NAME 1 // name of a data source, SfxStringItem
+#define DSID_ORIGINALNAME 2 // original name, internal, SfxStringItem
+#define DSID_CONNECTURL 3 // connection URL, SfxStringItem
+#define DSID_TABLEFILTER 4 // table filter, OStringListItem
+#define DSID_TYPECOLLECTION 5 // collection of data source types, ODsnTypeCollection
+#define DSID_INVALID_SELECTION 6 // is the selection (thus the set data) invalid?, SfxBoolItem
+#define DSID_READONLY 7 // is the selection (thus the set data) readonly?, SfxBoolItem
+#define DSID_USER 8 // the user name used for logon, SfxStringItem
+#define DSID_PASSWORD 9 // the password used for logon, SfxStringItem
+#define DSID_ADDITIONALOPTIONS 10 // additional options used for connecting, SfxStringItem
+#define DSID_CHARSET 11 // character set to use, SfxStringItem by now
+#define DSID_PASSWORDREQUIRED 12 // is the password required to connect?, SfxBoolItem
+#define DSID_SHOWDELETEDROWS 13 // show deleted rows?, SfxBoolItem
+#define DSID_ALLOWLONGTABLENAMES 14 // allow tables names longer than 8.3?, SfxBoolItem
+#define DSID_JDBCDRIVERCLASS 15 // JDBC driver class, SfxStringItem
+#define DSID_FIELDDELIMITER 16 // field delimiter, SfxUInt16Item
+#define DSID_TEXTDELIMITER 17 // text delimiter, SfxUInt16Item
+#define DSID_DECIMALDELIMITER 18 // decimal delimiter, SfxUInt16Item
+#define DSID_THOUSANDSDELIMITER 19 // thousands delimiter, SfxUInt16Item
+#define DSID_TEXTFILEEXTENSION 20 // extension for text files, SfxStringItem
+#define DSID_TEXTFILEHEADER 21 // the text file contains a header?, SfxBoolItem
+#define DSID_PARAMETERNAMESUBST 22
+#define DSID_CONN_PORTNUMBER 23
+#define DSID_SUPPRESSVERSIONCL 24 // meta data: sal_True if the data source described by the set is to-be-deleted
+#define DSID_CONN_SHUTSERVICE 25
+#define DSID_CONN_DATAINC 26
+#define DSID_CONN_CACHESIZE 27
+#define DSID_CONN_CTRLUSER 28
+#define DSID_CONN_CTRLPWD 29
+#define DSID_USECATALOG 30 // should the driver use the catalog name when the database is filebased
+#define DSID_CONN_HOSTNAME 31
+#define DSID_CONN_LDAP_BASEDN 32
+#define DSID_CONN_LDAP_PORTNUMBER 33
+#define DSID_CONN_LDAP_ROWCOUNT 34
+#define DSID_SQL92CHECK 35
+#define DSID_AUTOINCREMENTVALUE 36
+#define DSID_AUTORETRIEVEVALUE 37
+#define DSID_AUTORETRIEVEENABLED 38
+#define DSID_APPEND_TABLE_ALIAS 39
+#define DSID_MYSQL_PORTNUMBER 40
+#define DSID_IGNOREDRIVER_PRIV 41
+#define DSID_BOOLEANCOMPARISON 42
+#define DSID_ORACLE_PORTNUMBER 43
+#define DSID_ENABLEOUTERJOIN 44
+#define DSID_CATALOG 45
+#define DSID_SCHEMA 46
+#define DSID_INDEXAPPENDIX 47
+#define DSID_CONN_LDAP_USESSL 48
+#define DSID_DOCUMENT_URL 49
+#define DSID_DOSLINEENDS 50
+#define DSID_DATABASENAME 51
+#define DSID_AS_BEFORE_CORRNAME 52
+#define DSID_CHECK_REQUIRED_FIELDS 53
+#define DSID_IGNORECURRENCY 54
+#define DSID_CONN_SOCKET 55
+#define DSID_ESCAPE_DATETIME 56
+#define DSID_NAMED_PIPE 57
+#define DSID_PRIMARY_KEY_SUPPORT 58
+#define DSID_MAX_ROW_SCAN 59
+#define DSID_RESPECTRESULTSETTYPE 60
+ // don't forget to adjust DSID_LAST_ITEM_ID below!
+
+// item range. Adjust this if you introduce new items above
+
+#define DSID_FIRST_ITEM_ID DSID_NAME
+#define DSID_LAST_ITEM_ID DSID_RESPECTRESULTSETTYPE
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/dsmeta.hxx b/dbaccess/source/ui/inc/dsmeta.hxx
new file mode 100644
index 000000000..69b13ebb7
--- /dev/null
+++ b/dbaccess/source/ui/inc/dsmeta.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <set>
+
+#include "dsitems.hxx"
+
+#include <rtl/ustring.hxx>
+
+#include <memory>
+
+namespace dbaui
+{
+
+ // AuthenticationMode
+ enum AuthenticationMode
+ {
+ AuthNone,
+ AuthUserPwd,
+ AuthPwd
+ };
+
+ // DataSourceMetaData
+ class FeatureSet;
+ class DataSourceMetaData_Impl;
+ /** encapsulates meta data for a data source
+
+ On the long run, this class should a) encapsulate *all* meta data which
+ currently is hard coded somewhere in the program logic and b) be initialized
+ from the configuration.
+
+ At the moment, the data a) is still hard coded in the, well, code and b)
+ contains meta data about the advanced settings only.
+ */
+ class DataSourceMetaData
+ {
+ public:
+ DataSourceMetaData( const OUString& _sURL );
+ ~DataSourceMetaData();
+
+ /// returns a struct describing this data source type's support for our known advanced settings
+ const FeatureSet& getFeatureSet() const;
+
+ /// determines whether or not the data source requires authentication
+ static AuthenticationMode getAuthentication( const OUString& _sURL );
+
+ private:
+ std::shared_ptr< DataSourceMetaData_Impl > m_pImpl;
+ };
+
+ // FeatureSet
+ /** can be used to ask for (UI) support for certain advanced features
+ */
+ class FeatureSet
+ {
+ public:
+ typedef std::set< ItemID >::const_iterator const_iterator;
+
+ public:
+ FeatureSet() { }
+
+ void put( const ItemID _id ) { m_aContent.insert( _id ); }
+ bool has( const ItemID _id ) const { return m_aContent.find( _id ) != m_aContent.end(); }
+
+ inline bool supportsAnySpecialSetting() const;
+ inline bool supportsGeneratedValues() const;
+
+ const_iterator begin() const { return m_aContent.begin(); }
+ const_iterator end() const { return m_aContent.end(); }
+
+ private:
+ std::set< ItemID > m_aContent;
+ };
+
+ inline bool FeatureSet::supportsGeneratedValues() const
+ {
+ return has( DSID_AUTORETRIEVEENABLED );
+ }
+
+ inline bool FeatureSet::supportsAnySpecialSetting() const
+ {
+ return has( DSID_SQL92CHECK )
+ || has( DSID_APPEND_TABLE_ALIAS )
+ || has( DSID_AS_BEFORE_CORRNAME )
+ || has( DSID_ENABLEOUTERJOIN )
+ || has( DSID_IGNOREDRIVER_PRIV )
+ || has( DSID_PARAMETERNAMESUBST )
+ || has( DSID_SUPPRESSVERSIONCL )
+ || has( DSID_CATALOG )
+ || has( DSID_SCHEMA )
+ || has( DSID_INDEXAPPENDIX )
+ || has( DSID_DOSLINEENDS )
+ || has( DSID_BOOLEANCOMPARISON )
+ || has( DSID_CHECK_REQUIRED_FIELDS )
+ || has( DSID_IGNORECURRENCY )
+ || has( DSID_ESCAPE_DATETIME )
+ || has( DSID_PRIMARY_KEY_SUPPORT )
+ || has( DSID_MAX_ROW_SCAN )
+ || has( DSID_RESPECTRESULTSETTYPE )
+ ;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/exsrcbrw.hxx b/dbaccess/source/ui/inc/exsrcbrw.hxx
new file mode 100644
index 000000000..0ecda1ed6
--- /dev/null
+++ b/dbaccess/source/ui/inc/exsrcbrw.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "brwctrlr.hxx"
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/uno3.hxx>
+
+// SbaExternalSourceBrowser
+
+namespace dbaui
+{
+ class SbaXFormAdapter;
+ class SbaExternalSourceBrowser final
+ :public SbaXDataBrowserController
+ ,public css::util::XModifyBroadcaster
+ {
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener> m_aModifyListeners;
+ // for multiplexing the modify events
+ rtl::Reference<SbaXFormAdapter> m_pDataSourceImpl;
+ bool m_bInQueryDispatch;
+ // our queryDispatch will ask our frame, which first will ask our queryDispatch, so we need to protect against
+ // recursion
+
+ public:
+ SbaExternalSourceBrowser(const css::uno::Reference< css::uno::XComponentContext >& _rM);
+
+ // UNO
+ DECLARE_UNO3_DEFAULTS(SbaExternalSourceBrowser, SbaXDataBrowserController)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+ // virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > getIdlClasses();
+
+ // static css::uno::Reference< css::reflection::XIdlClass > getStaticIdlClass();
+
+ // css::frame::XDispatch
+ virtual void SAL_CALL dispatch(const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ // css::frame::XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) override;
+
+ // css::util::XModifyListener
+ virtual void SAL_CALL modified(const css::lang::EventObject& aEvent) override;
+
+ // css::util::XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > & aListener) override;
+ virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener > & aListener) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL disposing() override;
+
+ // css::form::XLoadListener
+ virtual void SAL_CALL unloading(const css::lang::EventObject& aEvent) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ private:
+ virtual ~SbaExternalSourceBrowser() override;
+
+ virtual css::uno::Reference< css::sdbc::XRowSet > CreateForm() override;
+ virtual bool InitializeForm( const css::uno::Reference< css::beans::XPropertySet >& i_formProperties ) override;
+
+ virtual bool LoadForm() override;
+
+ void Attach(const css::uno::Reference< css::sdbc::XRowSet > & xMaster);
+
+ void ClearView();
+
+ void startListening();
+ void stopListening();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/formadapter.hxx b/dbaccess/source/ui/inc/formadapter.hxx
new file mode 100644
index 000000000..c6d565896
--- /dev/null
+++ b/dbaccess/source/ui/inc/formadapter.hxx
@@ -0,0 +1,436 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "sbamultiplex.hxx"
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XSQLErrorBroadcaster.hpp>
+#include <com/sun/star/sdb/XRowSetApproveBroadcaster.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/form/XReset.hpp>
+#include <com/sun/star/form/XSubmit.hpp>
+#include <com/sun/star/form/XDatabaseParameterBroadcaster.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/awt/XTabControllerModel.hpp>
+#include <com/sun/star/io/XPersistObject.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implbase12.hxx>
+#include <cppuhelper/implbase10.hxx>
+
+namespace dbaui
+{
+ // SbaXFormAdapter
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaDataSupplier
+ , css::sdb::XResultSetAccess
+ , css::sdbc::XResultSetUpdate
+ , css::sdbc::XRowSet
+ , css::sdb::XRowSetApproveBroadcaster
+ , css::sdbcx::XRowLocate
+ , css::sdbc::XRowUpdate
+ , css::sdbc::XRow
+ , css::sdbcx::XColumnsSupplier
+ , css::sdbc::XColumnLocate
+ // --- stardiv::one::form::component::DatabaseForm ---
+ , css::sdbc::XParameters
+ , css::sdbcx::XDeleteRows
+ > SbaXFormAdapter_BASE1;
+ typedef ::cppu::ImplHelper12 < css::sdbc::XWarningsSupplier
+ , css::sdbc::XCloseable
+ , css::form::XLoadable
+ , css::sdb::XSQLErrorBroadcaster
+ , css::form::XDatabaseParameterBroadcaster
+ // --- stardiv::one::form::component::Form ---
+ , css::form::XForm
+ , css::form::XSubmit
+ , css::awt::XTabControllerModel
+ // --- stardiv::one::form::FormComponent ---
+ , css::lang::XComponent
+ , css::beans::XFastPropertySet
+ // already present : css::form::XFormComponent (base of css::form::XForm)
+ , css::beans::XMultiPropertySet
+ , css::container::XNamed
+ > SbaXFormAdapter_BASE2;
+ typedef ::cppu::ImplHelper10 < css::io::XPersistObject
+ , css::beans::XPropertySet
+ // --- stardiv::one::data::DatabaseCursor ---
+ , css::util::XCancellable
+ // already present : css::beans::XPropertySet
+ // --- stardiv::one::data::DatabaseComponent ---
+ // already present : css::lang::XComponent
+ // already present : css::container::XChild (base of css::form::XForm)
+ // interfaces I don't know the service which they belong to ;)
+ // (they are supported by FmXDatabaseForm, se we support it, too)
+ , css::beans::XPropertyState
+ , css::form::XReset
+ , css::container::XNameContainer
+ , css::container::XIndexContainer
+ , css::container::XContainer
+ , css::container::XEnumerationAccess
+ // interfaces we need because of other reasons
+ , css::beans::XPropertyChangeListener
+ > SbaXFormAdapter_BASE3;
+
+ class SbaXFormAdapter final
+ :public SbaXFormAdapter_BASE1
+ ,public SbaXFormAdapter_BASE2
+ ,public SbaXFormAdapter_BASE3
+ {
+ private:
+ css::uno::Reference< css::sdbc::XRowSet > m_xMainForm;
+ ::osl::Mutex m_aMutex;
+
+ SbaXLoadMultiplexer m_aLoadListeners;
+ SbaXRowSetMultiplexer m_aRowSetListeners;
+ SbaXRowSetApproveMultiplexer m_aRowSetApproveListeners;
+ SbaXSQLErrorMultiplexer m_aErrorListeners;
+ SbaXParameterMultiplexer m_aParameterListeners;
+ SbaXSubmitMultiplexer m_aSubmitListeners;
+ SbaXResetMultiplexer m_aResetListeners;
+
+ SbaXPropertyChangeMultiplexer m_aPropertyChangeListeners;
+ SbaXVetoableChangeMultiplexer m_aVetoablePropertyChangeListeners;
+ SbaXPropertiesChangeMultiplexer m_aPropertiesChangeListeners;
+
+ ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> m_aDisposeListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::container::XContainerListener> m_aContainerListeners;
+
+ // hierarchy administration
+ css::uno::Reference< css::uno::XInterface > m_xParent;
+ std::vector< css::uno::Reference< css::form::XFormComponent > > m_aChildren;
+ std::vector< OUString > m_aChildNames;
+
+ // properties
+ OUString m_sName;
+ sal_Int32 m_nNamePropHandle;
+
+ public:
+ const css::uno::Reference< css::sdbc::XRowSet >& getAttachedForm() const { return m_xMainForm; }
+
+ public:
+ SbaXFormAdapter();
+ virtual ~SbaXFormAdapter() override;
+
+ // css::uno::Reference< css::reflection::XIdlClass > getIdlClass();
+ // css::uno::Sequence<css::uno::Reference< css::reflection::XIdlClass > > getIdlClasses();
+
+ void AttachForm(const css::uno::Reference< css::sdbc::XRowSet >& xNewMaster);
+
+ // UNO
+ DECLARE_UNO3_DEFAULTS(SbaXFormAdapter, SbaXFormAdapter_BASE1)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // css::sdbc::XCloseable
+ virtual void SAL_CALL close() override;
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData() override;
+
+ // css::sdbc::XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn(const OUString& columnName) override;
+
+ // css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns() override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull() override;
+ virtual OUString SAL_CALL getString(sal_Int32 columnIndex) override;
+ virtual sal_Bool SAL_CALL getBoolean(sal_Int32 columnIndex) override;
+ virtual sal_Int8 SAL_CALL getByte(sal_Int32 columnIndex) override;
+ virtual sal_Int16 SAL_CALL getShort(sal_Int32 columnIndex) override;
+ virtual sal_Int32 SAL_CALL getInt(sal_Int32 columnIndex) override;
+ virtual sal_Int64 SAL_CALL getLong(sal_Int32 columnIndex) override;
+ virtual float SAL_CALL getFloat(sal_Int32 columnIndex) override;
+ virtual double SAL_CALL getDouble(sal_Int32 columnIndex) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes(sal_Int32 columnIndex) override;
+ virtual css::util::Date SAL_CALL getDate(sal_Int32 columnIndex) override;
+ virtual css::util::Time SAL_CALL getTime(sal_Int32 columnIndex) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp(sal_Int32 columnIndex) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream(sal_Int32 columnIndex) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream(sal_Int32 columnIndex) override;
+ virtual css::uno::Any SAL_CALL getObject(sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef(sal_Int32 columnIndex) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob(sal_Int32 columnIndex) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob(sal_Int32 columnIndex) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray(sal_Int32 columnIndex) override;
+
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark() override;
+ virtual sal_Bool SAL_CALL moveToBookmark(const css::uno::Any& bookmark) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark(const css::uno::Any& bookmark, sal_Int32 rows) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks(const css::uno::Any& first, const css::uno::Any& second) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks() override;
+ virtual sal_Int32 SAL_CALL hashBookmark(const css::uno::Any& bookmark) override;
+
+ // css::sdbc::XRowUpdate
+ virtual void SAL_CALL updateNull(sal_Int32 columnIndex) override;
+ virtual void SAL_CALL updateBoolean(sal_Int32 columnIndex, sal_Bool x) override;
+ virtual void SAL_CALL updateByte(sal_Int32 columnIndex, sal_Int8 x) override;
+ virtual void SAL_CALL updateShort(sal_Int32 columnIndex, sal_Int16 x) override;
+ virtual void SAL_CALL updateInt(sal_Int32 columnIndex, sal_Int32 x) override;
+ virtual void SAL_CALL updateLong(sal_Int32 columnIndex, sal_Int64 x) override;
+ virtual void SAL_CALL updateFloat(sal_Int32 columnIndex, float x) override;
+ virtual void SAL_CALL updateDouble(sal_Int32 columnIndex, double x) override;
+ virtual void SAL_CALL updateString(sal_Int32 columnIndex, const OUString& x) override;
+ virtual void SAL_CALL updateBytes(sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x) override;
+ virtual void SAL_CALL updateDate(sal_Int32 columnIndex, const css::util::Date& x) override;
+ virtual void SAL_CALL updateTime(sal_Int32 columnIndex, const css::util::Time& x) override;
+ virtual void SAL_CALL updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime& x) override;
+ virtual void SAL_CALL updateBinaryStream(sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override;
+ virtual void SAL_CALL updateCharacterStream(sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override;
+ virtual void SAL_CALL updateObject(sal_Int32 columnIndex, const css::uno::Any& x) override;
+ virtual void SAL_CALL updateNumericObject(sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale) override;
+
+ // css::sdbc::XResultSet
+ virtual sal_Bool SAL_CALL next() override;
+ virtual sal_Bool SAL_CALL isBeforeFirst() override;
+ virtual sal_Bool SAL_CALL isAfterLast() override;
+ virtual sal_Bool SAL_CALL isFirst() override;
+ virtual sal_Bool SAL_CALL isLast() override;
+ virtual void SAL_CALL beforeFirst() override;
+ virtual void SAL_CALL afterLast() override;
+ virtual sal_Bool SAL_CALL first() override;
+ virtual sal_Bool SAL_CALL last() override;
+ virtual sal_Int32 SAL_CALL getRow() override;
+ virtual sal_Bool SAL_CALL absolute(sal_Int32 row) override;
+ virtual sal_Bool SAL_CALL relative(sal_Int32 rows) override;
+ virtual sal_Bool SAL_CALL previous() override;
+ virtual void SAL_CALL refreshRow() override;
+ virtual sal_Bool SAL_CALL rowUpdated() override;
+ virtual sal_Bool SAL_CALL rowInserted() override;
+ virtual sal_Bool SAL_CALL rowDeleted() override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement() override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void SAL_CALL insertRow() override;
+ virtual void SAL_CALL updateRow() override;
+ virtual void SAL_CALL deleteRow() override;
+ virtual void SAL_CALL cancelRowUpdates() override;
+ virtual void SAL_CALL moveToInsertRow() override;
+ virtual void SAL_CALL moveToCurrentRow() override;
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute() override;
+ virtual void SAL_CALL addRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& listener) override;
+ virtual void SAL_CALL removeRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener >& listener) override;
+
+ // css::sdbcx::XDeleteRows
+ virtual css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence< css::uno::Any >& rows) override;
+
+ // css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings() override;
+ virtual void SAL_CALL clearWarnings() override;
+
+ // css::sdb::XRowSetApproveBroadcaster
+ virtual void SAL_CALL addRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener) override;
+ virtual void SAL_CALL removeRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener) override;
+
+ // css::sdbc::XSQLErrorBroadcaster
+ virtual void SAL_CALL addSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& _rListener) override;
+ virtual void SAL_CALL removeSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener >& _rListener) override;
+
+ // css::sdb::XResultSetAccess
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL createResultSet() override;
+
+ // css::form::XLoadable
+ virtual void SAL_CALL load() override;
+ virtual void SAL_CALL unload() override;
+ virtual void SAL_CALL reload() override;
+ virtual sal_Bool SAL_CALL isLoaded() override;
+ virtual void SAL_CALL addLoadListener(const css::uno::Reference< css::form::XLoadListener >& aListener) override;
+ virtual void SAL_CALL removeLoadListener(const css::uno::Reference< css::form::XLoadListener >& aListener) override;
+
+ // css::sdbc::XParameters
+ virtual void SAL_CALL setNull(sal_Int32 parameterIndex, sal_Int32 sqlType) override;
+ virtual void SAL_CALL setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName) override;
+ virtual void SAL_CALL setBoolean(sal_Int32 parameterIndex, sal_Bool x) override;
+ virtual void SAL_CALL setByte(sal_Int32 parameterIndex, sal_Int8 x) override;
+ virtual void SAL_CALL setShort(sal_Int32 parameterIndex, sal_Int16 x) override;
+ virtual void SAL_CALL setInt(sal_Int32 parameterIndex, sal_Int32 x) override;
+ virtual void SAL_CALL setLong(sal_Int32 parameterIndex, sal_Int64 x) override;
+ virtual void SAL_CALL setFloat(sal_Int32 parameterIndex, float x) override;
+ virtual void SAL_CALL setDouble(sal_Int32 parameterIndex, double x) override;
+ virtual void SAL_CALL setString(sal_Int32 parameterIndex, const OUString& x) override;
+ virtual void SAL_CALL setBytes(sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x) override;
+ virtual void SAL_CALL setDate(sal_Int32 parameterIndex, const css::util::Date& x) override;
+ virtual void SAL_CALL setTime(sal_Int32 parameterIndex, const css::util::Time& x) override;
+ virtual void SAL_CALL setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x) override;
+ virtual void SAL_CALL setBinaryStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override;
+ virtual void SAL_CALL setCharacterStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length) override;
+ virtual void SAL_CALL setObject(sal_Int32 parameterIndex, const css::uno::Any& x) override;
+ virtual void SAL_CALL setObjectWithInfo(sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale) override;
+ virtual void SAL_CALL setRef(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x) override;
+ virtual void SAL_CALL setBlob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x) override;
+ virtual void SAL_CALL setClob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x) override;
+ virtual void SAL_CALL setArray(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x) override;
+ virtual void SAL_CALL clearParameters() override;
+
+ // css::form::XDatabaseParameterBroadcaster
+ virtual void SAL_CALL addParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener) override;
+ virtual void SAL_CALL removeParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener >& aListener) override;
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent() override;
+ virtual void SAL_CALL setParent(const css::uno::Reference< css::uno::XInterface >& Parent) override;
+
+ // css::form::XSubmit
+ virtual void SAL_CALL submit(const css::uno::Reference< css::awt::XControl >& aControl, const css::awt::MouseEvent& aMouseEvt) override;
+ virtual void SAL_CALL addSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& aListener) override;
+ virtual void SAL_CALL removeSubmitListener(const css::uno::Reference< css::form::XSubmitListener >& aListener) override;
+
+ // css::awt::XTabControllerModel
+ virtual sal_Bool SAL_CALL getGroupControl() override;
+ virtual void SAL_CALL setGroupControl(sal_Bool GroupControl) override;
+ virtual void SAL_CALL setControlModels(const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& Controls) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > SAL_CALL getControlModels() override;
+ virtual void SAL_CALL setGroup(const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& _rGroup, const OUString& GroupName) override;
+ virtual sal_Int32 SAL_CALL getGroupCount() override;
+ virtual void SAL_CALL getGroup(sal_Int32 nGroup, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& _rGroup, OUString& Name) override;
+ virtual void SAL_CALL getGroupByName(const OUString& Name, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > >& _rGroup) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener >& xListener) override;
+ virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener >& aListener) override;
+
+ // css::beans::XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const css::uno::Any& aValue) override;
+ virtual css::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) override;
+
+ // css::container::XNamed
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName(const OUString& aName) override;
+
+ // css::io::XPersistObject
+ virtual OUString SAL_CALL getServiceName() override;
+ virtual void SAL_CALL write(const css::uno::Reference< css::io::XObjectOutputStream >& _rxOutStream) override;
+ virtual void SAL_CALL read(const css::uno::Reference< css::io::XObjectInputStream >& _rxInStream) override;
+
+ // css::beans::XMultiPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValues(const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Sequence< css::uno::Any >& Values) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues(const css::uno::Sequence< OUString >& aPropertyNames) override;
+ virtual void SAL_CALL addPropertiesChangeListener(const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener) override;
+ virtual void SAL_CALL removePropertiesChangeListener(const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener) override;
+ virtual void SAL_CALL firePropertiesChangeEvent(const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener) override;
+
+ // css::beans::XPropertySet
+ virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const css::uno::Any& aValue) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+ virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener) override;
+ virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener) override;
+ virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener) override;
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener) override;
+
+ // css::util::XCancellable
+ virtual void SAL_CALL cancel() override;
+
+ // css::beans::XPropertyState
+ virtual css::beans::PropertyState SAL_CALL getPropertyState(const OUString& PropertyName) override;
+ virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates(const css::uno::Sequence< OUString >& aPropertyName) override;
+ virtual void SAL_CALL setPropertyToDefault(const OUString& PropertyName) override;
+ virtual css::uno::Any SAL_CALL getPropertyDefault(const OUString& aPropertyName) override;
+
+ // css::form::XReset
+ virtual void SAL_CALL reset() override;
+ virtual void SAL_CALL addResetListener(const css::uno::Reference< css::form::XResetListener >& aListener) override;
+ virtual void SAL_CALL removeResetListener(const css::uno::Reference< css::form::XResetListener >& aListener) override;
+
+ // css::container::XNameContainer
+ virtual void SAL_CALL insertByName(const OUString& aName, const css::uno::Any& aElement) override;
+ virtual void SAL_CALL removeByName(const OUString& Name) override;
+
+ // css::container::XNameReplace
+ virtual void SAL_CALL replaceByName(const OUString& aName, const css::uno::Any& aElement) override;
+
+ // css::container::XNameAccess
+ virtual css::uno::Any SAL_CALL getByName(const OUString& aName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName(const OUString& aName) override;
+
+ // css::container::XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override ;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // css::container::XIndexContainer
+ virtual void SAL_CALL insertByIndex(sal_Int32 _rIndex, const css::uno::Any& Element) override;
+ virtual void SAL_CALL removeByIndex(sal_Int32 _rIndex) override;
+
+ // css::container::XIndexReplace
+ virtual void SAL_CALL replaceByIndex(sal_Int32 _rIndex, const css::uno::Any& Element) override;
+
+ // css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 _rIndex) override;
+
+ // css::container::XContainer
+ virtual void SAL_CALL addContainerListener(const css::uno::Reference< css::container::XContainerListener >& xListener) override;
+ virtual void SAL_CALL removeContainerListener(const css::uno::Reference< css::container::XContainerListener >& xListener) override;
+
+ // css::container::XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // css::beans::XPropertyChangeListener
+ virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
+
+ private:
+ // container handling
+ /// @throws css::lang::IllegalArgumentException
+ void implInsert(const css::uno::Any& aElement, sal_Int32 nIndex, const OUString* pNewElName = nullptr);
+ sal_Int32 implGetPos(const OUString& rName);
+
+ void StopListening();
+ void StartListening();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/imageprovider.hxx b/dbaccess/source/ui/inc/imageprovider.hxx
new file mode 100644
index 000000000..a8d24f428
--- /dev/null
+++ b/dbaccess/source/ui/inc/imageprovider.hxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <memory>
+
+namespace dbaui
+{
+ // ImageProvider
+ struct ImageProvider_Data;
+ /** provides images for database objects such as tables, queries, forms, reports ...
+
+ At the moment, this class cares for small icons only, that is, icons which can be used
+ in a tree control. On the medium term, we should extend it with support for different-sized
+ icons.
+ */
+ class ImageProvider
+ {
+ private:
+ std::shared_ptr< ImageProvider_Data > m_pData;
+
+ public:
+ /** creates a semi-functional ImageProvider instance
+
+ The resulting instance is not able to provide any concrete object images,
+ but only default images.
+ */
+ ImageProvider();
+
+ /** creates an ImageProvider instance
+
+ @param _rxConnection
+ denotes the connection to work for. Must not be <NULL/>.
+ */
+ ImageProvider(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+
+ /** returns the image to be used for a database object with the given name
+
+ @param _nDatabaseObjectType
+ the type of the object. Must be one of the css.sdb.application.DatabaseObject
+ constants.
+ @param _rName
+ the name of the object
+ @return
+ the name of the image to be used for the object.
+ */
+ OUString getImageId(
+ const OUString& _rName,
+ const sal_Int32 _nDatabaseObjectType
+ );
+
+ // check whether the connection can give us an icon
+ css::uno::Reference<css::graphic::XGraphic> getXGraphic(const OUString& _rName,
+ const sal_Int32 _nDatabaseObjectType);
+
+ /** returns the resource ID for the default image to be used for a database object
+
+ In opposite to getImageId, this method does not check the concrete object
+ for its image, but returns a default image to be used for all objects of the given
+ type.
+
+ @param _nDatabaseObjectType
+ the type of the object. Must be one of the css.sdb.application.DatabaseObject
+ constants.
+ @return
+ the resource image name to be used for the object type.
+ */
+ static OUString getDefaultImageResourceID(sal_Int32 _nDatabaseObjectType);
+
+ static OUString getFolderImageId(
+ sal_Int32 _nDatabaseObjectType
+ );
+
+ /** retrieves the image to be used for a database as a whole.
+ @return
+ the image to be used for folders of this type
+ */
+ static OUString getDatabaseImage();
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/indexcollection.hxx b/dbaccess/source/ui/inc/indexcollection.hxx
new file mode 100644
index 000000000..d677eed06
--- /dev/null
+++ b/dbaccess/source/ui/inc/indexcollection.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "indexes.hxx"
+
+namespace dbaui
+{
+
+ // OIndexCollection
+ class OIndexCollection
+ {
+ protected:
+ css::uno::Reference< css::container::XNameAccess >
+ m_xIndexes;
+
+ // cached information
+ Indexes m_aIndexes;
+
+ public:
+ // construction
+ OIndexCollection();
+ OIndexCollection(const OIndexCollection& _rSource);
+ // OIndexCollection(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes);
+
+ OIndexCollection& operator=(const OIndexCollection& _rSource);
+
+ // iterating through the collection
+ typedef OIndex* iterator;
+ typedef OIndex const* const_iterator;
+
+ /// get access to the first element of the index collection
+ Indexes::const_iterator begin() const { return m_aIndexes.begin(); }
+ /// get access to the first element of the index collection
+ Indexes::iterator begin() { return m_aIndexes.begin(); }
+ /// get access to the (last + 1st) element of the index collection
+ Indexes::const_iterator end() const { return m_aIndexes.end(); }
+ /// get access to the (last + 1st) element of the index collection
+ Indexes::iterator end() { return m_aIndexes.end(); }
+
+ // searching
+ Indexes::const_iterator find(const OUString& _rName) const;
+ Indexes::iterator find(const OUString& _rName);
+ Indexes::const_iterator findOriginal(const OUString& _rName) const;
+ Indexes::iterator findOriginal(const OUString& _rName);
+
+ // inserting without committing
+ // the OriginalName of the newly inserted index will be empty, thus indicating that it's new
+ Indexes::iterator insert(const OUString& _rName);
+ // commit a new index, which is already part if the collection, but does not have an equivalent in the
+ // data source, yet
+ void commitNewIndex(const Indexes::iterator& _rPos);
+
+ // reset the data for the given index
+ void resetIndex(const Indexes::iterator& _rPos);
+
+ // attach to a new key container
+ void attach(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes);
+ // detach from the container
+ void detach();
+
+ /// drop an index, and remove it from the collection
+ bool drop(const Indexes::iterator& _rPos);
+ /// simply drop the index described by the name, but don't remove the descriptor from the collection
+ bool dropNoRemove(const Indexes::iterator& _rPos);
+
+ protected:
+ void implConstructFrom(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes);
+ static void implFillIndexInfo(OIndex& _rIndex, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor);
+ void implFillIndexInfo(OIndex& _rIndex);
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/indexdialog.hxx b/dbaccess/source/ui/inc/indexdialog.hxx
new file mode 100644
index 000000000..f03b04f6f
--- /dev/null
+++ b/dbaccess/source/ui/inc/indexdialog.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <vcl/weld.hxx>
+#include "indexes.hxx"
+
+namespace dbaui
+{
+ // DbaIndexDialog
+ class IndexFieldsControl;
+ class OIndexCollection;
+ class DbaIndexDialog final : public weld::GenericDialogController
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ std::unique_ptr<OIndexCollection> m_xIndexes;
+ std::unique_ptr<weld::TreeIter> m_xPreviousSelection;
+ bool m_bEditingActive;
+ bool m_bEditAgain;
+ bool m_bNoHandlerCall;
+
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+
+ std::unique_ptr<weld::Toolbar> m_xActions;
+ std::unique_ptr<weld::TreeView> m_xIndexList;
+ std::unique_ptr<weld::Label> m_xIndexDetails;
+ std::unique_ptr<weld::Label> m_xDescriptionLabel;
+ std::unique_ptr<weld::Label> m_xDescription;
+ std::unique_ptr<weld::CheckButton> m_xUnique;
+ std::unique_ptr<weld::Label> m_xFieldsLabel;
+ std::unique_ptr<weld::Button> m_xClose;
+ std::unique_ptr<weld::Container> m_xTable;
+ css::uno::Reference<css::awt::XWindow> m_xTableCtrlParent;
+ VclPtr<IndexFieldsControl> m_xFields;
+
+ public:
+ DbaIndexDialog(
+ weld::Window* _pParent,
+ const css::uno::Sequence< OUString >& _rFieldNames,
+ const css::uno::Reference< css::container::XNameAccess >& _rxIndexes,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+ virtual ~DbaIndexDialog() override;
+
+ typedef std::pair<const weld::TreeIter&, OUString> IterString;
+ private:
+ void fillIndexList();
+ void updateToolbox();
+ void updateControls(const weld::TreeIter* pEntry);
+
+ void IndexSelected();
+
+ DECL_LINK( OnIndexSelected, weld::TreeView&, void );
+ DECL_LINK( OnIndexAction, const OString&, void );
+ DECL_LINK( OnEntryEditing, const weld::TreeIter&, bool );
+ DECL_LINK( OnEntryEdited, const IterString&, bool );
+ DECL_LINK( OnModifiedClick, weld::Toggleable&, void );
+ DECL_LINK( OnModified, IndexFieldsControl&, void );
+ DECL_LINK( OnCloseDialog, weld::Button&, void );
+
+ DECL_LINK( OnEditIndexAgain, void*, void );
+
+ void OnNewIndex();
+ void OnDropIndex(bool _bConfirm = true);
+ void OnRenameIndex();
+ void OnSaveIndex();
+ void OnResetIndex();
+
+ bool implCommit(const weld::TreeIter* pEntry);
+ bool implSaveModified(bool _bPlausibility = true);
+ bool implCommitPreviouslySelected();
+
+ bool implDropIndex(const weld::TreeIter* pEntry, bool _bRemoveFromCollection);
+
+ bool implCheckPlausibility(const Indexes::const_iterator& _rPos);
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/indexes.hxx b/dbaccess/source/ui/inc/indexes.hxx
new file mode 100644
index 000000000..75bd5b44b
--- /dev/null
+++ b/dbaccess/source/ui/inc/indexes.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/ustring.hxx>
+
+#include <vector>
+
+namespace dbaui
+{
+ // OIndexField
+ struct OIndexField
+ {
+ OUString sFieldName;
+ bool bSortAscending;
+
+ OIndexField() : bSortAscending(true) { }
+ };
+
+ typedef std::vector<OIndexField> IndexFields;
+
+ // OIndex
+ struct GrantIndexAccess
+ {
+ friend class OIndexCollection;
+ private:
+ GrantIndexAccess() { }
+ };
+
+ struct OIndex final
+ {
+ OUString sOriginalName;
+ bool bModified;
+
+ public:
+ OUString sName;
+ OUString sDescription;
+ bool bPrimaryKey;
+ bool bUnique;
+ IndexFields aFields;
+
+ OIndex(const OUString& _rOriginalName)
+ : sOriginalName(_rOriginalName), bModified(false), sName(_rOriginalName), bPrimaryKey(false), bUnique(false)
+ {
+ }
+
+ const OUString& getOriginalName() const { return sOriginalName; }
+
+ bool isModified() const { return bModified; }
+ void setModified(bool _bModified) { bModified = _bModified; }
+ void clearModified() { setModified(false); }
+
+ bool isNew() const { return getOriginalName().isEmpty(); }
+ void flagAsNew(const GrantIndexAccess&) { sOriginalName.clear(); }
+ void flagAsCommitted(const GrantIndexAccess&) { sOriginalName = sName; }
+ };
+
+ typedef std::vector<OIndex> Indexes;
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/indexfieldscontrol.hxx b/dbaccess/source/ui/inc/indexfieldscontrol.hxx
new file mode 100644
index 000000000..90ae7172e
--- /dev/null
+++ b/dbaccess/source/ui/inc/indexfieldscontrol.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/editbrowsebox.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include "indexes.hxx"
+
+namespace dbaui
+{
+
+ class DbaMouseDownListBoxController;
+
+ // IndexFieldsControl
+ class IndexFieldsControl final : public ::svt::EditBrowseBox
+ {
+ IndexFields m_aSavedValue;
+
+ IndexFields m_aFields; // !! order matters !!
+ IndexFields::const_iterator m_aSeekRow; // !!
+
+ Link<IndexFieldsControl&,void> m_aModifyHdl;
+
+ VclPtr< ::svt::ListBoxControl> m_pSortingCell;
+ VclPtr< ::svt::ListBoxControl> m_pFieldNameCell;
+
+ OUString m_sAscendingText;
+ OUString m_sDescendingText;
+
+ bool m_bAddIndexAppendix;
+
+ public:
+ IndexFieldsControl(const css::uno::Reference<css::awt::XWindow> &rParent);
+ virtual ~IndexFieldsControl() override;
+ virtual void dispose() override;
+
+ void Init(const css::uno::Sequence< OUString >& _rAvailableFields, bool _bAddIndexAppendix);
+
+ void initializeFrom(IndexFields&& _rFields);
+ void commitTo(IndexFields& _rFields);
+
+ bool SaveModified() override;
+ using EditBrowseBox::IsModified;
+
+ const IndexFields& GetSavedValue() const { return m_aSavedValue; }
+ void SaveValue() { m_aSavedValue = m_aFields; }
+
+ void SetModifyHdl(const Link<IndexFieldsControl&,void>& _rHdl) { m_aModifyHdl = _rHdl; }
+ virtual OUString GetCellText(sal_Int32 _nRow,sal_uInt16 nColId) const override;
+
+ private:
+ // EditBrowseBox overridables
+ virtual void PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, sal_uInt16 _nColumnId ) const override;
+ virtual bool SeekRow(sal_Int32 nRow) override;
+ virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override;
+ virtual bool IsTabAllowed(bool bForward) const override;
+
+ ::svt::CellController* GetController(sal_Int32 _nRow, sal_uInt16 _nColumnId) override;
+ void InitController(::svt::CellControllerRef&, sal_Int32 _nRow, sal_uInt16 _nColumnId) override;
+
+ OUString GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const;
+ bool implGetFieldDesc(sal_Int32 _nRow, IndexFields::const_iterator& _rPos);
+
+ bool isNewField() const { return GetCurRow() >= static_cast<sal_Int32>(m_aFields.size()); }
+
+ DECL_LINK( OnListEntrySelected, DbaMouseDownListBoxController&, void );
+
+ using ::svt::EditBrowseBox::Init;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/linkeddocuments.hxx b/dbaccess/source/ui/inc/linkeddocuments.hxx
new file mode 100644
index 000000000..961b2ea4c
--- /dev/null
+++ b/dbaccess/source/ui/inc/linkeddocuments.hxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "AppElementType.hxx"
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+
+namespace weld { class Window; }
+namespace dbaui
+{
+
+ // OLinkedDocumentsAccess
+ class OLinkedDocumentsAccess final
+ {
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+ css::uno::Reference< css::container::XNameAccess >
+ m_xDocumentContainer;
+ css::uno::Reference< css::sdbc::XConnection>
+ m_xConnection;
+ css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >
+ m_xDocumentUI;
+ weld::Window* m_pDialogParent;
+ OUString m_sDataSourceName;
+
+ public:
+ OLinkedDocumentsAccess(
+ weld::Window* pDialogParent,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& i_rDocumentUI,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const css::uno::Reference< css::container::XNameAccess >& _rxContainer,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const OUString& _sDataSourceName
+ );
+ ~OLinkedDocumentsAccess();
+
+ bool isConnected() const { return m_xConnection.is(); }
+
+ css::uno::Reference< css::lang::XComponent>
+ open(
+ const OUString& _rLinkName,
+ css::uno::Reference< css::lang::XComponent>& _xDefinition,
+ ElementOpenMode _eOpenMode,
+ const ::comphelper::NamedValueCollection& _rAdditionalArgs
+ );
+
+ css::uno::Reference< css::lang::XComponent >
+ newDocument(
+ sal_Int32 i_nActionID,
+ const ::comphelper::NamedValueCollection& i_rCreationArgs,
+ css::uno::Reference< css::lang::XComponent >& o_rDefinition
+ );
+
+ void newFormWithPilot(
+ const sal_Int32 _nCommandType,
+ const OUString& _rObjectName
+ );
+ void newReportWithPilot(
+ const sal_Int32 _nCommandType,
+ const OUString& _rObjectName
+ );
+ void newQueryWithPilot();
+ void newTableWithPilot();
+
+ private:
+ css::uno::Reference< css::lang::XComponent >
+ impl_open(
+ const OUString& _rLinkName,
+ css::uno::Reference< css::lang::XComponent >& _xDefinition,
+ ElementOpenMode _eOpenMode,
+ const ::comphelper::NamedValueCollection& _rAdditionalArgs
+ );
+
+ void
+ impl_newWithPilot(
+ const char* _pWizardService,
+ const sal_Int32 _nCommandType,
+ const OUString& _rObjectName
+ );
+
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/objectnamecheck.hxx b/dbaccess/source/ui/inc/objectnamecheck.hxx
new file mode 100644
index 000000000..52f639e53
--- /dev/null
+++ b/dbaccess/source/ui/inc/objectnamecheck.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+namespace dbtools { class SQLExceptionInfo; }
+
+namespace dbaui
+{
+
+ // IObjectNameCheck
+ /** interface encapsulating the check for the validity of an object name
+ */
+ class IObjectNameCheck
+ {
+ public:
+ /** determines whether a given object name is valid
+
+ @param _rObjectName
+ the name to check
+ @param _out_rErrorToDisplay
+ output parameter taking an error message describing why the name is not
+ valid, if applicable.
+
+ @return
+ <TRUE/> if and only if the given name is valid.
+ */
+ virtual bool isNameValid(
+ const OUString& _rObjectName,
+ ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay
+ ) const = 0;
+
+ public:
+ virtual ~IObjectNameCheck() { }
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/opendoccontrols.hxx b/dbaccess/source/ui/inc/opendoccontrols.hxx
new file mode 100644
index 000000000..8448a047d
--- /dev/null
+++ b/dbaccess/source/ui/inc/opendoccontrols.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <rtl/ustring.hxx>
+
+namespace dbaui
+{
+
+ // OpenDocumentButton
+ /** a button which can be used to open a document
+
+ The text of the button is the same as for the "Open" command in the application
+ UI. Additionally, the icon for this command is also displayed on the button.
+ */
+ class OpenDocumentButton
+ {
+ private:
+ OUString m_sModule;
+
+ std::unique_ptr<weld::Button> m_xControl;
+ public:
+ OpenDocumentButton(std::unique_ptr<weld::Button> xControl, const char* _pAsciiModuleName);
+
+ void set_sensitive(bool bSensitive) { m_xControl->set_sensitive(bSensitive); }
+ void connect_clicked(const Link<weld::Button&, void>& rLink) { m_xControl->connect_clicked(rLink); }
+
+ private:
+ void impl_init( const char* _pAsciiModuleName );
+ };
+
+ // OpenDocumentListBox
+ class OpenDocumentListBox
+ {
+ private:
+ typedef std::pair< OUString, OUString > StringPair;
+
+ std::vector<StringPair> m_aURLs;
+
+ std::unique_ptr<weld::ComboBox> m_xControl;
+
+ public:
+ OpenDocumentListBox(std::unique_ptr<weld::ComboBox> xControl, const char* _pAsciiModuleName);
+
+ OUString GetSelectedDocumentURL() const;
+
+ void set_sensitive(bool bSensitive) { m_xControl->set_sensitive(bSensitive); }
+ int get_count() const { return m_xControl->get_count(); }
+ void set_active(int nPos) { m_xControl->set_active(nPos); }
+ void connect_changed(const Link<weld::ComboBox&, void>& rLink) { m_xControl->connect_changed(rLink); }
+
+ private:
+ const StringPair & impl_getDocumentAtIndex( sal_uInt16 _nListIndex ) const;
+
+ void impl_init( const char* _pAsciiModuleName );
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/paramdialog.hxx b/dbaccess/source/ui/inc/paramdialog.hxx
new file mode 100644
index 000000000..489a621e6
--- /dev/null
+++ b/dbaccess/source/ui/inc/paramdialog.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <vcl/timer.hxx>
+
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <connectivity/predicateinput.hxx>
+#include <svx/ParseContext.hxx>
+#include <o3tl/typed_flags_set.hxx>
+
+namespace connectivity
+{
+ class OSQLParseNode;
+}
+
+enum class VisitFlags {
+ NONE = 0x00,
+ Visited = 0x01,
+ Dirty = 0x02,
+};
+namespace o3tl {
+ template<> struct typed_flags<VisitFlags> : is_typed_flags<VisitFlags, 0x03> {};
+}
+
+namespace dbaui
+{
+ // OParameterDialog
+ class OParameterDialog final
+ : public weld::GenericDialogController
+ , public ::svxform::OParseContextClient
+ {
+ sal_Int32 m_nCurrentlySelected;
+
+ css::uno::Reference< css::container::XIndexAccess >
+ m_xParams;
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xConnection;
+ css::uno::Reference< css::util::XNumberFormatter >
+ m_xFormatter;
+ ::dbtools::OPredicateInputController
+ m_aPredicateInput;
+
+ std::vector<VisitFlags> m_aVisitedParams;
+ Timer m_aResetVisitFlag;
+ // we reset the "visited flag" 1 second after and entry has been selected
+
+ css::uno::Sequence< css::beans::PropertyValue >
+ m_aFinalValues; /// the final values as entered by the user
+
+ // the controls
+ std::unique_ptr<weld::TreeView> m_xAllParams;
+ std::unique_ptr<weld::Entry> m_xParam;
+ std::unique_ptr<weld::Button> m_xTravelNext;
+ std::unique_ptr<weld::Button> m_xOKBtn;
+ std::unique_ptr<weld::Button> m_xCancelBtn;
+
+ public:
+ OParameterDialog(weld::Window* _pParent,
+ const css::uno::Reference< css::container::XIndexAccess > & _rParamContainer,
+ const css::uno::Reference< css::sdbc::XConnection > & _rxConnection,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext);
+ virtual ~OParameterDialog() override;
+
+ const css::uno::Sequence< css::beans::PropertyValue >&
+ getValues() const { return m_aFinalValues; }
+
+ private:
+ void Construct();
+
+ DECL_LINK(OnVisitedTimeout, Timer*, void);
+ DECL_LINK(OnValueModified, weld::Entry&, void);
+ DECL_LINK(OnEntryListBoxSelected, weld::TreeView&, void);
+ DECL_LINK(OnButtonClicked, weld::Button&, void);
+ DECL_LINK(OnValueLoseFocusHdl, weld::Widget&, void);
+ bool CheckValueForError();
+ bool OnEntrySelected();
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/propertystorage.hxx b/dbaccess/source/ui/inc/propertystorage.hxx
new file mode 100644
index 000000000..35d9f24d6
--- /dev/null
+++ b/dbaccess/source/ui/inc/propertystorage.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Any.hxx>
+#include <map>
+#include <memory>
+
+class SfxItemSet;
+
+namespace dbaui
+{
+
+ /** a PropertyStorage implementation which stores the value in an item set
+ */
+ class SetItemPropertyStorage
+ {
+ public:
+ SetItemPropertyStorage( SfxItemSet& _rItemSet, const sal_uInt16 _nItemID )
+ :m_rItemSet( _rItemSet )
+ ,m_nItemID( _nItemID )
+ {
+ }
+
+ void getPropertyValue( css::uno::Any& _out_rValue ) const;
+ void setPropertyValue( const css::uno::Any& _rValue );
+
+ private:
+ SfxItemSet& m_rItemSet;
+ const sal_uInt16 m_nItemID;
+ };
+
+ typedef std::map< sal_Int32, std::shared_ptr< SetItemPropertyStorage > > PropertyValues;
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/querycontainerwindow.hxx b/dbaccess/source/ui/inc/querycontainerwindow.hxx
new file mode 100644
index 000000000..12583ec0c
--- /dev/null
+++ b/dbaccess/source/ui/inc/querycontainerwindow.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/window.hxx>
+#include <vcl/split.hxx>
+#include <dbaccess/dataview.hxx>
+#include <com/sun/star/frame/XFrame2.hpp>
+#include "QueryViewSwitch.hxx"
+#include <vcl/dockwin.hxx>
+
+namespace dbaui
+{
+
+ // OBeamer
+ // temporary class until the beamer is implemented
+ class OBeamer : public DockingWindow
+ {
+ public:
+ OBeamer(vcl::Window* _pParent) : DockingWindow(_pParent,0){}
+ };
+
+ // OQueryContainerWindow
+ class OQueryContainerWindow : public ODataView
+ {
+ OQueryViewSwitch* m_pViewSwitch;
+ VclPtr<OBeamer> m_pBeamer;
+ VclPtr<Splitter> m_pSplitter;
+ css::uno::Reference< css::frame::XFrame2 > m_xBeamer;
+
+ DECL_LINK( SplitHdl, Splitter*, void );
+ public:
+ OQueryContainerWindow(vcl::Window* pParent, OQueryController& _rController,const css::uno::Reference< css::uno::XComponentContext >&);
+ virtual ~OQueryContainerWindow() override;
+ virtual void dispose() override;
+
+ virtual void Construct() override;
+
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+
+ // show the beamer
+ void showPreview(const css::uno::Reference< css::frame::XFrame >& _xFrame);
+ // called when the beamer has been disposed
+ void disposingPreview();
+
+ const css::uno::Reference< css::frame::XFrame2 >&
+ getPreviewFrame() const { return m_xBeamer; }
+
+ OQueryDesignView* getDesignView() { return m_pViewSwitch->getDesignView(); }
+
+ bool isCutAllowed() const { return m_pViewSwitch->isCutAllowed(); }
+ bool isPasteAllowed() const { return m_pViewSwitch->isPasteAllowed(); }
+ bool isCopyAllowed() const { return m_pViewSwitch->isCopyAllowed(); }
+ void copy() { m_pViewSwitch->copy(); }
+ void cut() { m_pViewSwitch->cut(); }
+ void paste() { m_pViewSwitch->paste(); }
+
+ void clear() { m_pViewSwitch->clear(); }
+ bool isSlotEnabled( sal_Int32 _nSlotId ) { return m_pViewSwitch->isSlotEnabled( _nSlotId ); }
+ void setSlotEnabled( sal_Int32 _nSlotId, bool _bEnable ) { m_pViewSwitch->setSlotEnabled( _nSlotId, _bEnable ); }
+ void setNoneVisibleRow(sal_Int32 _nRows) { m_pViewSwitch->setNoneVisibleRow( _nRows); }
+
+ bool checkStatement() { return m_pViewSwitch->checkStatement( ); }
+ OUString getStatement() { return m_pViewSwitch->getStatement( ); }
+ void setStatement( const OUString& _rsStatement ) { m_pViewSwitch->setStatement( _rsStatement ); }
+
+ void initialize() override { m_pViewSwitch->initialize(); }
+ void SaveUIConfig() { m_pViewSwitch->SaveUIConfig(); }
+ void reset() { m_pViewSwitch->reset(); }
+
+ bool switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo );
+ void forceInitialView();
+
+ virtual void GetFocus() override;
+
+ protected:
+ // re-arrange the controls belonging to the document itself
+ virtual void resizeAll( const tools::Rectangle& _rPlayground ) override;
+
+ // arrange derived classes controls in the rectangle given
+ virtual void resizeDocumentView(tools::Rectangle& _rPlayground) override;
+ };
+ // end of temp classes
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/querycontroller.hxx b/dbaccess/source/ui/inc/querycontroller.hxx
new file mode 100644
index 000000000..94bb5d8f4
--- /dev/null
+++ b/dbaccess/source/ui/inc/querycontroller.hxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "JoinController.hxx"
+#include "querycontainerwindow.hxx"
+#include <svx/ParseContext.hxx>
+#include "TableFieldDescription.hxx"
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XSQLQueryComposer.hpp>
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlparse.hxx>
+
+namespace comphelper
+{
+ class NamedValueCollection;
+}
+
+namespace dbaui
+{
+ class OQueryContainerWindow;
+
+ typedef ::comphelper::OPropertyContainer OQueryController_PBase;
+ typedef ::comphelper::OPropertyArrayUsageHelper< OQueryController > OQueryController_PABase;
+ class OQueryController :public OJoinController
+ ,public OQueryController_PBase
+ ,public OQueryController_PABase
+ {
+ OTableFields m_vTableFieldDesc;
+ OTableFields m_vUnUsedFieldsDesc; // contains fields which aren't visible and don't have any criteria
+
+ css::uno::Sequence< css::beans::PropertyValue > m_aFieldInformation;
+
+ std::unique_ptr<::svxform::OSystemParseContext> m_pParseContext;
+ ::connectivity::OSQLParser m_aSqlParser;
+ std::unique_ptr<::connectivity::OSQLParseTreeIterator> m_pSqlIterator;
+
+ css::uno::Reference< css::sdb::XSQLQueryComposer > m_xComposer;
+ /// if we're editing an existing view, this is non-NULL
+ css::uno::Reference< css::sdbcx::XAlterView > m_xAlterView;
+
+ OUString m_sStatement; // contains the current sql statement
+ OUString m_sUpdateCatalogName; // catalog for update data
+ OUString m_sUpdateSchemaName; // schema for update data
+ mutable OUString
+ m_sName; // name of the query
+
+ sal_Int64 m_nLimit; // the limit of the query result (All==-1)
+
+ sal_Int32 m_nVisibleRows; // which rows the selection browse should show
+ sal_Int32 m_nSplitPos; // the position of the splitter
+ sal_Int32 m_nCommandType; // the type of the object we're designing
+ bool m_bGraphicalDesign; // are we in the graphical design mode (sal_True) or in the text design (sal_False)?
+ bool m_bDistinct; // true when you want "select distinct" otherwise false
+ bool m_bEscapeProcessing;// is true when we shouldn't parse the statement
+
+
+ /** returns the container of queries, views, or command definitions, depending on what object type
+ we design currently.
+
+ Not allowed to be called if we design an independent SQL command.
+ */
+ css::uno::Reference< css::container::XNameAccess >
+ getObjectContainer() const;
+
+ bool editingView() const { return m_nCommandType == css::sdb::CommandType::TABLE; }
+ bool editingQuery() const { return m_nCommandType == css::sdb::CommandType::QUERY; }
+ bool editingCommand() const { return m_nCommandType == css::sdb::CommandType::COMMAND; }
+
+ bool askForNewName( const css::uno::Reference< css::container::XNameAccess>& _xElements,
+ bool _bSaveAs);
+ // creates the querycomposer
+ void setQueryComposer();
+ void deleteIterator();
+ void executeQuery();
+ bool doSaveAsDoc(bool _bSaveAs);
+
+ void saveViewSettings( ::comphelper::NamedValueCollection& o_rViewSettings, const bool i_includingCriteria ) const;
+ void loadViewSettings( const ::comphelper::NamedValueCollection& o_rViewSettings );
+ OUString translateStatement( bool _bFireStatementChange = true );
+
+ void execute_QueryPropDlg();
+
+ protected:
+ // all the features which should be handled by this class
+ virtual void describeSupportedFeatures() override;
+ // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot.
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ // execute a feature
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ virtual void reconnect( bool _bUI ) override;
+ virtual OUString getPrivateTitle( ) const override;
+
+ OQueryContainerWindow* getContainer() const { return static_cast< OQueryContainerWindow* >( getView() ); }
+
+ public:
+ OQueryController(const css::uno::Reference< css::uno::XComponentContext >& _rM);
+
+ virtual ~OQueryController() override;
+ OTableFields& getTableFieldDesc() { return m_vTableFieldDesc; }
+ OTableFields& getUnUsedFields() { return m_vUnUsedFieldsDesc; }
+
+ void clearFields();
+
+ virtual void impl_onModifyChanged() override;
+
+ // should the statement be parsed by our own sql parser
+ bool isEscapeProcessing() const { return m_bEscapeProcessing; }
+ bool isGraphicalDesign() const { return m_bGraphicalDesign; }
+ bool isDistinct() const { return m_bDistinct; }
+ sal_Int64 getLimit() const { return m_nLimit; }
+
+ const OUString& getStatement() const { return m_sStatement; }
+ sal_Int32 getSplitPos() const { return m_nSplitPos;}
+ sal_Int32 getVisibleRows() const { return m_nVisibleRows; }
+
+ void setDistinct(bool _bDistinct) { m_bDistinct = _bDistinct;}
+ void setLimit(const sal_Int64 _nLimit) { m_nLimit = _nLimit;}
+ void setSplitPos(sal_Int32 _nSplitPos) { m_nSplitPos = _nSplitPos;}
+ void setVisibleRows(sal_Int32 _nVisibleRows) { m_nVisibleRows = _nVisibleRows;}
+
+ sal_Int32 getColWidth(sal_uInt16 _nColPos) const;
+
+ const css::uno::Sequence< css::beans::PropertyValue >&
+ getFieldInformation() const { return m_aFieldInformation; }
+
+ ::connectivity::OSQLParser& getParser() { return m_aSqlParser; }
+ ::connectivity::OSQLParseTreeIterator& getParseIterator() { return *m_pSqlIterator; }
+
+ virtual bool Construct(vcl::Window* pParent) override;
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+ // XPropertySet
+ virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL disposing() override;
+
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XController
+ virtual css::uno::Any SAL_CALL getViewData() override;
+ virtual void SAL_CALL restoreViewData(const css::uno::Any& Data) override;
+
+ private:
+ virtual void onLoadedMenu(const css::uno::Reference< css::frame::XLayoutManager >& _xLayoutManager) override;
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // OPropertySetHelper
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+
+ virtual OJoinDesignView* getJoinView() override;
+ // ask the user if the design should be saved when it is modified
+ virtual short saveModified() override;
+ virtual void reset() override;
+ virtual void impl_initialize() override;
+
+ void impl_reset( const bool i_bIgnoreQuerySettings = false );
+ /// tells the user that we needed to switch to SQL view automatically
+ void impl_showAutoSQLViewError( const css::uno::Any& _rErrorDetails );
+
+ /** switches to the graphical or SQL view mode, as determined by m_bGraphicalDesign
+ */
+ void impl_setViewMode( ::dbtools::SQLExceptionInfo* _pErrorInfo );
+
+ /// sets m_sStatement, and notifies our respective property change listeners
+ void setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange = true );
+ /// sets the m_bEscapeProcessing member, and notifies our respective property change listeners
+ void setEscapeProcessing_fireEvent( const bool _bEscapeProcessing );
+
+ // OJoinController overridables
+ virtual bool allowViews() const override;
+ virtual bool allowQueries() const override;
+
+ private:
+ DECL_LINK( OnExecuteAddTable, void*, void );
+
+ private:
+ using OQueryController_PBase::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/queryfilter.hxx b/dbaccess/source/ui/inc/queryfilter.hxx
new file mode 100644
index 000000000..396778f22
--- /dev/null
+++ b/dbaccess/source/ui/inc/queryfilter.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <connectivity/sqliterator.hxx>
+
+#include <connectivity/predicateinput.hxx>
+#include <svx/ParseContext.hxx>
+
+namespace com::sun::star {
+ namespace sdb
+ {
+ class XSingleSelectQueryComposer;
+ }
+ namespace sdbc
+ {
+ class XConnection;
+ class XDatabaseMetaData;
+ }
+ namespace container
+ {
+ class XNameAccess;
+ }
+ namespace beans
+ {
+ struct PropertyValue;
+ }
+}
+
+// DlgFilterCrit
+namespace dbaui
+{
+ class DlgFilterCrit final : public weld::GenericDialogController
+ , public ::svxform::OParseContextClient
+ {
+ private:
+ std::vector<OUString> m_aSTR_COMPARE_OPERATORS;
+
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xQueryComposer;
+ css::uno::Reference< css::container::XNameAccess> m_xColumns;
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xMetaData;
+
+ ::dbtools::OPredicateInputController m_aPredicateInput;
+
+ std::unique_ptr<weld::ComboBox> m_xLB_WHEREFIELD1;
+ std::unique_ptr<weld::ComboBox> m_xLB_WHERECOMP1;
+ std::unique_ptr<weld::Entry> m_xET_WHEREVALUE1;
+
+ std::unique_ptr<weld::ComboBox> m_xLB_WHERECOND2;
+ std::unique_ptr<weld::ComboBox> m_xLB_WHEREFIELD2;
+ std::unique_ptr<weld::ComboBox> m_xLB_WHERECOMP2;
+ std::unique_ptr<weld::Entry> m_xET_WHEREVALUE2;
+
+ std::unique_ptr<weld::ComboBox> m_xLB_WHERECOND3;
+ std::unique_ptr<weld::ComboBox> m_xLB_WHEREFIELD3;
+ std::unique_ptr<weld::ComboBox> m_xLB_WHERECOMP3;
+ std::unique_ptr<weld::Entry> m_xET_WHEREVALUE3;
+
+ static void SelectField(weld::ComboBox& rBox, std::u16string_view rField);
+ DECL_LINK(ListSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(ListSelectCompHdl, weld::ComboBox&, void);
+
+ void SetLine( int nIdx, const css::beans::PropertyValue& _rItem, bool _bOr );
+ void EnableLines();
+ sal_Int32 GetOSQLPredicateType( std::u16string_view _rSelectedPredicate ) const;
+ static sal_Int32 GetSelectionPos(sal_Int32 eType, const weld::ComboBox& rListBox);
+ bool getCondition(const weld::ComboBox& _rField, const weld::ComboBox& _rComp, const weld::Entry& _rValue, css::beans::PropertyValue& _rFilter) const;
+ void fillLines(int &i, const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& _aValues);
+
+ css::uno::Reference< css::beans::XPropertySet > getMatchingColumn( const weld::Entry& _rValueInput ) const;
+ css::uno::Reference< css::beans::XPropertySet > getColumn( const OUString& _rFieldName ) const;
+ css::uno::Reference< css::beans::XPropertySet > getQueryColumn( const OUString& _rFieldName ) const;
+
+ public:
+ DlgFilterCrit(weld::Window * pParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::sdbc::XConnection>& _rxConnection,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryComposer>& _rxComposer,
+ const css::uno::Reference< css::container::XNameAccess>& _rxCols);
+ virtual ~DlgFilterCrit() override;
+
+ void BuildWherePart();
+
+ private:
+ DECL_LINK(PredicateLoseFocus, weld::Widget&, void);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/queryorder.hxx b/dbaccess/source/ui/inc/queryorder.hxx
new file mode 100644
index 000000000..523d84f31
--- /dev/null
+++ b/dbaccess/source/ui/inc/queryorder.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+#define DOG_ROWS 3
+
+namespace com::sun::star{
+ namespace sdb
+ {
+ class XSingleSelectQueryComposer;
+ }
+ namespace sdbc
+ {
+ class XConnection;
+ }
+ namespace container
+ {
+ class XNameAccess;
+ }
+}
+
+// DlgOrderCrit
+namespace dbaui
+{
+ class DlgOrderCrit final : public weld::GenericDialogController
+ {
+ OUString m_sOrgOrder;
+
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xQueryComposer;
+ css::uno::Reference< css::container::XNameAccess> m_xColumns;
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+
+ weld::ComboBox* m_aColumnList[DOG_ROWS];
+ weld::ComboBox* m_aValueList[DOG_ROWS];
+
+ std::unique_ptr<weld::ComboBox> m_xLB_ORDERFIELD1;
+ std::unique_ptr<weld::ComboBox> m_xLB_ORDERVALUE1;
+ std::unique_ptr<weld::ComboBox> m_xLB_ORDERFIELD2;
+ std::unique_ptr<weld::ComboBox> m_xLB_ORDERVALUE2;
+ std::unique_ptr<weld::ComboBox> m_xLB_ORDERFIELD3;
+ std::unique_ptr<weld::ComboBox> m_xLB_ORDERVALUE3;
+
+ DECL_LINK(FieldListSelectHdl, weld::ComboBox&, void);
+ void EnableLines();
+
+ public:
+ DlgOrderCrit(weld::Window * pParent,
+ const css::uno::Reference< css::sdbc::XConnection>& _rxConnection,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryComposer>& _rxComposer,
+ const css::uno::Reference< css::container::XNameAccess>& _rxCols);
+ virtual ~DlgOrderCrit() override;
+
+ void BuildOrderPart();
+
+ OUString GetOrderList( ) const;
+ const OUString& GetOriginalOrder() const { return m_sOrgOrder; }
+
+ private:
+ void impl_initializeOrderList_nothrow();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/sbagrid.hrc b/dbaccess/source/ui/inc/sbagrid.hrc
new file mode 100644
index 000000000..c84dbccea
--- /dev/null
+++ b/dbaccess/source/ui/inc/sbagrid.hrc
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef DBACCESS_SBA_GRID_HRC
+#define DBACCESS_SBA_GRID_HRC
+
+//----------------Menueitems-------------------------------------------------
+// Table
+#define SBA_WHICHID_START 100
+
+// Columns
+// Formatting
+#define SBA_DEF_RANGEFORMAT (SBA_WHICHID_START+143) // RangeItem
+#define SBA_DEF_FMTVALUE (SBA_WHICHID_START+144) // SfxULONG, Format
+
+// Justification
+#define SBA_ATTR_ALIGN_HOR_JUSTIFY (SBA_WHICHID_START + 145) // SvxHorJustifyItem
+
+#endif // DBACCESS_SBA_GRID_HRC
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/sbagrid.hxx b/dbaccess/source/ui/inc/sbagrid.hxx
new file mode 100644
index 000000000..0d22f6dce
--- /dev/null
+++ b/dbaccess/source/ui/inc/sbagrid.hxx
@@ -0,0 +1,293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/fmgridcl.hxx>
+
+#include <svx/fmgridif.hxx>
+
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <comphelper/multiinterfacecontainer3.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/uno3.hxx>
+#include "sbamultiplex.hxx"
+#include <svx/dataaccessdescriptor.hxx>
+#include <rtl/ref.hxx>
+#include <map>
+#include <queue>
+
+class SvNumberFormatter;
+
+namespace com::sun::star {
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+}
+
+namespace dbaui
+{
+ struct SbaURLCompare
+ {
+ bool operator() (const css::util::URL& x, const css::util::URL& y) const { return x.Complete == y.Complete; }
+ };
+
+ class SbaXStatusMultiplexer;
+ class SbaXGridControl
+ :public FmXGridControl
+ ,public css::frame::XDispatch
+ {
+ typedef std::map<css::util::URL, rtl::Reference<SbaXStatusMultiplexer>, SbaURLCompare> StatusMultiplexerArray;
+ StatusMultiplexerArray m_aStatusMultiplexer;
+
+ public:
+ SbaXGridControl(const css::uno::Reference< css::uno::XComponentContext >&);
+ virtual ~SbaXGridControl() override;
+
+ // UNO
+ DECLARE_UNO3_DEFAULTS(SbaXGridControl, FmXGridControl)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // css::lang::XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // css::frame::XDispatch
+ virtual void SAL_CALL dispatch(const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs) override;
+ virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override;
+ virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL dispose() override;
+
+ virtual void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit > & rToolkit, const css::uno::Reference< css::awt::XWindowPeer > & rParentPeer) override;
+
+ protected:
+ virtual rtl::Reference<FmXGridPeer> imp_CreatePeer(vcl::Window* pParent) override;
+ };
+
+ // SbaXGridPeer
+
+ class SbaXGridPeer final
+ :public FmXGridPeer
+ ,public css::frame::XDispatch
+ {
+ comphelper::OMultiTypeInterfaceContainerHelperVar3< css::frame::XStatusListener,
+ css::util::URL, SbaURLCompare> m_aStatusListeners;
+
+ public:
+ SbaXGridPeer(const css::uno::Reference< css::uno::XComponentContext >&);
+ virtual ~SbaXGridPeer() override;
+
+ // UNO
+ virtual void SAL_CALL acquire() noexcept override { FmXGridPeer::acquire(); }
+ virtual void SAL_CALL release() noexcept override { FmXGridPeer::release(); }
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+ UNO3_GETIMPLEMENTATION_DECL(SbaXGridPeer)
+
+ // css::frame::XDispatch
+ virtual void SAL_CALL dispatch(const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs) override;
+ virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override;
+ virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override;
+
+ // css::frame::XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL dispose() override;
+
+ private:
+ virtual VclPtr<FmGridControl> imp_CreateControl(vcl::Window* pParent, WinBits nStyle) override;
+ void NotifyStatusChanged(const css::util::URL& aUrl, const css::uno::Reference< css::frame::XStatusListener > & xControl);
+
+ // for any execution of XDispatch::dispatch
+ struct DispatchArgs
+ {
+ css::util::URL aURL;
+ css::uno::Sequence< css::beans::PropertyValue > aArgs;
+ };
+ std::queue< DispatchArgs > m_aDispatchArgs;
+ DECL_LINK( OnDispatchEvent, void*, void );
+
+ // for dynamic states of our 4 dispatchable URLs
+ enum DispatchType
+ {
+ dtBrowserAttribs,
+ dtRowHeight,
+ dtColumnAttribs,
+ dtColumnWidth,
+
+ dtUnknown
+ };
+ static DispatchType classifyDispatchURL( const css::util::URL& _rURL );
+
+ typedef std::map<DispatchType, bool> MapDispatchToBool;
+ MapDispatchToBool m_aDispatchStates;
+ };
+
+ // SbaGridHeader
+
+ class SbaGridHeader
+ :public FmGridHeader
+ ,public DragSourceHelper
+ {
+ public:
+ SbaGridHeader(BrowseBox* pParent);
+ virtual void dispose() override;
+ virtual ~SbaGridHeader() override;
+ protected:
+
+ // FmGridHeader overridables
+ virtual void PreExecuteColumnContextMenu(sal_uInt16 nColId, weld::Menu& rMenu,
+ weld::Menu& rInsertMenu, weld::Menu& rChangeMenu,
+ weld::Menu& rShowMenu) override;
+ virtual void PostExecuteColumnContextMenu(sal_uInt16 nColId, const weld::Menu& rMenu, const OString& rExecutionResult) override;
+
+ private:
+ // DragSourceHelper overridables
+ virtual void StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) override;
+
+ // Window overridables
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+
+ void ImplStartColumnDrag(sal_Int8 _nAction, const Point& _rMousePos);
+ };
+
+ // interfaces for communication between the vcl grid control and a controller
+ class SbaGridListener
+ {
+ public:
+ virtual void RowChanged() = 0;
+ virtual void ColumnChanged() = 0;
+ virtual void SelectionChanged() = 0;
+ virtual void CellActivated() = 0;
+ virtual void CellDeactivated() = 0;
+ virtual void BeforeDrop() = 0;
+ virtual void AfterDrop() = 0;
+
+ protected:
+ ~SbaGridListener() {}
+ };
+
+ // SbaGridControl
+ class SbaGridControl final : public FmGridControl
+ {
+ friend class SbaGridHeader;
+ friend class SbaXGridPeer;
+
+ // Attributes
+ svx::ODataAccessDescriptor m_aDataDescriptor;
+ SbaGridListener* m_pMasterListener;
+
+ ImplSVEvent * m_nAsyncDropEvent;
+
+ bool m_bActivatingForDrop;
+
+ public:
+ SbaGridControl(css::uno::Reference< css::uno::XComponentContext > const & _rM, Window* pParent, FmXGridPeer* _pPeer, WinBits nBits);
+ virtual ~SbaGridControl() override;
+ virtual void dispose() override;
+
+ virtual void Select() override;
+
+ void SetMasterListener(SbaGridListener* pListener) { m_pMasterListener = pListener; }
+
+ virtual void ActivateCell(sal_Int32 nRow, sal_uInt16 nCol, bool bSetCellFocus = true) override;
+ virtual void DeactivateCell(bool bUpdate = true) override;
+ using FmGridControl::ActivateCell;
+
+ bool IsAllSelected() const { return (GetSelectRowCount() == GetRowCount()) && (GetRowCount() > 0); }
+
+ HeaderBar* GetHeaderBar() const { return FmGridControl::GetHeaderBar(); }
+
+ /** return the description of the specified object.
+ @param eObjType
+ The type to ask for
+ @param _nPosition
+ The position of a tablecell (index position), header bar column/row cell
+ @return
+ The description of the specified object.
+ */
+ virtual OUString GetAccessibleObjectDescription( AccessibleBrowseBoxObjType eObjType,sal_Int32 _nPosition = -1) const override;
+
+ using FmGridControl::DeleteSelectedRows;
+ /** copies the currently selected rows to the clipboard
+ @precond
+ at least one row is selected
+ */
+ void CopySelectedRowsToClipboard();
+
+ private:
+ // DragSourceHelper overridables
+ virtual void StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) override;
+
+ // BrowseBox overridables
+ virtual sal_Int8 AcceptDrop( const BrowserAcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) override;
+ virtual void MouseButtonDown( const BrowserMouseEvent& rMEvt) override;
+
+ // EditBrowseBox overridables
+ virtual VclPtr<BrowserHeader> imp_CreateHeaderBar(BrowseBox* pParent) override;
+ virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override;
+
+ // DbGridControl overridables
+ virtual void PreExecuteRowContextMenu(weld::Menu& rMenu) override;
+ virtual void PostExecuteRowContextMenu(const OString& rExecutionResult) override;
+
+ // DbGridControl overridables
+ virtual void onRowChange() override;
+ virtual void onColumnChange() override;
+
+ // get a fields property set from a model pos
+ css::uno::Reference< css::beans::XPropertySet > getField(sal_uInt16 nModelPos);
+
+ // get my data source
+ css::uno::Reference< css::beans::XPropertySet > getDataSource() const;
+
+ // drag events
+ void DoColumnDrag(sal_uInt16 nColumnPos);
+ void DoFieldDrag(sal_uInt16 nColumnPos, sal_Int16 nRowPos);
+
+ void SetBrowserAttrs();
+ void SetColWidth(sal_uInt16 nColId);
+ void SetRowHeight();
+ void SetColAttrs(sal_uInt16 nColId);
+
+ SvNumberFormatter* GetDatasourceFormatter();
+
+ DECL_LINK(AsynchDropEvent, void*, void);
+
+ bool IsReadOnlyDB() const;
+ void implTransferSelectedRows( sal_Int16 nRowPos, bool _bTrueIfClipboardFalseIfDrag );
+
+ using FmGridControl::AcceptDrop;
+ using FmGridControl::ExecuteDrop;
+ using FmGridControl::MouseButtonDown;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/sbamultiplex.hxx b/dbaccess/source/ui/inc/sbamultiplex.hxx
new file mode 100644
index 000000000..d48e3299e
--- /dev/null
+++ b/dbaccess/source/ui/inc/sbamultiplex.hxx
@@ -0,0 +1,308 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/XVetoableChangeListener.hpp>
+#include <com/sun/star/form/XDatabaseParameterListener.hpp>
+#include <com/sun/star/form/XLoadListener.hpp>
+#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/form/XSubmitListener.hpp>
+#include <com/sun/star/form/XResetListener.hpp>
+#include <com/sun/star/sdb/XSQLErrorListener.hpp>
+#include <com/sun/star/sdb/XRowSetApproveListener.hpp>
+#include <com/sun/star/sdbc/XRowSetListener.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <comphelper/uno3.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/multiinterfacecontainer3.hxx>
+#include <cppuhelper/weak.hxx>
+
+namespace dbaui
+{
+ // TODO : replace this class if MM provides a WeakSubObject in cppu
+ class OSbaWeakSubObject : public ::cppu::OWeakObject
+ {
+ protected:
+ ::cppu::OWeakObject& m_rParent;
+
+ public:
+ OSbaWeakSubObject(::cppu::OWeakObject& rParent) : m_rParent(rParent) { }
+
+ virtual void SAL_CALL acquire() noexcept override { m_rParent.acquire(); }
+ virtual void SAL_CALL release() noexcept override { m_rParent.release(); }
+ };
+
+ // some listener multiplexers
+ // css::frame::XStatusListener
+ class SbaXStatusMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::frame::XStatusListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener>
+ {
+ public:
+ SbaXStatusMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXStatusMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& e) override;
+
+ private:
+ css::frame::FeatureStateEvent m_aLastKnownStatus;
+ public:
+ const css::frame::FeatureStateEvent& getLastEvent( ) const { return m_aLastKnownStatus; }
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::form::XLoadListener
+ class SbaXLoadMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::form::XLoadListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::form::XLoadListener>
+ {
+ public:
+ SbaXLoadMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXLoadMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ virtual void SAL_CALL loaded(const css::lang::EventObject& e) override;
+ virtual void SAL_CALL unloaded(const css::lang::EventObject& e) override;
+ virtual void SAL_CALL unloading(const css::lang::EventObject& e) override;
+ virtual void SAL_CALL reloading(const css::lang::EventObject& e) override;
+ virtual void SAL_CALL reloaded(const css::lang::EventObject& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::form::XDatabaseParameterListener
+ class SbaXParameterMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::form::XDatabaseParameterListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::form::XDatabaseParameterListener>
+ {
+ public:
+ SbaXParameterMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXParameterMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+ virtual sal_Bool SAL_CALL approveParameter(const css::form::DatabaseParameterEvent& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::form::XSubmitListener
+ class SbaXSubmitMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::form::XSubmitListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::form::XSubmitListener>
+ {
+ public:
+ SbaXSubmitMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXSubmitMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+ virtual sal_Bool SAL_CALL approveSubmit(const css::lang::EventObject& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::form::XResetListener
+ class SbaXResetMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::form::XResetListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::form::XResetListener>
+ {
+ public:
+ SbaXResetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXResetMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+ virtual sal_Bool SAL_CALL approveReset(const css::lang::EventObject& e) override;
+ virtual void SAL_CALL resetted(const css::lang::EventObject& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::sdbc::XRowSetListener
+ class SbaXRowSetMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::sdbc::XRowSetListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::sdbc::XRowSetListener>
+ {
+ public:
+ SbaXRowSetMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXRowSetMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+ virtual void SAL_CALL cursorMoved(const css::lang::EventObject& e) override;
+ virtual void SAL_CALL rowChanged(const css::lang::EventObject& e) override;
+ virtual void SAL_CALL rowSetChanged(const css::lang::EventObject& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::sdb::XRowSetApproveListener
+ class SbaXRowSetApproveMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::sdb::XRowSetApproveListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::sdb::XRowSetApproveListener>
+ {
+ public:
+ SbaXRowSetApproveMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXRowSetApproveMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+ virtual sal_Bool SAL_CALL approveCursorMove(const css::lang::EventObject& e) override;
+ virtual sal_Bool SAL_CALL approveRowChange(const css::sdb::RowChangeEvent& e) override;
+ virtual sal_Bool SAL_CALL approveRowSetChange(const css::lang::EventObject& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::sdb::XSQLErrorListener
+ class SbaXSQLErrorMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::sdb::XSQLErrorListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::sdb::XSQLErrorListener>
+ {
+ public:
+ SbaXSQLErrorMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXSQLErrorMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+ virtual void SAL_CALL errorOccured(const css::sdb::SQLErrorEvent& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+
+ // css::beans::XPropertyChangeListener
+ class SbaXPropertyChangeMultiplexer final
+ :public OSbaWeakSubObject
+ ,public css::beans::XPropertyChangeListener
+ {
+ typedef ::comphelper::OMultiTypeInterfaceContainerHelperVar3<css::beans::XPropertyChangeListener, OUString> ListenerContainerMap;
+ ListenerContainerMap m_aListeners;
+
+ public:
+ SbaXPropertyChangeMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex );
+ DECLARE_UNO3_DEFAULTS(SbaXPropertyChangeMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& e) override;
+
+ void addInterface(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener >& rListener);
+ void removeInterface(const OUString& rName, const css::uno::Reference< css::beans::XPropertyChangeListener >& rListener);
+
+ void disposeAndClear();
+
+ sal_Int32 getOverallLen() const;
+
+ ::comphelper::OInterfaceContainerHelper3<css::beans::XPropertyChangeListener>* getContainer(const OUString& rName)
+ { return m_aListeners.getContainer(rName); }
+
+ private:
+ void Notify(::comphelper::OInterfaceContainerHelper3<css::beans::XPropertyChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e);
+ };
+
+ // css::beans::XVetoableChangeListener
+ class SbaXVetoableChangeMultiplexer final
+ :public OSbaWeakSubObject
+ ,public css::beans::XVetoableChangeListener
+ {
+ typedef ::comphelper::OMultiTypeInterfaceContainerHelperVar3<css::beans::XVetoableChangeListener, OUString > ListenerContainerMap;
+ ListenerContainerMap m_aListeners;
+
+ public:
+ SbaXVetoableChangeMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex );
+ DECLARE_UNO3_DEFAULTS(SbaXVetoableChangeMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ virtual void SAL_CALL vetoableChange(const css::beans::PropertyChangeEvent& e) override;
+
+ void addInterface(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener >& rListener);
+ void removeInterface(const OUString& rName, const css::uno::Reference< css::beans::XVetoableChangeListener >& rListener);
+
+ void disposeAndClear();
+
+ sal_Int32 getOverallLen() const;
+
+ ::comphelper::OInterfaceContainerHelper3<css::beans::XVetoableChangeListener>* getContainer(const OUString& rName)
+ { return m_aListeners.getContainer(rName); }
+
+ private:
+ void Notify(::comphelper::OInterfaceContainerHelper3<css::beans::XVetoableChangeListener>& rListeners, const css::beans::PropertyChangeEvent& e);
+ };
+
+ // css::beans::XPropertiesChangeListener
+ class SbaXPropertiesChangeMultiplexer
+ :public OSbaWeakSubObject
+ ,public css::beans::XPropertiesChangeListener
+ ,public ::comphelper::OInterfaceContainerHelper3<css::beans::XPropertiesChangeListener>
+ {
+ public:
+ SbaXPropertiesChangeMultiplexer(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex);
+ DECLARE_UNO3_DEFAULTS(SbaXPropertiesChangeMultiplexer, OSbaWeakSubObject)
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ /* css::lang::XEventListener */
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+ virtual void SAL_CALL propertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent >& e) override;
+ /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */
+ using OSbaWeakSubObject::operator new;
+ using OSbaWeakSubObject::operator delete;
+ };
+ // the SbaXPropertiesChangeMultiplexer doesn't care about the property names a listener logs on for, it simply
+ // forwards _all_ changes to _all_ listeners
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/singledoccontroller.hxx b/dbaccess/source/ui/inc/singledoccontroller.hxx
new file mode 100644
index 000000000..e5e11ba7a
--- /dev/null
+++ b/dbaccess/source/ui/inc/singledoccontroller.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <dbaccess/dbsubcomponentcontroller.hxx>
+
+#include <com/sun/star/document/XUndoManagerSupplier.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+class SfxUndoAction;
+class SfxUndoManager;
+
+namespace dbaui
+{
+
+ // OSingleDocumentController
+ struct OSingleDocumentController_Data;
+ typedef ::cppu::ImplInheritanceHelper< DBSubComponentController
+ , css::document::XUndoManagerSupplier
+ > OSingleDocumentController_Base;
+ class OSingleDocumentController : public OSingleDocumentController_Base
+ {
+ protected:
+ OSingleDocumentController( const css::uno::Reference< css::uno::XComponentContext>& _rxORB );
+ virtual ~OSingleDocumentController() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ public:
+ /// need for undo's and redo's
+ SfxUndoManager& GetUndoManager() const;
+
+ /// complete clears the Undo/Redo stacks
+ void ClearUndoManager();
+
+ /** addUndoActionAndInvalidate adds an undo action to the undoManager,
+ additionally invalidates the UNDO and REDO slot
+ @param pAction the undo action to add
+ */
+ void addUndoActionAndInvalidate( std::unique_ptr<SfxUndoAction> pAction );
+
+ // OGenericUnoController
+ virtual FeatureState GetState( sal_uInt16 nId ) const override;
+ virtual void Execute( sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs ) override;
+
+ // XUndoManagerSupplier
+ virtual css::uno::Reference< css::document::XUndoManager > SAL_CALL getUndoManager( ) override;
+
+ // XEventListener
+ using OSingleDocumentController_Base::disposing;
+
+ private:
+ std::unique_ptr< OSingleDocumentController_Data > m_pData;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/sqledit.hxx b/dbaccess/source/ui/inc/sqledit.hxx
new file mode 100644
index 000000000..0f2ecc8b6
--- /dev/null
+++ b/dbaccess/source/ui/inc/sqledit.hxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <comphelper/syntaxhighlight.hxx>
+#include <rtl/ref.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svx/weldeditview.hxx>
+#include <vcl/timer.hxx>
+
+namespace com::sun::star::beans { class XMultiPropertySet; }
+
+namespace dbaui
+{
+ class SQLEditView final : public WeldEditView, public utl::ConfigurationListener
+ {
+ private:
+ class ChangesListener;
+ friend class ChangesListener;
+
+ std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow;
+ Link<LinkParamNone*,void> m_aModifyLink;
+ const svtools::ColorConfig m_aColorConfig;
+ Timer m_aUpdateDataTimer;
+ const SyntaxHighlighter m_aHighlighter;
+ svtools::ColorConfig m_ColorConfig;
+ rtl::Reference<SfxItemPool> m_pItemPool;
+
+ rtl::Reference<ChangesListener> m_listener;
+ osl::Mutex m_mutex;
+ css::uno::Reference<css::beans::XMultiPropertySet> m_notifier;
+
+ bool m_bInUpdate;
+ bool m_bDisableInternalUndo;
+
+ DECL_LINK(ModifyHdl, LinkParamNone*, void);
+ DECL_LINK(ImplUpdateDataHdl, Timer*, void);
+ DECL_LINK(ScrollHdl, weld::ScrolledWindow&, void);
+ DECL_LINK(EditStatusHdl, EditStatus&, void);
+
+ Color GetColorValue(TokenType aToken);
+
+ void ImplSetFont();
+
+ void DoBracketHilight(sal_uInt16 nKey);
+
+ static void SetItemPoolFont(SfxItemPool* pItemPool);
+
+ void UpdateData();
+
+ void SetScrollBarRange();
+ void DoScroll();
+
+ virtual void EditViewScrollStateChange() override;
+
+ public:
+ SQLEditView(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow);
+ virtual void makeEditEngine() override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual ~SQLEditView() override;
+
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool Command(const CommandEvent& rCEvt) override;
+
+ void SetTextAndUpdate(const OUString& rNewText);
+
+ void SetModifyHdl(const Link<LinkParamNone*,void>& rLink)
+ {
+ m_aModifyLink = rLink;
+ }
+
+ void DisableInternalUndo();
+
+ static Color GetSyntaxHighlightColor(const svtools::ColorConfig& rColorConfig, HighlighterLanguage eLanguage, TokenType aToken);
+
+ virtual void ConfigurationChanged(utl::ConfigurationBroadcaster*, ConfigurationHints) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/sqlmessage.hxx b/dbaccess/source/ui/inc/sqlmessage.hxx
new file mode 100644
index 000000000..a2541dc0f
--- /dev/null
+++ b/dbaccess/source/ui/inc/sqlmessage.hxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/dbexception.hxx>
+#include <vcl/weld.hxx>
+#include <memory>
+
+// some forwards
+namespace com::sun::star {
+ namespace sdb {
+ class SQLContext;
+ }
+ namespace sdbc {
+ class SQLException;
+ }
+}
+
+namespace dbaui
+{
+
+enum MessageType
+{
+ Info,
+ Error,
+ Warning,
+ Query,
+ AUTO
+};
+
+enum class MessBoxStyle {
+ NONE = 0x0000,
+ Ok = 0x0001,
+ OkCancel = 0x0002,
+ YesNo = 0x0004,
+ YesNoCancel = 0x0008,
+ RetryCancel = 0x0010,
+ DefaultOk = 0x0020,
+ DefaultCancel = 0x0040,
+ DefaultRetry = 0x0080,
+ DefaultYes = 0x0100,
+ DefaultNo = 0x0200,
+};
+
+}
+
+namespace o3tl {
+ template<> struct typed_flags<dbaui::MessBoxStyle> : is_typed_flags<dbaui::MessBoxStyle, 0x03ff> {};
+}
+
+
+namespace dbaui
+{
+
+// OSQLMessageBox
+struct SQLMessageBox_Impl;
+class OSQLMessageBox : public weld::DialogController
+{
+ std::unique_ptr<weld::MessageDialog> m_xDialog;
+ std::unique_ptr<weld::Button> m_xMoreButton;
+ std::unique_ptr<SQLMessageBox_Impl> m_pImpl;
+ OUString m_sHelpURL;
+
+ virtual weld::Dialog* getDialog() override { return m_xDialog.get(); }
+public:
+ /** display an SQLException with auto-recognizing a main and a detailed message
+
+ The first two messages from the exception chain are used as main and detailed message (recognizing the
+ detailed field of an <type scope="css::sdb">SQLContext</type>).
+ */
+ OSQLMessageBox(
+ weld::Window* pParent,
+ const dbtools::SQLExceptionInfo& _rException,
+ MessBoxStyle _nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk,
+ const OUString& _rHelpURL = OUString()
+ );
+
+ /** display a database related error message
+
+ @param rTitle the title to display
+ @param rMessage the detailed message to display
+ @param _eType determines the image to use. AUTO is disallowed in this constructor version
+ */
+ OSQLMessageBox(weld::Window* pParent,
+ const OUString& rTitle,
+ const OUString& rMessage,
+ MessBoxStyle nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk,
+ MessageType _eType = Info,
+ const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo = nullptr );
+
+ void set_title(const OUString& rTitle) { m_xDialog->set_title(rTitle); }
+ void add_button(const OUString& rText, int nResponse, const OString& rHelpId = OString()) { m_xDialog->add_button(rText, nResponse, rHelpId); }
+ void set_default_response(int nResponse) { m_xDialog->set_default_response(nResponse); }
+
+ virtual ~OSQLMessageBox() override;
+
+private:
+ void Construct(weld::Window* pParent, MessBoxStyle nStyle, MessageType eImage);
+
+ DECL_LINK(ButtonClickHdl, weld::Button&, void);
+
+private:
+ void impl_fillMessages();
+ void impl_createStandardButtons( MessBoxStyle _nStyle );
+ void impl_addDetailsButton();
+};
+
+// OSQLWarningBox
+class OSQLWarningBox : public OSQLMessageBox
+{
+public:
+ OSQLWarningBox( weld::Window* pParent,
+ const OUString& _rMessage,
+ MessBoxStyle _nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk,
+ const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo = nullptr );
+};
+
+// OSQLErrorBox
+class OSQLErrorBox : public OSQLMessageBox
+{
+public:
+ OSQLErrorBox( weld::Window* pParent,
+ const OUString& _rMessage );
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/stringlistitem.hxx b/dbaccess/source/ui/inc/stringlistitem.hxx
new file mode 100644
index 000000000..3d16f6770
--- /dev/null
+++ b/dbaccess/source/ui/inc/stringlistitem.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/poolitem.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <rtl/ustring.hxx>
+
+namespace dbaui
+{
+// OStringListItem
+/** <type>SfxPoolItem</type> which transports a sequence of <type scope="rtl">OUString</type>'s
+*/
+class OStringListItem : public SfxPoolItem
+{
+ css::uno::Sequence<OUString> m_aList;
+
+public:
+ OStringListItem(sal_Int16 nWhich, const css::uno::Sequence<OUString>& _rList);
+ OStringListItem(const OStringListItem& _rSource);
+
+ virtual bool operator==(const SfxPoolItem& _rItem) const override;
+ virtual OStringListItem* Clone(SfxItemPool* _pPool = nullptr) const override;
+
+ const css::uno::Sequence<OUString>& getList() const { return m_aList; }
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/tabletree.hxx b/dbaccess/source/ui/inc/tabletree.hxx
new file mode 100644
index 000000000..ebfbf7d29
--- /dev/null
+++ b/dbaccess/source/ui/inc/tabletree.hxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "imageprovider.hxx"
+#include "dbtreelistbox.hxx"
+
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <memory>
+
+namespace dbaui
+{
+
+// OTableTreeListBox
+class OTableTreeListBox : public TreeListBox
+{
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xConnection; // the connection we're working for, set in implOnNewConnection, called by UpdateTableList
+ std::unique_ptr< ImageProvider >
+ m_xImageProvider; // provider for our images
+ bool m_bVirtualRoot; // should the first entry be visible
+ bool m_bNoEmptyFolders; // should empty catalogs/schematas be prevented from being displayed?
+ bool m_bShowToggles; // show toggle buttons
+
+public:
+ OTableTreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bShowToggles);
+
+ void init() { m_bVirtualRoot = true; }
+
+ typedef std::pair< OUString, bool > TTableViewName;
+ typedef std::vector< TTableViewName > TNames;
+
+ void SuppressEmptyFolders() { m_bNoEmptyFolders = true; }
+
+ /** determines whether the given entry denotes a tables folder
+ */
+ bool isFolderEntry(const weld::TreeIter& rEntry) const;
+
+ /** fill the table list with the tables belonging to the connection described by the parameters
+ @param _rxConnection
+ the connection, which must support the service com.sun.star.sdb.Connection
+ @throws
+ <type scope="css::sdbc">SQLException</type> if no connection could be created
+ */
+ void UpdateTableList(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+
+ /** fill the table list with the tables and views determined by the two given containers.
+ The views sequence is used to determine which table is of type view.
+ @param _rxConnection the connection where you got the object names from. Must not be NULL.
+ Used to split the full qualified names into its parts.
+ @param _rTables table/view sequence
+ @param _rViews view sequence
+ */
+ void UpdateTableList(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Sequence< OUString>& _rTables,
+ const css::uno::Sequence< OUString>& _rViews
+ );
+
+ /** to be used if a foreign instance added a table
+ */
+ std::unique_ptr<weld::TreeIter> addedTable( const OUString& _rName );
+
+ /** to be used if a foreign instance removed a table
+ */
+ void removedTable( const OUString& _rName );
+
+ std::unique_ptr<weld::TreeIter> getAllObjectsEntry() const;
+
+ /** does a wildcard check of the given entry
+ <p>There are two different 'checked' states: If the user checks all children of an entry, this is different
+ from checking the entry itself. The second is called 'wildcard' checking, 'cause in the resulting
+ table filter it's represented by a wildcard.</p>
+ */
+ void checkWildcard(const weld::TreeIter& rEntry);
+
+ /** determine if the given entry is 'wildcard checked'
+ @see checkWildcard
+ */
+ bool isWildcardChecked(const weld::TreeIter& rEntry);
+
+ void CheckButtons(); // make the button states consistent (bottom-up)
+
+ void checkedButton_noBroadcast(const weld::TreeIter& rEntry);
+private:
+ TriState implDetermineState(const weld::TreeIter& rEntry);
+
+ void implEmphasize(const weld::TreeIter& rEntry, bool _bChecked, bool _bUpdateDescendants = true, bool _bUpdateAncestors = true);
+
+ /** adds the given entry to our list
+ @precond
+ our image provider must already have been reset to the connection to which the meta data
+ belong.
+ */
+ std::unique_ptr<weld::TreeIter> implAddEntry(
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxMeta,
+ const OUString& _rTableName,
+ bool _bCheckName = true
+ );
+
+ void implOnNewConnection( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection );
+
+ bool impl_getAndAssertMetaData( css::uno::Reference< css::sdbc::XDatabaseMetaData >& _out_rMetaData ) const;
+
+ bool haveVirtualRoot() const { return m_bVirtualRoot; }
+
+public:
+ /** fill the table list with the tables and views determined by the two given containers
+ @param _rxConnection the connection where you got the object names from. Must not be NULL.
+ Used to split the full qualified names into its parts.
+ @param _rTables table/view sequence, the second argument is <TRUE/> if it is a table, otherwise it is a view.
+ */
+ void UpdateTableList(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const TNames& _rTables
+ );
+
+ /** returns a NamedDatabaseObject record which describes the given entry
+ */
+ css::sdb::application::NamedDatabaseObject
+ describeObject(const weld::TreeIter& rEntry);
+
+ /** returns the fully qualified name of a table entry
+ @param _pEntry
+ the entry whose name is to be obtained. Must not denote a folder entry.
+ */
+ OUString getQualifiedTableName(const weld::TreeIter& rEntry) const;
+
+ std::unique_ptr<weld::TreeIter> getEntryByQualifiedName(const OUString& rName);
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/textconnectionsettings.hxx b/dbaccess/source/ui/inc/textconnectionsettings.hxx
new file mode 100644
index 000000000..9d21c8795
--- /dev/null
+++ b/dbaccess/source/ui/inc/textconnectionsettings.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "propertystorage.hxx"
+#include <vcl/weld.hxx>
+#include <memory>
+
+class SfxItemSet;
+namespace dbaui
+{
+
+ class OTextConnectionHelper;
+
+ // TextConnectionSettingsDialog
+ class TextConnectionSettingsDialog : public weld::GenericDialogController
+ {
+ public:
+ TextConnectionSettingsDialog(weld::Window* _pParent, SfxItemSet& rItems);
+ virtual ~TextConnectionSettingsDialog() override;
+
+ /** initializes a set of PropertyStorage instances, which are bound to
+ the text-connection relevant items in our item sets
+ */
+ static void bindItemStorages( SfxItemSet& _rSet, PropertyValues& _rValues );
+
+ virtual short run() override;
+
+ private:
+ SfxItemSet& m_rItems;
+
+ std::unique_ptr<weld::Widget> m_xContainer;
+ std::unique_ptr<weld::Button> m_xOK;
+ std::unique_ptr<OTextConnectionHelper> m_xTextConnectionHelper;
+
+ private:
+ DECL_LINK(OnOK, weld::Button&, void);
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/undosqledit.hxx b/dbaccess/source/ui/inc/undosqledit.hxx
new file mode 100644
index 000000000..2b760bbad
--- /dev/null
+++ b/dbaccess/source/ui/inc/undosqledit.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "GeneralUndo.hxx"
+#include <strings.hrc>
+
+namespace dbaui
+{
+ class OQueryTextView;
+
+ // OSqlEditUndoAct - Undo-class for changing sql text
+ class OSqlEditUndoAct final : public OCommentUndoAction
+ {
+ OQueryTextView& m_rOwner;
+ OUString m_strNextText;
+
+ virtual void Undo() override { ToggleText(); }
+ virtual void Redo() override { ToggleText(); }
+
+ void ToggleText();
+ public:
+ OSqlEditUndoAct(OQueryTextView& rEdit) : OCommentUndoAction(STR_QUERY_UNDO_MODIFYSQLEDIT), m_rOwner(rEdit) { }
+
+ void SetOriginalText(const OUString& strText) { m_strNextText = strText; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/unoadmin.hxx b/dbaccess/source/ui/inc/unoadmin.hxx
new file mode 100644
index 000000000..944dccf87
--- /dev/null
+++ b/dbaccess/source/ui/inc/unoadmin.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/genericunodialog.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <dsntypes.hxx>
+
+class SfxItemSet;
+class SfxItemPool;
+class SfxPoolItem;
+
+namespace dbaui
+{
+
+// ODatabaseAdministrationDialog
+typedef ::svt::OGenericUnoDialog ODatabaseAdministrationDialogBase;
+class ODatabaseAdministrationDialog
+ :public ODatabaseAdministrationDialogBase
+{
+protected:
+ std::unique_ptr<SfxItemSet> m_pDatasourceItems; // item set for the dialog
+ rtl::Reference<SfxItemPool> m_pItemPool; // item pool for the item set for the dialog
+ std::vector<SfxPoolItem*>*
+ m_pItemPoolDefaults; // pool defaults
+ std::unique_ptr<::dbaccess::ODsnTypeCollection>
+ m_pCollection; // datasource type collection
+
+ css::uno::Any m_aInitialSelection;
+ css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection;
+
+protected:
+ ODatabaseAdministrationDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+ virtual ~ODatabaseAdministrationDialog() override;
+protected:
+// OGenericUnoDialog overridables
+ virtual void implInitialize(const css::uno::Any& _rValue) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/unodatbr.hxx b/dbaccess/source/ui/inc/unodatbr.hxx
new file mode 100644
index 000000000..4bb5c26c7
--- /dev/null
+++ b/dbaccess/source/ui/inc/unodatbr.hxx
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "brwctrlr.hxx"
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/i18n/XCollator.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <com/sun/star/ui/XContextMenuInterception.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/sdb/XDatabaseRegistrationsListener.hpp>
+#include <comphelper/interfacecontainer2.hxx>
+#include <cppuhelper/implbase5.hxx>
+#include "callbacks.hxx"
+#include <vcl/transfer.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include "TableCopyHelper.hxx"
+#include "commontypes.hxx"
+
+class Splitter;
+class ODataClipboard;
+
+namespace com::sun::star::container { class XNameContainer; }
+
+namespace dbaui
+{
+ struct DBTreeEditedEntry;
+ struct DBTreeListUserData;
+ class ImageProvider;
+
+ typedef ::cppu::ImplHelper5 < css::frame::XStatusListener
+ , css::view::XSelectionSupplier
+ , css::document::XScriptInvocationContext
+ , css::ui::XContextMenuInterception
+ , css::sdb::XDatabaseRegistrationsListener
+ > SbaTableQueryBrowser_Base;
+ class SbaTableQueryBrowser final
+ :public SbaXDataBrowserController
+ ,public SbaTableQueryBrowser_Base
+ ,public IControlActionListener
+ ,public IContextMenuProvider
+ {
+ css::uno::Reference< css::i18n::XCollator > m_xCollator;
+ css::uno::Reference< css::frame::XFrame > m_xCurrentFrameParent;
+ css::uno::Reference< css::awt::XWindow > m_xMainToolbar;
+
+ struct ExternalFeature
+ {
+ css::util::URL aURL;
+ css::uno::Reference< css::frame::XDispatch >
+ xDispatcher;
+ bool bEnabled;
+
+ ExternalFeature() : bEnabled( false ) { }
+ ExternalFeature( const css::util::URL& _rURL ) : aURL( _rURL ), bEnabled( false ) { }
+ };
+
+ typedef std::map< sal_uInt16, ExternalFeature > ExternalFeaturesMap;
+ ExternalFeaturesMap m_aExternalFeatures;
+
+ svx::ODataAccessDescriptor m_aDocumentDataSource;
+ // if we're part of a document, this is the state of the DocumentDataSource slot
+
+ ::comphelper::OInterfaceContainerHelper2 m_aSelectionListeners;
+ ::comphelper::OInterfaceContainerHelper2 m_aContextMenuInterceptors;
+
+ OTableCopyHelper::DropDescriptor m_aAsyncDrop;
+ OTableCopyHelper m_aTableCopyHelper;
+
+ OUString m_sQueryCommand; // the command of the query currently loaded (if any)
+ //OUString m_sToBeLoaded; // contains the element name which should be loaded if any
+
+ VclPtr<InterimDBTreeListBox> m_pTreeView; // contains the datasources of the registry
+ VclPtr<Splitter> m_pSplitter;
+ std::unique_ptr<weld::TreeIter> m_xCurrentlyDisplayed;
+ ImplSVEvent * m_nAsyncDrop;
+
+ bool m_bQueryEscapeProcessing : 1; // the escape processing flag of the query currently loaded (if any)
+ bool m_bShowMenu; // if sal_True the menu should be visible otherwise not
+ bool m_bInSuspend;
+ bool m_bEnableBrowser;
+ ::std::optional< bool >
+ m_aDocScriptSupport; // relevant if and only if we are associated with exactly one DBDoc
+
+ virtual OUString getPrivateTitle( ) const override;
+ // attribute access
+ public:
+ SbaTableQueryBrowser(const css::uno::Reference< css::uno::XComponentContext >& _rM);
+ virtual ~SbaTableQueryBrowser() override;
+
+ enum EntryType
+ {
+ // don't change the above definitions! There are places (in particular SbaTableQueryBrowser::getCurrentSelection)
+ // which rely on the fact that the EntryType values really equal the DatabaseObject(Container) values!
+ etDatasource = css::sdb::application::DatabaseObjectContainer::DATA_SOURCE,
+ etQueryContainer = css::sdb::application::DatabaseObjectContainer::QUERIES,
+ etTableContainer = css::sdb::application::DatabaseObjectContainer::TABLES,
+ etQuery = css::sdb::application::DatabaseObject::QUERY,
+ etTableOrView = css::sdb::application::DatabaseObject::TABLE,
+ etUnknown = -1
+ };
+
+ /** returns a DatabaseObject value corresponding to the given EntryType
+ @param _eType
+ the entry type. Must not be etUnknown.
+ */
+ static sal_Int32 getDatabaseObjectType( EntryType _eType );
+
+ DECLARE_UNO3_DEFAULTS(SbaTableQueryBrowser,SbaXDataBrowserController)
+ // late construction
+ virtual bool Construct(vcl::Window* pParent) override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // css::beans::XPropertyChangeListener
+ virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
+
+ // css::frame::XController
+ virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override;
+ virtual void SAL_CALL attachFrame(const css::uno::Reference< css::frame::XFrame > & xFrame) override;
+
+ // css::lang::XComponent
+ virtual void SAL_CALL disposing() override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XSelectionSupplier
+ virtual sal_Bool SAL_CALL select( const css::uno::Any& aSelection ) override;
+ virtual css::uno::Any SAL_CALL getSelection( ) override;
+ virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+ // css::frame::XFrameActionListener
+ virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent& aEvent) override;
+
+ // XScriptInvocationContext
+ virtual css::uno::Reference< css::document::XEmbeddedScripts > SAL_CALL getScriptContainer() override;
+
+ // XContextMenuInterception
+ virtual void SAL_CALL registerContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override;
+ virtual void SAL_CALL releaseContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override;
+
+ // XDatabaseRegistrationsListener
+ virtual void SAL_CALL registeredDatabaseLocation( const css::sdb::DatabaseRegistrationEvent& Event ) override;
+ virtual void SAL_CALL revokedDatabaseLocation( const css::sdb::DatabaseRegistrationEvent& Event ) override;
+ virtual void SAL_CALL changedDatabaseLocation( const css::sdb::DatabaseRegistrationEvent& Event ) override;
+
+ private:
+ // SbaXDataBrowserController overridable
+ virtual bool InitializeForm( const css::uno::Reference< css::beans::XPropertySet >& i_formProperties ) override;
+
+ void InitializeGridModel(const css::uno::Reference< css::form::XFormComponent > & xGrid);
+
+ virtual bool preReloadForm() override;
+ virtual void postReloadForm() override;
+
+ virtual void addModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel) override;
+ virtual void removeModelListeners(const css::uno::Reference< css::awt::XControlModel > & _xGridControlModel) override;
+
+ virtual void AddColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol) override;
+ virtual void RemoveColumnListener(const css::uno::Reference< css::beans::XPropertySet > & xCol) override;
+
+ virtual void LoadFinished(bool _bWasSynch) override;
+
+ virtual void criticalFail() override;
+
+ virtual void describeSupportedFeatures() override;
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ // IControlActionListener overridables
+ virtual bool requestQuickHelp(const void* pUserData, OUString& rText) const override;
+ virtual bool requestDrag(const weld::TreeIter& rEntry) override;
+ virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override;
+ virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override;
+
+ // IContextMenuProvider
+ virtual OUString getContextMenuResourceName() const override;
+ virtual IController& getCommandController() override;
+ virtual ::comphelper::OInterfaceContainerHelper2*
+ getContextMenuInterceptors() override;
+ virtual css::uno::Any getCurrentSelection(weld::TreeView& rControl) const override;
+ virtual vcl::Window* getMenuParent() const override;
+ virtual void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const override;
+
+ virtual void impl_initialize() override;
+
+ // SbaGridListener overridables
+ virtual void RowChanged() override;
+ virtual void ColumnChanged() override;
+ virtual void SelectionChanged() override;
+
+ // methods for showing/hiding the explorer part
+ bool haveExplorer() const;
+ void hideExplorer();
+ void showExplorer();
+ void toggleExplorer() { if (haveExplorer()) hideExplorer(); else showExplorer(); }
+
+ // methods for handling the 'selection' (painting them bold) of SvLBoxEntries
+ // returns <TRUE/> if the entry is selected (which means it's part of the selected path)
+ bool isSelected(const weld::TreeIter& rEntry) const;
+ // select the entry (and only the entry, not the whole path)
+ void select(const weld::TreeIter* pEntry, bool bSelect);
+ // select the path of the entry (which must be an entry without children)
+ void selectPath(const weld::TreeIter* pEntry, bool bSelect = true);
+
+ virtual void loadMenu(const css::uno::Reference< css::frame::XFrame >& _xFrame) override;
+
+ // check the state of the external slot given, update any UI elements if necessary
+ void implCheckExternalSlot( sal_uInt16 _nId );
+
+ // connect to the external dispatchers (if any)
+ void connectExternalDispatches();
+
+ /** get the state of an external slot
+ <p>The slot is available if an external dispatcher is responsible for it, _and_ if this dispatcher
+ told us the slot is available.</p>
+ */
+ bool getExternalSlotState( sal_uInt16 _nId ) const;
+
+ /** add an entry (including the subentries for queries/tables) to the list model
+
+ <p>The given names and images may be empty, in this case they're filled with the correct
+ values. This way they may be reused for the next call, which saves some resource manager calls.</p>
+ */
+ void implAddDatasource(const OUString& _rDbName, OUString& _rDbImage,
+ OUString& _rQueryName, OUString& _rQueryImage,
+ OUString& _rTableName, OUString& _rTableImage,
+ const SharedConnection& _rxConnection
+ );
+
+ void implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection );
+
+ /// removes (and cleans up) the entry for the given data source
+ void impl_cleanupDataSourceEntry( std::u16string_view _rDataSourceName );
+
+ /// clears the tree list box
+ void clearTreeModel();
+
+ /** unloads the form, empties the grid model, cleans up anything related to the currently displayed object
+ @param _bDisposeConnection
+ <TRUE/> if the connection should be disposed
+ @param _bFlushData
+ <TRUE/> if the currently displayed object (if any) should be flushed
+ */
+ void unloadAndCleanup( bool _bDisposeConnection = true );
+
+ // disposes the connection associated with the given entry (which must represent a data source)
+ void disposeConnection(const weld::TreeIter* xpDSEntry);
+
+ /// flushes and disposes the given connection, and de-registers as listener
+ void impl_releaseConnection( SharedConnection& _rxConnection );
+
+ /** close the connection (and collapse the list entries) of the given list entries
+ */
+ void closeConnection(const weld::TreeIter& rEntry, bool bDisposeConnection = true);
+
+ void populateTree(const css::uno::Reference< css::container::XNameAccess>& xNameAccess, const weld::TreeIter& rParent, EntryType eEntryType);
+ void initializeTreeModel();
+
+ /** search in the tree for query- or tablecontainer equal to this interface and return
+ this container entry
+ */
+ std::unique_ptr<weld::TreeIter> getEntryFromContainer(const css::uno::Reference<css::container::XNameAccess>& rxNameAccess);
+
+ // return true when there is connection available
+ bool ensureConnection(const weld::TreeIter* pDSEntry, void * pDSData, SharedConnection& rConnection);
+ bool ensureConnection(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection);
+
+ bool getExistentConnectionFor(const weld::TreeIter* pDSEntry, SharedConnection& rConnection);
+ /** returns an image provider which works with the connection belonging to the given entry
+ */
+ std::unique_ptr<ImageProvider> getImageProviderFor(const weld::TreeIter* pAnyEntry);
+
+ void implAdministrate(const weld::TreeIter& rApplyTo);
+
+ bool implCopyObject(ODataClipboard& rExchange, const weld::TreeIter& rApplyTo, sal_Int32 nCommandType);
+
+ EntryType getEntryType(const weld::TreeIter& rEntry) const;
+ EntryType getChildType(const weld::TreeIter& rEntry) const;
+ static bool isObject( EntryType _eType ) { return ( etTableOrView== _eType ) || ( etQuery == _eType ); }
+ static bool isContainer( EntryType _eType ) { return (etTableContainer == _eType) || (etQueryContainer == _eType); }
+ bool isContainer(const weld::TreeIter& rEntry) const { return isContainer(getEntryType(rEntry)); }
+
+ // ensure that the xObject for the given entry is set on the user data
+ bool ensureEntryObject(const weld::TreeIter& rEntry);
+
+ // get the display text of the entry given
+ OUString GetEntryText(const weld::TreeIter& rEntry) const;
+
+ // is called when a table or a query was selected
+ DECL_LINK( OnSelectionChange, LinkParamNone*, void );
+ DECL_LINK( OnExpandEntry, const weld::TreeIter&, bool );
+
+ DECL_LINK( OnCopyEntry, LinkParamNone*, void );
+
+ int OnTreeEntryCompare(const weld::TreeIter& rLHS, const weld::TreeIter& rRHS);
+
+ DECL_LINK( OnAsyncDrop, void*, void );
+
+ void implRemoveStatusListeners();
+
+ bool implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect = false);
+ bool implSelect(const weld::TreeIter* pEntry);
+
+ /// selects the entry given and loads the grid control with the object's data
+ bool implSelect(
+ const OUString& _rDataSourceName,
+ const OUString& _rCommand,
+ const sal_Int32 _nCommandType,
+ const bool _bEscapeProcessing,
+ const SharedConnection& _rxConnection,
+ bool _bSelectDirect
+ );
+
+ std::unique_ptr<weld::TreeIter> implGetConnectionEntry(const weld::TreeIter& rEntry) const;
+ /// inserts an entry into the tree
+ std::unique_ptr<weld::TreeIter> implAppendEntry(
+ const weld::TreeIter* pParent,
+ const OUString& rName,
+ const DBTreeListUserData* pUserData);
+
+ /// loads the grid control with the data object specified (which may be a table, a query or a command)
+ bool implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand,
+ const sal_Int32 _nCommandType, const bool _bEscapeProcessing, const SharedConnection& _rxConnection );
+
+ /** retrieves the tree entry for the object described by <arg>_rDescriptor</arg>
+ @param rDescriptor
+ the object descriptor
+ @param ppDataSourceEntry
+ If not <NULL/>, the data source tree entry will be returned here
+ @param ppContainerEntry
+ If not <NULL/>, the object container tree entry will be returned here
+ */
+ std::unique_ptr<weld::TreeIter> getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor,
+ std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry
+ );
+ /** retrieves the tree entry for the object described by data source name, command and command type
+ @param rDataSource
+ the data source name
+ @param rCommand
+ the command
+ @param nCommandType
+ the command type
+ @param rDescriptor
+ the object descriptor
+ @param ppDataSourceEntry
+ If not <NULL/>, the data source tree entry will be returned here
+ @param ppContainerEntry
+ If not <NULL/>, the object container tree entry will be returned here
+ @param bExpandAncestors
+ If <TRUE/>, all ancestor on the way to the entry will be expanded
+ */
+ std::unique_ptr<weld::TreeIter> getObjectEntry(
+ const OUString& rDataSource, const OUString& rCommand, sal_Int32 nCommandType,
+ std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry,
+ bool _bExpandAncestors = true,
+ const SharedConnection& rxConnection = SharedConnection()
+ );
+
+ /// checks if m_aDocumentDataSource describes a known object
+ void checkDocumentDataSource();
+
+ static void extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor,
+ OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing);
+
+ void transferChangedControlProperty(const OUString& _rProperty, const css::uno::Any& _rNewValue);
+
+ // checks whether the given tree entry denotes a data source
+ bool impl_isDataSourceEntry(const weld::TreeIter* pEntry) const;
+
+ /// retrieves the data source URL/name for the given entry representing a data source
+ OUString getDataSourceAccessor(const weld::TreeIter& rDataSourceEntry) const;
+
+ /** get the signature (command/escape processing) of the query the form is based on
+ <p>If the for is not based on a query or not even loaded, nothing happens and <FALSE/> is returned.</p>
+ */
+ bool implGetQuerySignature( OUString& _rCommand, bool& _bEscapeProcessing );
+
+ bool isEntryCopyAllowed(const weld::TreeIter& rEntry) const;
+
+ void copyEntry(const weld::TreeIter& rEntry);
+
+ // remove all grid columns and dispose them
+ static void clearGridColumns(const css::uno::Reference< css::container::XNameContainer >& _xColContainer);
+
+ /** checks if the currently displayed entry changed
+ @param rName
+ Name of the changed entry
+ @param rContainer
+ The container of the displayed entry
+ @return
+ <TRUE/> if it is the currently displayed otherwise <FALSE/>
+ */
+ bool isCurrentlyDisplayedChanged(std::u16string_view rName, const weld::TreeIter& rContainer);
+
+ /** called whenever the content of the browser is used for preview, as the very last action
+ of the load process
+ */
+ void initializePreviewMode();
+
+ /** checks whether the Order/Filter clauses set at our row set are valid, removes them if not so
+ */
+ void impl_sanitizeRowSetClauses_nothrow();
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/inc/unosqlmessage.hxx b/dbaccess/source/ui/inc/unosqlmessage.hxx
new file mode 100644
index 000000000..c084ef240
--- /dev/null
+++ b/dbaccess/source/ui/inc/unosqlmessage.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/genericunodialog.hxx>
+#include <comphelper/proparrhlp.hxx>
+
+namespace dbaui
+{
+
+typedef ::svt::OGenericUnoDialog OSQLMessageDialogBase;
+class OSQLMessageDialog final
+ :public OSQLMessageDialogBase
+ ,public ::comphelper::OPropertyArrayUsageHelper< OSQLMessageDialog >
+{
+ // <properties>
+ css::uno::Any m_aException;
+ OUString m_sHelpURL;
+ // </properties>
+
+public:
+ OSQLMessageDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+private:
+ virtual void SAL_CALL initialize(css::uno::Sequence< css::uno::Any > const & args) override;
+
+// OPropertySetHelper overridables
+ // (overwriting these three, because we have some special handling for our property)
+ virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any& _rConvertedValue, css::uno::Any& _rOldValue, sal_Int32 _nHandle, const css::uno::Any& _rValue) override;
+
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/DExport.cxx b/dbaccess/source/ui/misc/DExport.cxx
new file mode 100644
index 000000000..4f25bb467
--- /dev/null
+++ b/dbaccess/source/ui/misc/DExport.cxx
@@ -0,0 +1,840 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DExport.hxx>
+#include <core_resource.hxx>
+
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <sal/log.hxx>
+#include <sfx2/sfxhtml.hxx>
+#include <svl/numuno.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TypeInfo.hxx>
+#include <FieldDescriptions.hxx>
+#include <UITools.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <WCopyTable.hxx>
+#include <unotools/syslocale.hxx>
+#include <svl/numformat.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/FValue.hxx>
+#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
+#include <sqlmessage.hxx>
+#include "UpdateHelperImpl.hxx"
+#include <cppuhelper/exc_hlp.hxx>
+
+using namespace dbaui;
+using namespace utl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::awt;
+
+namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
+
+// ODatabaseExport
+ODatabaseExport::ODatabaseExport(sal_Int32 nRows,
+ TPositions&&_rColumnPositions,
+ const Reference< XNumberFormatter >& _rxNumberF,
+ const Reference< css::uno::XComponentContext >& _rxContext,
+ const TColumnVector* pList,
+ const OTypeInfoMap* _pInfoMap,
+ bool _bAutoIncrementEnabled,
+ SvStream& _rInputStream)
+ :m_vColumnPositions(std::move(_rColumnPositions))
+ ,m_aDestColumns(true)
+ ,m_xFormatter(_rxNumberF)
+ ,m_xContext(_rxContext)
+ ,m_pFormatter(nullptr)
+ ,m_rInputStream( _rInputStream )
+ ,m_pColumnList(pList)
+ ,m_pInfoMap(_pInfoMap)
+ ,m_nColumnPos(0)
+ ,m_nRows(1)
+ ,m_nRowCount(0)
+ ,m_bError(false)
+ ,m_bInTbl(false)
+ ,m_bHead(true)
+ ,m_bDontAskAgain(false)
+ ,m_bIsAutoIncrement(_bAutoIncrementEnabled)
+ ,m_bFoundTable(false)
+ ,m_bCheckOnly(false)
+ ,m_bAppendFirstLine(false)
+{
+ m_nRows += nRows;
+ sal_Int32 nCount = 0;
+ for(const std::pair<sal_Int32,sal_Int32> & rPair : m_vColumnPositions)
+ if ( rPair.first != COLUMN_POSITION_NOT_FOUND )
+ ++nCount;
+
+ m_vColumnSize.resize(nCount);
+ m_vNumberFormat.resize(nCount);
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ m_vColumnSize[i] = 0;
+ m_vNumberFormat[i] = 0;
+ }
+
+ try
+ {
+ SvtSysLocale aSysLocale;
+ m_aLocale = aSysLocale.GetLanguageTag().getLocale();
+ }
+ catch(Exception&)
+ {
+ }
+
+ SetColumnTypes(pList,_pInfoMap);
+}
+
+ODatabaseExport::ODatabaseExport(const SharedConnection& _rxConnection,
+ const Reference< XNumberFormatter >& _rxNumberF,
+ const Reference< css::uno::XComponentContext >& _rxContext,
+ SvStream& _rInputStream)
+ :m_aDestColumns(_rxConnection->getMetaData().is() && _rxConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers())
+ ,m_xConnection(_rxConnection)
+ ,m_xFormatter(_rxNumberF)
+ ,m_xContext(_rxContext)
+ ,m_pFormatter(nullptr)
+ ,m_rInputStream( _rInputStream )
+ ,m_pColumnList(nullptr)
+ ,m_pInfoMap(nullptr)
+ ,m_nColumnPos(0)
+ ,m_nRows(1)
+ ,m_nRowCount(0)
+ ,m_bError(false)
+ ,m_bInTbl(false)
+ ,m_bHead(true)
+ ,m_bDontAskAgain(false)
+ ,m_bIsAutoIncrement(false)
+ ,m_bFoundTable(false)
+ ,m_bCheckOnly(false)
+ ,m_bAppendFirstLine(false)
+{
+ try
+ {
+ SvtSysLocale aSysLocale;
+ m_aLocale = aSysLocale.GetLanguageTag().getLocale();
+ }
+ catch(Exception&)
+ {
+ }
+
+ Reference<XTablesSupplier> xTablesSup(m_xConnection,UNO_QUERY);
+ if(xTablesSup.is())
+ m_xTables = xTablesSup->getTables();
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ Reference<XResultSet> xSet = xMeta.is() ? xMeta->getTypeInfo() : Reference<XResultSet>();
+ if(xSet.is())
+ {
+ ::connectivity::ORowSetValue aValue;
+ std::vector<sal_Int32> aTypes;
+ std::vector<bool> aNullable;
+ Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xSet,UNO_QUERY_THROW)->getMetaData();
+ Reference<XRow> xRow(xSet,UNO_QUERY_THROW);
+ while(xSet->next())
+ {
+ if ( aTypes.empty() )
+ {
+ sal_Int32 nCount = xResultSetMetaData->getColumnCount();
+ if ( nCount < 1 )
+ nCount = 18;
+ aTypes.reserve(nCount+1);
+ aNullable.reserve(nCount+1);
+ aTypes.push_back(-1);
+ aNullable.push_back(false);
+ for (sal_Int32 j = 1; j <= nCount ; ++j)
+ {
+ aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS );
+ aTypes.push_back(xResultSetMetaData->getColumnType(j));
+ }
+ }
+
+ sal_Int32 nPos = 1;
+ OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector");
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ OUString sTypeName = aValue.getString();
+ ++nPos;
+ OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector");
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ sal_Int32 nType = aValue.getInt32();
+ ++nPos;
+
+ if( nType == DataType::VARCHAR )
+ {
+ m_pTypeInfo = std::make_shared<OTypeInfo>();
+
+ m_pTypeInfo->aTypeName = sTypeName;
+ m_pTypeInfo->nType = nType;
+
+ OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector");
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->nPrecision = aValue.getInt32();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralPrefix
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->aCreateParams = aValue.getString();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->bNullable = aValue.getInt32() == ColumnValue::NULLABLE;
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ // bCaseSensitive
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->nSearchType = aValue.getInt16();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ // bUnsigned
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->bCurrency = aValue.getBool();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->bAutoIncrement = aValue.getBool();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->aLocalTypeName = aValue.getString();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->nMinimumScale = aValue.getInt16();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ m_pTypeInfo->nMaximumScale = aValue.getInt16();
+ nPos = 18;
+ aValue.fill(nPos,aTypes[nPos],xRow);
+ m_pTypeInfo->nNumPrecRadix = aValue.getInt32();
+
+ // check if values are less than zero like it happens in a oracle jdbc driver
+ if( m_pTypeInfo->nPrecision < 0)
+ m_pTypeInfo->nPrecision = 0;
+ if( m_pTypeInfo->nMinimumScale < 0)
+ m_pTypeInfo->nMinimumScale = 0;
+ if( m_pTypeInfo->nMaximumScale < 0)
+ m_pTypeInfo->nMaximumScale = 0;
+ if( m_pTypeInfo->nNumPrecRadix <= 1)
+ m_pTypeInfo->nNumPrecRadix = 10;
+ break;
+ }
+ }
+ }
+ if ( !m_pTypeInfo )
+ m_pTypeInfo = std::make_shared<OTypeInfo>();
+}
+
+ODatabaseExport::~ODatabaseExport()
+{
+ m_pFormatter = nullptr;
+ for (auto const& destColumn : m_aDestColumns)
+ delete destColumn.second;
+ m_vDestVector.clear();
+ m_aDestColumns.clear();
+}
+
+void ODatabaseExport::insertValueIntoColumn()
+{
+ if(m_nColumnPos >= sal_Int32(m_vDestVector.size()))
+ return;
+
+ OFieldDescription* pField = m_vDestVector[m_nColumnPos]->second;
+ if(!pField)
+ return;
+
+ sal_Int32 nNewPos = m_bIsAutoIncrement ? m_nColumnPos+1 : m_nColumnPos;
+ OSL_ENSURE(nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()),"m_vColumnPositions: Illegal index for vector");
+
+ if ( nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size() ) )
+ {
+ sal_Int32 nPos = m_vColumnPositions[nNewPos].first;
+ if ( nPos != COLUMN_POSITION_NOT_FOUND )
+ {
+ if ( m_sTextToken.isEmpty() && pField->IsNullable() )
+ m_pUpdateHelper->updateNull(nPos,pField->GetType());
+ else
+ {
+ OSL_ENSURE((nNewPos) < static_cast<sal_Int32>(m_vColumnTypes.size()),"Illegal index for vector");
+ if (m_vColumnTypes[nNewPos] != DataType::VARCHAR && m_vColumnTypes[nNewPos] != DataType::CHAR && m_vColumnTypes[nNewPos] != DataType::LONGVARCHAR )
+ {
+ SAL_INFO("dbaccess.ui", "ODatabaseExport::insertValueIntoColumn != DataType::VARCHAR" );
+ ensureFormatter();
+ sal_Int32 nNumberFormat = 0;
+ double fOutNumber = 0.0;
+ bool bNumberFormatError = false;
+ if ( m_pFormatter && !m_sNumToken.isEmpty() )
+ {
+ LanguageType eNumLang = LANGUAGE_NONE;
+ sal_uInt32 nNumberFormat2( nNumberFormat );
+ fOutNumber = SfxHTMLParser::GetTableDataOptionsValNum(nNumberFormat2,eNumLang,m_sTextToken,m_sNumToken,*m_pFormatter);
+ if ( eNumLang != LANGUAGE_NONE )
+ {
+ nNumberFormat2 = m_pFormatter->GetFormatForLanguageIfBuiltIn( nNumberFormat2, eNumLang );
+ (void)m_pFormatter->IsNumberFormat( m_sTextToken, nNumberFormat2, fOutNumber );
+ }
+ nNumberFormat = static_cast<sal_Int32>(nNumberFormat2);
+ }
+ else
+ {
+ Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier();
+ Reference<XNumberFormatTypes> xNumType(xSupplier->getNumberFormats(),UNO_QUERY);
+ const sal_Int16 nFormats[] = {
+ NumberFormat::DATETIME
+ ,NumberFormat::DATE
+ ,NumberFormat::TIME
+ ,NumberFormat::CURRENCY
+ ,NumberFormat::NUMBER
+ ,NumberFormat::LOGICAL
+ };
+ for (short nFormat : nFormats)
+ {
+ try
+ {
+ nNumberFormat = m_xFormatter->detectNumberFormat(xNumType->getStandardFormat(nFormat,m_aLocale),m_sTextToken);
+ break;
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ try
+ {
+ fOutNumber = m_xFormatter->convertStringToNumber(nNumberFormat,m_sTextToken);
+ }
+ catch(Exception&)
+ {
+ bNumberFormatError = true;
+ m_pUpdateHelper->updateString(nPos,m_sTextToken);
+ }
+ }
+ if ( !bNumberFormatError )
+ {
+ try
+ {
+ Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier();
+ Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats();
+ Reference<XPropertySet> xProp = xFormats->getByKey(nNumberFormat);
+ sal_Int16 nType = 0;
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ switch(nType)
+ {
+ case NumberFormat::DATE:
+ m_pUpdateHelper->updateDate(nPos,::dbtools::DBTypeConversion::toDate(fOutNumber,m_aNullDate));
+ break;
+ case NumberFormat::DATETIME:
+ m_pUpdateHelper->updateTimestamp(nPos,::dbtools::DBTypeConversion::toDateTime(fOutNumber,m_aNullDate));
+ break;
+ case NumberFormat::TIME:
+ m_pUpdateHelper->updateTime(nPos,::dbtools::DBTypeConversion::toTime(fOutNumber));
+ break;
+ default:
+ m_pUpdateHelper->updateDouble(nPos,fOutNumber);
+ }
+ }
+ catch(Exception&)
+ {
+ m_pUpdateHelper->updateString(nPos,m_sTextToken);
+ }
+ }
+
+ }
+ else
+ m_pUpdateHelper->updateString(nPos,m_sTextToken);
+ }
+ }
+ }
+ eraseTokens();
+}
+
+sal_Int16 ODatabaseExport::CheckString(const OUString& aCheckToken, sal_Int16 _nOldNumberFormat)
+{
+ sal_Int16 nNumberFormat = 0;
+
+ try
+ {
+ Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier();
+ Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats();
+
+ ensureFormatter();
+ if ( m_pFormatter && !m_sNumToken.isEmpty() )
+ {
+ LanguageType eNumLang;
+ sal_uInt32 nFormatKey(0);
+ double fOutNumber = SfxHTMLParser::GetTableDataOptionsValNum(nFormatKey,eNumLang,m_sTextToken,m_sNumToken,*m_pFormatter);
+ if ( eNumLang != LANGUAGE_NONE )
+ {
+ nFormatKey = m_pFormatter->GetFormatForLanguageIfBuiltIn( nFormatKey, eNumLang );
+ if ( !m_pFormatter->IsNumberFormat( m_sTextToken, nFormatKey, fOutNumber ) )
+ return NumberFormat::TEXT;
+ }
+ Reference<XPropertySet> xProp = xFormats->getByKey(nFormatKey);
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= nNumberFormat;
+ }
+ else
+ {
+ Reference<XNumberFormatTypes> xNumType(xFormats,UNO_QUERY);
+ sal_Int32 nFormatKey = m_xFormatter->detectNumberFormat(xNumType->getStandardFormat(NumberFormat::ALL,m_aLocale),aCheckToken);
+ m_xFormatter->convertStringToNumber(nFormatKey,aCheckToken);
+
+ Reference<XPropertySet> xProp = xFormats->getByKey(nFormatKey);
+ sal_Int16 nType = 0;
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= nType;
+
+ switch(nType)
+ {
+ case NumberFormat::ALL:
+ nNumberFormat = NumberFormat::ALL;
+ break;
+ case NumberFormat::DEFINED:
+ nNumberFormat = NumberFormat::TEXT;
+ break;
+ case NumberFormat::DATE:
+ switch(_nOldNumberFormat)
+ {
+ case NumberFormat::DATETIME:
+ case NumberFormat::TEXT:
+ case NumberFormat::DATE:
+ nNumberFormat = _nOldNumberFormat;
+ break;
+ case NumberFormat::ALL:
+ nNumberFormat = NumberFormat::DATE;
+ break;
+ default:
+ nNumberFormat = NumberFormat::TEXT;
+
+ }
+ break;
+ case NumberFormat::TIME:
+ switch(_nOldNumberFormat)
+ {
+ case NumberFormat::DATETIME:
+ case NumberFormat::TEXT:
+ case NumberFormat::TIME:
+ nNumberFormat = _nOldNumberFormat;
+ break;
+ case NumberFormat::ALL:
+ nNumberFormat = NumberFormat::TIME;
+ break;
+ default:
+ nNumberFormat = NumberFormat::TEXT;
+ break;
+ }
+ break;
+ case NumberFormat::CURRENCY:
+ switch(_nOldNumberFormat)
+ {
+ case NumberFormat::NUMBER:
+ nNumberFormat = NumberFormat::CURRENCY;
+ break;
+ case NumberFormat::CURRENCY:
+ nNumberFormat = _nOldNumberFormat;
+ break;
+ case NumberFormat::ALL:
+ nNumberFormat = NumberFormat::CURRENCY;
+ break;
+ default:
+ nNumberFormat = NumberFormat::TEXT;
+ break;
+ }
+ break;
+ case NumberFormat::NUMBER:
+ case NumberFormat::SCIENTIFIC:
+ case NumberFormat::FRACTION:
+ case NumberFormat::PERCENT:
+ switch(_nOldNumberFormat)
+ {
+ case NumberFormat::NUMBER:
+ nNumberFormat = _nOldNumberFormat;
+ break;
+ case NumberFormat::CURRENCY:
+ nNumberFormat = NumberFormat::CURRENCY;
+ break;
+ case NumberFormat::ALL:
+ nNumberFormat = nType;
+ break;
+ default:
+ nNumberFormat = NumberFormat::TEXT;
+ break;
+ }
+ break;
+ case NumberFormat::TEXT:
+ case NumberFormat::UNDEFINED:
+ case NumberFormat::LOGICAL:
+ nNumberFormat = NumberFormat::TEXT; // Text overwrites everything
+ break;
+ case NumberFormat::DATETIME:
+ switch(_nOldNumberFormat)
+ {
+ case NumberFormat::DATETIME:
+ case NumberFormat::TEXT:
+ case NumberFormat::TIME:
+ nNumberFormat = _nOldNumberFormat;
+ break;
+ case NumberFormat::ALL:
+ nNumberFormat = NumberFormat::DATETIME;
+ break;
+ default:
+ nNumberFormat = NumberFormat::TEXT;
+ break;
+ }
+ break;
+ default:
+ SAL_WARN("dbaccess.ui", "ODatabaseExport: Unknown NumberFormat");
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ nNumberFormat = NumberFormat::TEXT; // Text overwrites everything
+ }
+
+ return nNumberFormat;
+}
+
+void ODatabaseExport::SetColumnTypes(const TColumnVector* _pList,const OTypeInfoMap* _pInfoMap)
+{
+ if(!(_pList && _pInfoMap))
+ return;
+
+ OSL_ENSURE(m_vNumberFormat.size() == m_vColumnSize.size() && m_vColumnSize.size() == _pList->size(),"Illegal columns in list");
+ Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier();
+ Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats();
+ sal_Int32 minBothSize = std::min<sal_Int32>(m_vNumberFormat.size(), m_vColumnSize.size());
+ sal_Int32 i = 0;
+ for (auto const& elem : *_pList)
+ {
+ if (i >= minBothSize)
+ break;
+
+ sal_Int32 nDataType;
+ sal_Int32 nLength(0),nScale(0);
+ sal_Int16 nType = m_vNumberFormat[i] & ~NumberFormat::DEFINED;
+
+ switch ( nType )
+ {
+ case NumberFormat::ALL:
+ nDataType = DataType::DOUBLE;
+ break;
+ case NumberFormat::DEFINED:
+ nDataType = DataType::VARCHAR;
+ nLength = ((m_vColumnSize[i] % 10 ) ? m_vColumnSize[i]/ 10 + 1: m_vColumnSize[i]/ 10) * 10;
+ break;
+ case NumberFormat::DATE:
+ nDataType = DataType::DATE;
+ break;
+ case NumberFormat::TIME:
+ nDataType = DataType::TIME;
+ break;
+ case NumberFormat::DATETIME:
+ nDataType = DataType::TIMESTAMP;
+ break;
+ case NumberFormat::CURRENCY:
+ nDataType = DataType::NUMERIC;
+ nScale = 4;
+ nLength = 19;
+ break;
+ case NumberFormat::NUMBER:
+ case NumberFormat::SCIENTIFIC:
+ case NumberFormat::FRACTION:
+ case NumberFormat::PERCENT:
+ nDataType = DataType::DOUBLE;
+ break;
+ case NumberFormat::TEXT:
+ case NumberFormat::UNDEFINED:
+ case NumberFormat::LOGICAL:
+ default:
+ nDataType = DataType::VARCHAR;
+ nLength = ((m_vColumnSize[i] % 10 ) ? m_vColumnSize[i]/ 10 + 1: m_vColumnSize[i]/ 10) * 10;
+ break;
+ }
+ OTypeInfoMap::const_iterator aFind = _pInfoMap->find(nDataType);
+ if(aFind != _pInfoMap->end())
+ {
+ elem->second->SetType(aFind->second);
+ elem->second->SetPrecision(std::min<sal_Int32>(aFind->second->nPrecision,nLength));
+ elem->second->SetScale(std::min<sal_Int32>(aFind->second->nMaximumScale,nScale));
+
+ sal_Int32 nFormatKey = ::dbtools::getDefaultNumberFormat( nDataType,
+ elem->second->GetScale(),
+ elem->second->IsCurrency(),
+ Reference< XNumberFormatTypes>(xFormats,UNO_QUERY),
+ m_aLocale);
+
+ elem->second->SetFormatKey(nFormatKey);
+ }
+ ++i;
+ }
+}
+
+void ODatabaseExport::CreateDefaultColumn(const OUString& _rColumnName)
+{
+ Reference< XDatabaseMetaData> xDestMetaData(m_xConnection->getMetaData());
+ sal_Int32 nMaxNameLen(xDestMetaData->getMaxColumnNameLength());
+ OUString aAlias = _rColumnName;
+ if ( isSQL92CheckEnabled(m_xConnection) )
+ aAlias = ::dbtools::convertName2SQLName(_rColumnName,xDestMetaData->getExtraNameCharacters());
+
+ if(nMaxNameLen && aAlias.getLength() > nMaxNameLen)
+ aAlias = aAlias.copy(0, std::min<sal_Int32>( nMaxNameLen-1, aAlias.getLength() ) );
+
+ OUString sName(aAlias);
+ if(m_aDestColumns.find(sName) != m_aDestColumns.end())
+ {
+ sal_Int32 nPos = 0;
+ sal_Int32 nCount = 2;
+ while(m_aDestColumns.find(sName) != m_aDestColumns.end())
+ {
+ sName = aAlias
+ + OUString::number(++nPos);
+ if(nMaxNameLen && sName.getLength() > nMaxNameLen)
+ {
+ aAlias = aAlias.copy(0,std::min<sal_Int32>( nMaxNameLen-nCount, aAlias.getLength() ));
+ sName = aAlias
+ + OUString::number(nPos);
+ ++nCount;
+ }
+ }
+ }
+ aAlias = sName;
+ // now create a column
+ OFieldDescription* pField = new OFieldDescription();
+ pField->SetType(m_pTypeInfo);
+ pField->SetName(aAlias);
+ pField->SetPrecision(std::min<sal_Int32>(sal_Int32(255),m_pTypeInfo->nPrecision));
+ pField->SetScale(0);
+ pField->SetIsNullable(ColumnValue::NULLABLE);
+ pField->SetAutoIncrement(false);
+ pField->SetPrimaryKey(false);
+ pField->SetCurrency(false);
+
+ TColumns::const_iterator aFind = m_aDestColumns.find( aAlias );
+ if ( aFind != m_aDestColumns.end() )
+ {
+ delete aFind->second;
+ m_aDestColumns.erase(aFind);
+ }
+
+ m_vDestVector.emplace_back(m_aDestColumns.emplace(aAlias,pField).first);
+}
+
+void ODatabaseExport::createRowSet()
+{
+ m_pUpdateHelper = std::make_shared<OParameterUpdateHelper>(createPreparedStatment(m_xConnection->getMetaData(),m_xTable,m_vColumnPositions));
+}
+
+bool ODatabaseExport::executeWizard(const OUString& _rTableName, const Any& _aTextColor, const FontDescriptor& _rFont)
+{
+ bool bHaveDefaultTable = !m_sDefaultTableName.isEmpty();
+ OUString sTableName( bHaveDefaultTable ? m_sDefaultTableName : _rTableName );
+ OCopyTableWizard aWizard(
+ nullptr,
+ sTableName,
+ bHaveDefaultTable ? CopyTableOperation::AppendData : CopyTableOperation::CopyDefinitionAndData,
+ ODatabaseExport::TColumns(m_aDestColumns),
+ m_vDestVector,
+ m_xConnection,
+ m_xFormatter,
+ getTypeSelectionPageFactory(),
+ m_rInputStream,
+ m_xContext
+ );
+
+ bool bError = false;
+ try
+ {
+ if (aWizard.run())
+ {
+ switch(aWizard.getOperation())
+ {
+ case CopyTableOperation::CopyDefinitionAndData:
+ case CopyTableOperation::AppendData:
+ {
+ m_xTable = aWizard.returnTable();
+ bError = !m_xTable.is();
+ if(m_xTable.is())
+ {
+ m_xTable->setPropertyValue(PROPERTY_FONT,Any(_rFont));
+ if(_aTextColor.hasValue())
+ m_xTable->setPropertyValue(PROPERTY_TEXTCOLOR,_aTextColor);
+ }
+ m_bIsAutoIncrement = aWizard.shouldCreatePrimaryKey();
+ m_vColumnPositions = aWizard.GetColumnPositions();
+ m_vColumnTypes = aWizard.GetColumnTypes();
+ m_bAppendFirstLine = !aWizard.UseHeaderLine();
+ }
+ break;
+ default:
+ bError = true; // there is no error but I have nothing more to do
+ }
+ }
+ else
+ bError = true;
+
+ if(!bError)
+ createRowSet();
+ }
+ catch( const SQLException&)
+ {
+ ::dbtools::showError( ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ), aWizard.getDialog()->GetXWindow(), m_xContext );
+ bError = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return bError;
+}
+
+void ODatabaseExport::showErrorDialog(const css::sdbc::SQLException& e)
+{
+ if(!m_bDontAskAgain)
+ {
+ OUString aMsg = e.Message
+ + "\n"
+ + DBA_RES( STR_QRY_CONTINUE );
+ OSQLWarningBox aBox(nullptr, aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultNo);
+
+ if (aBox.run() == RET_YES)
+ m_bDontAskAgain = true;
+ else
+ m_bError = true;
+ }
+}
+
+void ODatabaseExport::adjustFormat()
+{
+ if ( m_sTextToken.isEmpty() )
+ return;
+
+ sal_Int32 nNewPos = m_bIsAutoIncrement ? m_nColumnPos+1 : m_nColumnPos;
+ OSL_ENSURE(nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()),"Illegal index for vector");
+ if ( nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()) )
+ {
+ sal_Int32 nColPos = m_vColumnPositions[nNewPos].first;
+ if( nColPos != COLUMN_POSITION_NOT_FOUND)
+ {
+ --nColPos;
+ OSL_ENSURE((nColPos) < static_cast<sal_Int32>(m_vNumberFormat.size()),"m_vFormatKey: Illegal index for vector");
+ OSL_ENSURE((nColPos) < static_cast<sal_Int32>(m_vColumnSize.size()),"m_vColumnSize: Illegal index for vector");
+ m_vNumberFormat[nColPos] = CheckString(m_sTextToken,m_vNumberFormat[nColPos]);
+ m_vColumnSize[nColPos] = std::max<sal_Int32>(static_cast<sal_Int32>(m_vColumnSize[nColPos]), m_sTextToken.getLength());
+ }
+ }
+ eraseTokens();
+}
+
+void ODatabaseExport::eraseTokens()
+{
+ m_sTextToken.clear();
+ m_sNumToken.clear();
+}
+
+void ODatabaseExport::ensureFormatter()
+{
+ if ( !m_pFormatter )
+ {
+ Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier();
+ auto pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xSupplier);
+ m_pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr;
+ Reference<XPropertySet> xNumberFormatSettings = xSupplier->getNumberFormatSettings();
+ xNumberFormatSettings->getPropertyValue("NullDate") >>= m_aNullDate;
+ }
+}
+
+Reference< XPreparedStatement > ODatabaseExport::createPreparedStatment( const Reference<XDatabaseMetaData>& _xMetaData
+ ,const Reference<XPropertySet>& _xDestTable
+ ,const TPositions& _rvColumns)
+{
+ OUString sComposedTableName = ::dbtools::composeTableName( _xMetaData, _xDestTable, ::dbtools::EComposeRule::InDataManipulation, true );
+
+ OUStringBuffer aSql = "INSERT INTO "
+ + sComposedTableName
+ + " ( ";
+
+ // set values and column names
+ OUStringBuffer aValues(" VALUES ( ");
+
+ OUString aQuote;
+ if ( _xMetaData.is() )
+ aQuote = _xMetaData->getIdentifierQuoteString();
+
+ Reference<XColumnsSupplier> xDestColsSup(_xDestTable,UNO_QUERY_THROW);
+
+ // create sql string and set column types
+ Sequence< OUString> aDestColumnNames = xDestColsSup->getColumns()->getElementNames();
+ if ( !aDestColumnNames.hasElements() )
+ {
+ return Reference< XPreparedStatement > ();
+ }
+ const OUString* pIter = aDestColumnNames.getConstArray();
+ std::vector< OUString> aInsertList;
+ aInsertList.resize(aDestColumnNames.getLength()+1);
+ for(size_t j=0; j < aInsertList.size(); ++j)
+ {
+ ODatabaseExport::TPositions::const_iterator aFind = std::find_if(_rvColumns.begin(),_rvColumns.end(),
+ [j] (const ODatabaseExport::TPositions::value_type& tPos)
+ { return tPos.second == static_cast<sal_Int32>(j+1); });
+ if ( _rvColumns.end() != aFind && aFind->second != COLUMN_POSITION_NOT_FOUND && aFind->first != COLUMN_POSITION_NOT_FOUND )
+ {
+ OSL_ENSURE((aFind->first) < static_cast<sal_Int32>(aInsertList.size()),"aInsertList: Illegal index for vector");
+ aInsertList[aFind->first] = ::dbtools::quoteName( aQuote,*(pIter+j));
+ }
+ }
+
+ // create the sql string
+ for (auto const& elem : aInsertList)
+ {
+ if ( !elem.isEmpty() )
+ {
+ aSql.append(elem);
+ aSql.append(",");
+ aValues.append("?,");
+ }
+ }
+
+ aSql[aSql.getLength()-1] = ')';
+ aValues[aValues.getLength()-1] = ')';
+
+ aSql.append(aValues);
+ // now create,fill and execute the prepared statement
+ return _xMetaData->getConnection()->prepareStatement(aSql.makeStringAndClear());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/HtmlReader.cxx b/dbaccess/source/ui/misc/HtmlReader.cxx
new file mode 100644
index 000000000..c2917a630
--- /dev/null
+++ b/dbaccess/source/ui/misc/HtmlReader.cxx
@@ -0,0 +1,481 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <HtmlReader.hxx>
+#include <connectivity/dbtools.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/stream.hxx>
+#include <tools/tenccvt.hxx>
+#include <comphelper/string.hxx>
+#include <strings.hrc>
+#include <osl/diagnose.h>
+#include <core_resource.hxx>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <svtools/htmltokn.h>
+#include <svtools/htmlkywd.hxx>
+#include <tools/color.hxx>
+#include <WExtendPages.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::awt;
+
+#define DBAUI_HTML_FONTSIZES 8 // like export, HTML-Options
+
+// OHTMLReader
+OHTMLReader::OHTMLReader(SvStream& rIn,const SharedConnection& _rxConnection,
+ const Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext)
+ : HTMLParser(rIn)
+ , ODatabaseExport( _rxConnection, _rxNumberF, _rxContext, rIn )
+ , m_nTableCount(0)
+ , m_nColumnWidth(87)
+{
+ SetSrcEncoding( GetExtendedCompatibilityTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
+ // If the file starts with a BOM, switch to UCS2.
+ SetSwitchToUCS2( true );
+}
+
+OHTMLReader::OHTMLReader(SvStream& rIn,
+ sal_Int32 nRows,
+ TPositions&& _rColumnPositions,
+ const Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const TColumnVector* pList,
+ const OTypeInfoMap* _pInfoMap,
+ bool _bAutoIncrementEnabled)
+ : HTMLParser(rIn)
+ , ODatabaseExport( nRows, std::move(_rColumnPositions), _rxNumberF, _rxContext, pList, _pInfoMap, _bAutoIncrementEnabled, rIn )
+ , m_nTableCount(0)
+ , m_nColumnWidth(87)
+{
+ SetSrcEncoding( GetExtendedCompatibilityTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
+ // If the file starts with a BOM, switch to UCS2.
+ SetSwitchToUCS2( true );
+}
+
+OHTMLReader::~OHTMLReader()
+{
+}
+
+SvParserState OHTMLReader::CallParser()
+{
+ rInput.Seek(STREAM_SEEK_TO_BEGIN);
+ rInput.ResetError();
+ SvParserState eParseState = HTMLParser::CallParser();
+ SetColumnTypes(m_pColumnList,m_pInfoMap);
+ return m_bFoundTable ? eParseState : SvParserState::Error;
+}
+
+#if defined _MSC_VER
+#pragma warning(disable: 4702) // unreachable code, bug in MSVC2015
+#endif
+void OHTMLReader::NextToken( HtmlTokenId nToken )
+{
+ if(m_bError || !m_nRows) // if there is an error or no more rows to check, return immediately
+ return;
+ if ( nToken == HtmlTokenId::META )
+ setTextEncoding();
+
+ if(m_xConnection.is()) // names, which CTOR was called and hence, if a table should be created
+ {
+ switch(nToken)
+ {
+ case HtmlTokenId::TABLE_ON:
+ ++m_nTableCount;
+ { // can also be TD or TH, if there was no TABLE before
+ const HTMLOptions& rHtmlOptions = GetOptions();
+ for (const auto & rOption : rHtmlOptions)
+ {
+ if( rOption.GetToken() == HtmlOptionId::WIDTH )
+ { // percentage: of document width respectively outer cell
+ m_nColumnWidth = GetWidthPixel( rOption );
+ }
+ }
+ }
+ [[fallthrough]];
+ case HtmlTokenId::THEAD_ON:
+ case HtmlTokenId::TBODY_ON:
+ {
+ sal_uInt64 const nTell = rInput.Tell(); // perhaps alters position of the stream
+ if ( !m_xTable.is() )
+ {// use first line as header
+ m_bError = !CreateTable(nToken);
+ if ( m_bAppendFirstLine )
+ rInput.Seek(nTell);
+ }
+ }
+ break;
+ case HtmlTokenId::TABLE_OFF:
+ if(!--m_nTableCount)
+ {
+ m_xTable = nullptr;
+ }
+ break;
+ case HtmlTokenId::TABLEROW_ON:
+ if ( !m_pUpdateHelper )
+ m_bError = true;
+ break;
+ case HtmlTokenId::TEXTTOKEN:
+ case HtmlTokenId::SINGLECHAR:
+ if ( m_bInTbl ) //&& !m_bSDNum ) // important, as otherwise we also get the names of the fonts
+ m_sTextToken += aToken;
+ break;
+ case HtmlTokenId::PARABREAK_OFF:
+ m_sCurrent += m_sTextToken;
+ break;
+ case HtmlTokenId::PARABREAK_ON:
+ m_sTextToken.clear();
+ break;
+ case HtmlTokenId::TABLEDATA_ON:
+ fetchOptions();
+ break;
+ case HtmlTokenId::TABLEDATA_OFF:
+ {
+ if ( !m_sCurrent.isEmpty() )
+ m_sTextToken = m_sCurrent;
+ try
+ {
+ insertValueIntoColumn();
+ }
+ catch(SQLException& e)
+ // handling update failure
+ {
+ showErrorDialog(e);
+ }
+ m_sCurrent.clear();
+ m_nColumnPos++;
+ eraseTokens();
+ m_bInTbl = false;
+ }
+ break;
+ case HtmlTokenId::TABLEROW_OFF:
+ if ( !m_pUpdateHelper )
+ {
+ m_bError = true;
+ break;
+ }
+ try
+ {
+ m_nRowCount++;
+ if (m_bIsAutoIncrement) // if bSetAutoIncrement then I have to set the autoincrement
+ m_pUpdateHelper->updateInt(1,m_nRowCount);
+ m_pUpdateHelper->insertRow();
+ }
+ catch(SQLException& e)
+ // handling update failure
+ {
+ showErrorDialog(e);
+ }
+ m_nColumnPos = 0;
+ break;
+ default: break;
+ }
+ }
+ else // branch only valid for type checking
+ {
+ switch(nToken)
+ {
+ case HtmlTokenId::THEAD_ON:
+ case HtmlTokenId::TBODY_ON:
+ // The head of the column is not included
+ if(m_bHead)
+ {
+ do
+ {}
+ while(GetNextToken() != HtmlTokenId::TABLEROW_OFF);
+ m_bHead = false;
+ }
+ break;
+ case HtmlTokenId::TABLEDATA_ON:
+ case HtmlTokenId::TABLEHEADER_ON:
+ fetchOptions();
+ break;
+ case HtmlTokenId::TEXTTOKEN:
+ case HtmlTokenId::SINGLECHAR:
+ if ( m_bInTbl ) // && !m_bSDNum ) // important, as otherwise we also get the names of the fonts
+ m_sTextToken += aToken;
+ break;
+ case HtmlTokenId::PARABREAK_OFF:
+ m_sCurrent += m_sTextToken;
+ break;
+ case HtmlTokenId::PARABREAK_ON:
+ m_sTextToken.clear();
+ break;
+ case HtmlTokenId::TABLEDATA_OFF:
+ if ( !m_sCurrent.isEmpty() )
+ m_sTextToken = m_sCurrent;
+ adjustFormat();
+ m_nColumnPos++;
+ m_bInTbl = false;
+ m_sCurrent.clear();
+ break;
+ case HtmlTokenId::TABLEROW_OFF:
+ if ( !m_sCurrent.isEmpty() )
+ m_sTextToken = m_sCurrent;
+ adjustFormat();
+ m_nColumnPos = 0;
+ m_nRows--;
+ m_sCurrent.clear();
+ break;
+ default: break;
+ }
+ }
+}
+
+void OHTMLReader::fetchOptions()
+{
+ m_bInTbl = true;
+ const HTMLOptions& options = GetOptions();
+ for (const auto & rOption : options)
+ {
+ switch( rOption.GetToken() )
+ {
+ case HtmlOptionId::SDNUM:
+ m_sNumToken = rOption.GetString();
+ break;
+ default: break;
+ }
+ }
+}
+
+void OHTMLReader::TableDataOn(SvxCellHorJustify& eVal)
+{
+ const HTMLOptions& rHtmlOptions = GetOptions();
+ for (const auto & rOption : rHtmlOptions)
+ {
+ switch( rOption.GetToken() )
+ {
+ case HtmlOptionId::ALIGN:
+ {
+ const OUString& rOptVal = rOption.GetString();
+ if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ))
+ eVal = SvxCellHorJustify::Right;
+ else if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center ))
+ eVal = SvxCellHorJustify::Center;
+ else if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ))
+ eVal = SvxCellHorJustify::Left;
+ else
+ eVal = SvxCellHorJustify::Standard;
+ }
+ break;
+ default: break;
+ }
+ }
+}
+
+void OHTMLReader::TableFontOn(FontDescriptor& _rFont, Color &_rTextColor)
+{
+ const HTMLOptions& rHtmlOptions = GetOptions();
+ for (const auto & rOption : rHtmlOptions)
+ {
+ switch( rOption.GetToken() )
+ {
+ case HtmlOptionId::COLOR:
+ {
+ Color aColor;
+ rOption.GetColor( aColor );
+ _rTextColor = aColor.GetRGBColor();
+ }
+ break;
+ case HtmlOptionId::FACE :
+ {
+ const OUString& rFace = rOption.GetString();
+ OUStringBuffer aFontName;
+ sal_Int32 nPos = 0;
+ while( nPos != -1 )
+ {
+ // list of fonts, VCL: semicolon as separator, HTML: comma
+ std::u16string_view aFName = o3tl::getToken(rFace, 0, ',', nPos );
+ aFName = comphelper::string::strip(aFName, ' ');
+ if( !aFontName.isEmpty() )
+ aFontName.append(";");
+ aFontName.append(aFName);
+ }
+ if ( !aFontName.isEmpty() )
+ _rFont.Name = aFontName.makeStringAndClear();
+ }
+ break;
+ case HtmlOptionId::SIZE :
+ {
+ sal_Int16 nSize = static_cast<sal_Int16>(rOption.GetNumber());
+ if ( nSize == 0 )
+ nSize = 1;
+ else if ( nSize < DBAUI_HTML_FONTSIZES )
+ nSize = DBAUI_HTML_FONTSIZES;
+
+ _rFont.Height = nSize;
+ }
+ break;
+ default: break;
+ }
+ }
+}
+
+sal_Int16 OHTMLReader::GetWidthPixel( const HTMLOption& rOption )
+{
+ const OUString& rOptVal = rOption.GetString();
+ if ( rOptVal.indexOf('%') != -1 )
+ { // percentage
+ OSL_ENSURE( m_nColumnWidth, "WIDTH Option: m_nColumnWidth==0 and Width%" );
+ return static_cast<sal_Int16>((rOption.GetNumber() * m_nColumnWidth) / 100);
+ }
+ else
+ {
+ if ( rOptVal.indexOf('*') != -1 )
+ { // relative to what?!?
+//TODO: collect ColArray of all relevant values and then MakeCol
+ return 0;
+ }
+ else
+ return static_cast<sal_Int16>(rOption.GetNumber()); // pixel
+ }
+}
+
+bool OHTMLReader::CreateTable(HtmlTokenId nToken)
+{
+ OUString aTempName(DBA_RES(STR_TBL_TITLE));
+ aTempName = aTempName.getToken(0,' ');
+ aTempName = ::dbtools::createUniqueName(m_xTables, aTempName);
+
+ bool bCaption = false;
+ bool bTableHeader = false;
+ OUString aColumnName;
+ SvxCellHorJustify eVal;
+
+ OUString aTableName;
+ FontDescriptor aFont = VCLUnoHelper::CreateFontDescriptor(Application::GetSettings().GetStyleSettings().GetAppFont());
+ Color nTextColor;
+ do
+ {
+ switch (nToken)
+ {
+ case HtmlTokenId::TEXTTOKEN:
+ case HtmlTokenId::SINGLECHAR:
+ if(bTableHeader)
+ aColumnName += aToken;
+ if(bCaption)
+ aTableName += aToken;
+ break;
+ case HtmlTokenId::PARABREAK_OFF:
+ m_sCurrent += aColumnName;
+ break;
+ case HtmlTokenId::PARABREAK_ON:
+ m_sTextToken.clear();
+ break;
+ case HtmlTokenId::TABLEDATA_ON:
+ case HtmlTokenId::TABLEHEADER_ON:
+ TableDataOn(eVal);
+ bTableHeader = true;
+ break;
+ case HtmlTokenId::TABLEDATA_OFF:
+ case HtmlTokenId::TABLEHEADER_OFF:
+ {
+ aColumnName = comphelper::string::strip(aColumnName, ' ' );
+ if (aColumnName.isEmpty() || m_bAppendFirstLine )
+ aColumnName = DBA_RES(STR_COLUMN_NAME);
+ else if ( !m_sCurrent.isEmpty() )
+ aColumnName = m_sCurrent;
+
+ aColumnName = comphelper::string::strip(aColumnName, ' ');
+ CreateDefaultColumn(aColumnName);
+ aColumnName.clear();
+ m_sCurrent.clear();
+
+ eVal = SvxCellHorJustify::Standard;
+ bTableHeader = false;
+ }
+ break;
+
+ case HtmlTokenId::TITLE_ON:
+ case HtmlTokenId::CAPTION_ON:
+ bCaption = true;
+ break;
+ case HtmlTokenId::TITLE_OFF:
+ case HtmlTokenId::CAPTION_OFF:
+ aTableName = comphelper::string::strip(aTableName, ' ');
+ if(aTableName.isEmpty())
+ aTableName = ::dbtools::createUniqueName(m_xTables, aTableName);
+ else
+ aTableName = aTempName;
+ bCaption = false;
+ break;
+ case HtmlTokenId::FONT_ON:
+ TableFontOn(aFont,nTextColor);
+ break;
+ case HtmlTokenId::BOLD_ON:
+ aFont.Weight = css::awt::FontWeight::BOLD;
+ break;
+ case HtmlTokenId::ITALIC_ON:
+ aFont.Slant = css::awt::FontSlant_ITALIC;
+ break;
+ case HtmlTokenId::UNDERLINE_ON:
+ aFont.Underline = css::awt::FontUnderline::SINGLE;
+ break;
+ case HtmlTokenId::STRIKE_ON:
+ aFont.Strikeout = css::awt::FontStrikeout::SINGLE;
+ break;
+ default: break;
+ }
+ nToken = GetNextToken();
+ }
+ while (nToken != HtmlTokenId::TABLEROW_OFF);
+
+ if ( !m_sCurrent.isEmpty() )
+ aColumnName = m_sCurrent;
+ aColumnName = comphelper::string::strip(aColumnName, ' ');
+ if(!aColumnName.isEmpty())
+ CreateDefaultColumn(aColumnName);
+
+ if ( m_vDestVector.empty() )
+ return false;
+
+ if(aTableName.isEmpty())
+ aTableName = aTempName;
+
+ m_bInTbl = false;
+ m_bFoundTable = true;
+
+ if ( isCheckEnabled() )
+ return true;
+
+ return !executeWizard(aTableName,Any(nTextColor),aFont) && m_xTable.is();
+}
+
+void OHTMLReader::setTextEncoding()
+{
+ ParseMetaOptions(nullptr, nullptr);
+}
+
+TypeSelectionPageFactory OHTMLReader::getTypeSelectionPageFactory()
+{
+ return &OWizHTMLExtend::Create;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/RowSetDrop.cxx b/dbaccess/source/ui/misc/RowSetDrop.cxx
new file mode 100644
index 000000000..065fee9ce
--- /dev/null
+++ b/dbaccess/source/ui/misc/RowSetDrop.cxx
@@ -0,0 +1,247 @@
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DExport.hxx>
+#include <TokenWriter.hxx>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <sqlmessage.hxx>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::lang;
+
+// export data
+ORowSetImportExport::ORowSetImportExport(weld::Window* pParent,
+ const Reference< XResultSetUpdate >& xResultSetUpdate,
+ const svx::ODataAccessDescriptor& aDataDescriptor,
+ const Reference< XComponentContext >& rM)
+ : ODatabaseImportExport(aDataDescriptor,rM,nullptr)
+ ,m_xTargetResultSetUpdate(xResultSetUpdate)
+ ,m_xTargetRowUpdate(xResultSetUpdate,UNO_QUERY)
+ ,m_pParent(pParent)
+ ,m_bAlreadyAsked(false)
+{
+ OSL_ENSURE(pParent,"Window can't be null!");
+}
+
+void ORowSetImportExport::initialize()
+{
+ ODatabaseImportExport::initialize();
+ // do namemapping
+ Reference<XColumnLocate> xColumnLocate(m_xResultSet,UNO_QUERY);
+ OSL_ENSURE(xColumnLocate.is(),"The rowset normally should support this");
+
+ m_xTargetResultSetMetaData = Reference<XResultSetMetaDataSupplier>(m_xTargetResultSetUpdate,UNO_QUERY_THROW)->getMetaData();
+ if(!m_xTargetResultSetMetaData.is() || !xColumnLocate.is() || !m_xResultSetMetaData.is() )
+ throw SQLException(DBA_RES(STR_UNEXPECTED_ERROR),*this,"S1000",0,Any());
+
+ sal_Int32 nCount = m_xTargetResultSetMetaData->getColumnCount();
+ m_aColumnMapping.reserve(nCount);
+ m_aColumnTypes.reserve(nCount);
+ for (sal_Int32 i = 1;i <= nCount; ++i)
+ {
+ sal_Int32 nPos = COLUMN_POSITION_NOT_FOUND; // means column is autoincrement or doesn't exist
+ if(!m_xTargetResultSetMetaData->isAutoIncrement(i))
+ {
+ try
+ {
+ OUString sColumnName = m_xTargetResultSetMetaData->getColumnName(i);
+ nPos = xColumnLocate->findColumn(sColumnName);
+ }
+ catch(const SQLException&)
+ {
+ if(m_xTargetResultSetMetaData->isNullable(i))
+ nPos = 0; // column doesn't exist but we could set it to null
+ }
+ }
+
+ m_aColumnMapping.push_back(nPos);
+ if(nPos > 0)
+ m_aColumnTypes.push_back(m_xResultSetMetaData->getColumnType(nPos));
+ else
+ m_aColumnTypes.push_back(DataType::OTHER);
+ }
+}
+
+bool ORowSetImportExport::Write()
+{
+ return true;
+}
+
+bool ORowSetImportExport::Read()
+{
+ // check if there is any column to copy
+ if(std::none_of(m_aColumnMapping.begin(),m_aColumnMapping.end(),
+ [](sal_Int32 n) { return n > 0; }))
+ return false;
+ bool bContinue = true;
+ if(m_aSelection.hasElements())
+ {
+ const Any* pBegin = m_aSelection.getConstArray();
+ const Any* pEnd = pBegin + m_aSelection.getLength();
+ for(;pBegin != pEnd && bContinue;++pBegin)
+ {
+ sal_Int32 nPos = -1;
+ *pBegin >>= nPos;
+ OSL_ENSURE(nPos != -1,"Invalid position!");
+ bContinue = (m_xResultSet.is() && m_xResultSet->absolute(nPos) && insertNewRow());
+ }
+ }
+ else
+ {
+ Reference<XPropertySet> xProp(m_xResultSet,UNO_QUERY);
+ sal_Int32 nRowCount = 0;
+ if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISROWCOUNTFINAL) )
+ {
+ bool bFinal = false;
+ xProp->getPropertyValue(PROPERTY_ISROWCOUNTFINAL) >>= bFinal;
+ if ( !bFinal )
+ m_xResultSet->afterLast();
+ xProp->getPropertyValue(PROPERTY_ROWCOUNT) >>= nRowCount;
+ }
+ if ( !nRowCount )
+ {
+ m_xResultSet->afterLast();
+ nRowCount = m_xResultSet->getRow();
+ }
+ OSL_ENSURE(nRowCount,"RowCount is 0!");
+ m_xResultSet->beforeFirst();
+ while(m_xResultSet.is() && m_xResultSet->next() && bContinue && nRowCount )
+ {
+ --nRowCount;
+ bContinue = insertNewRow();
+ }
+ }
+ return true;
+}
+
+bool ORowSetImportExport::insertNewRow()
+{
+ try
+ {
+ m_xTargetResultSetUpdate->moveToInsertRow();
+ sal_Int32 i = 1;
+ for (auto const& column : m_aColumnMapping)
+ {
+ if(column > 0)
+ {
+ Any aValue;
+ switch(m_aColumnTypes[i-1])
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ aValue <<= m_xRow->getString(column);
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ aValue <<= m_xRow->getDouble(column);
+ break;
+ case DataType::BIGINT:
+ aValue <<= m_xRow->getLong(column);
+ break;
+ case DataType::FLOAT:
+ aValue <<= m_xRow->getFloat(column);
+ break;
+ case DataType::DOUBLE:
+ aValue <<= m_xRow->getDouble(column);
+ break;
+ case DataType::LONGVARCHAR:
+ aValue <<= m_xRow->getString(column);
+ break;
+ case DataType::LONGVARBINARY:
+ aValue <<= m_xRow->getBytes(column);
+ break;
+ case DataType::DATE:
+ aValue <<= m_xRow->getDate(column);
+ break;
+ case DataType::TIME:
+ aValue <<= m_xRow->getTime(column);
+ break;
+ case DataType::TIMESTAMP:
+ aValue <<= m_xRow->getTimestamp(column);
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ aValue <<= m_xRow->getBoolean(column);
+ break;
+ case DataType::TINYINT:
+ aValue <<= m_xRow->getByte(column);
+ break;
+ case DataType::SMALLINT:
+ aValue <<= m_xRow->getShort(column);
+ break;
+ case DataType::INTEGER:
+ aValue <<= m_xRow->getInt(column);
+ break;
+ case DataType::REAL:
+ aValue <<= m_xRow->getDouble(column);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ aValue <<= m_xRow->getBytes(column);
+ break;
+ case DataType::BLOB:
+ aValue <<= m_xRow->getBlob(column);
+ break;
+ case DataType::CLOB:
+ aValue <<= m_xRow->getClob(column);
+ break;
+ default:
+ SAL_WARN("dbaccess.ui", "Unknown type");
+ }
+ if(m_xRow->wasNull())
+ m_xTargetRowUpdate->updateNull(i);
+ else
+ m_xTargetRowUpdate->updateObject(i,aValue);
+ }
+ else if(column == 0)//now we have know that we to set this column to null
+ m_xTargetRowUpdate->updateNull(i);
+ ++i;
+ }
+ m_xTargetResultSetUpdate->insertRow();
+ }
+ catch(const SQLException&)
+ {
+ if(!m_bAlreadyAsked)
+ {
+ OUString sAskIfContinue = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING);
+ OSQLWarningBox aDlg(m_pParent, sAskIfContinue, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes);
+ if (aDlg.run() == RET_YES)
+ m_bAlreadyAsked = true;
+ else
+ return false;
+ }
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/RtfReader.cxx b/dbaccess/source/ui/misc/RtfReader.cxx
new file mode 100644
index 000000000..8895d494f
--- /dev/null
+++ b/dbaccess/source/ui/misc/RtfReader.cxx
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <RtfReader.hxx>
+#include <tools/stream.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <core_resource.hxx>
+#include <svtools/rtftoken.h>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <strings.hrc>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/string.hxx>
+#include <tools/color.hxx>
+#include <WExtendPages.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::awt;
+
+// ORTFReader
+ORTFReader::ORTFReader( SvStream& rIn,
+ const SharedConnection& _rxConnection,
+ const Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext)
+ :SvRTFParser(rIn)
+ ,ODatabaseExport( _rxConnection, _rxNumberF, _rxContext, rIn )
+{
+ m_bAppendFirstLine = false;
+}
+
+ORTFReader::ORTFReader(SvStream& rIn,
+ sal_Int32 nRows,
+ TPositions&& _rColumnPositions,
+ const Reference< css::util::XNumberFormatter >& _rxNumberF,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ const TColumnVector* pList,
+ const OTypeInfoMap* _pInfoMap,
+ bool _bAutoIncrementEnabled)
+ :SvRTFParser(rIn)
+ ,ODatabaseExport( nRows, std::move(_rColumnPositions), _rxNumberF, _rxContext, pList, _pInfoMap, _bAutoIncrementEnabled, rIn )
+{
+ m_bAppendFirstLine = false;
+}
+
+ORTFReader::~ORTFReader()
+{
+}
+
+SvParserState ORTFReader::CallParser()
+{
+ rInput.Seek(STREAM_SEEK_TO_BEGIN);
+ rInput.ResetError();
+ SvParserState eParseState = SvRTFParser::CallParser();
+ SetColumnTypes(m_pColumnList,m_pInfoMap);
+ return m_bFoundTable ? eParseState : SvParserState::Error;
+}
+
+#if defined _MSC_VER
+#pragma warning(disable: 4702) // unreachable code, bug in MSVC2015
+#endif
+
+void ORTFReader::NextToken( int nToken )
+{
+ if(m_bError || !m_nRows) // if there is an error or no more rows to check, return immediately
+ return;
+
+ if(m_xConnection.is()) // names, which CTOR was called and hence, if a table should be created
+ {
+ switch(nToken)
+ {
+ case RTF_COLORTBL:
+ {
+
+ int nTmpToken2 = GetNextToken();
+ do
+ {
+ Color aColor;
+ do
+ {
+ switch(nTmpToken2)
+ {
+ case RTF_RED: aColor.SetRed(static_cast<sal_uInt8>(nTokenValue)); break;
+ case RTF_BLUE: aColor.SetBlue(static_cast<sal_uInt8>(nTokenValue)); break;
+ case RTF_GREEN: aColor.SetGreen(static_cast<sal_uInt8>(nTokenValue)); break;
+ default: break;
+ }
+ nTmpToken2 = GetNextToken();
+ }
+ while(aToken[0] != ';' && eState != SvParserState::Error && eState != SvParserState::Accepted);
+ m_vecColor.push_back(aColor.GetRGBColor());
+ nTmpToken2 = GetNextToken();
+ }
+ while(nTmpToken2 == RTF_RED && eState != SvParserState::Error && eState != SvParserState::Accepted);
+ SkipToken();
+ }
+ break;
+
+ case RTF_TROWD:
+ {
+ if ( !m_xTable.is() ) // use first line as header
+ {
+ sal_uInt64 const nTell = rInput.Tell(); // perhaps alters position of the stream
+
+ m_bError = !CreateTable(nToken);
+ if ( m_bAppendFirstLine )
+ {
+ rInput.Seek(nTell);
+ rInput.ResetError();
+ }
+ }
+ }
+ break;
+ case RTF_INTBL:
+ if(m_bInTbl)
+ {
+ eraseTokens();
+ }
+
+ m_bInTbl = true; // Now we are in a table description
+ break;
+ case RTF_TEXTTOKEN:
+ case RTF_SINGLECHAR:
+ if(m_bInTbl) // important, as otherwise we also get the names of the fonts
+ m_sTextToken += aToken;
+ break;
+ case RTF_CELL:
+ {
+ try
+ {
+ insertValueIntoColumn();
+ }
+ catch(SQLException& e)
+ // handling update failure
+ {
+ showErrorDialog(e);
+ }
+ m_nColumnPos++;
+ eraseTokens();
+ }
+ break;
+ case RTF_ROW:
+ // it can happen that the last cell is not concluded with \cell
+ try
+ {
+ insertValueIntoColumn();
+ m_nRowCount++;
+ if(m_bIsAutoIncrement) // if bSetAutoIncrement then I have to set the autoincrement
+ m_pUpdateHelper->updateInt(1,m_nRowCount);
+ m_pUpdateHelper->insertRow();
+ }
+ catch(SQLException& e)
+ // handling update failure
+ {
+ showErrorDialog(e);
+ }
+ m_nColumnPos = 0;
+ break;
+ }
+ }
+ else // branch only valid for type checking
+ {
+ switch(nToken)
+ {
+ case RTF_TROWD:
+ // The head of the column is not included
+ if(m_bHead)
+ {
+ do
+ {}
+ while(GetNextToken() != RTF_ROW && eState != SvParserState::Error && eState != SvParserState::Accepted);
+ m_bHead = false;
+ }
+ break;
+ case RTF_INTBL:
+ m_bInTbl = true;
+ break;
+ case RTF_TEXTTOKEN:
+ case RTF_SINGLECHAR:
+ if(m_bInTbl)
+ m_sTextToken += aToken;
+ break;
+ case RTF_CELL:
+ adjustFormat();
+ m_nColumnPos++;
+ break;
+ case RTF_ROW:
+ adjustFormat();
+ m_nColumnPos = 0;
+ m_nRows--;
+ break;
+ }
+ }
+}
+
+bool ORTFReader::CreateTable(int nToken)
+{
+ OUString aTableName(DBA_RES(STR_TBL_TITLE));
+ aTableName = aTableName.getToken(0,' ');
+ aTableName = ::dbtools::createUniqueName(m_xTables, aTableName);
+
+ OUString aColumnName;
+
+ FontDescriptor aFont = VCLUnoHelper::CreateFontDescriptor(Application::GetSettings().GetStyleSettings().GetAppFont());
+ do
+ {
+ switch (nToken)
+ {
+ case RTF_UNKNOWNCONTROL:
+ case RTF_UNKNOWNDATA:
+ m_bInTbl = false;
+ aColumnName.clear();
+ break;
+ case RTF_INTBL:
+ if(m_bInTbl)
+ aColumnName.clear();
+
+ m_bInTbl = true;
+ break;
+ case RTF_TEXTTOKEN:
+ case RTF_SINGLECHAR:
+ if(m_bInTbl)
+ aColumnName += aToken;
+ break;
+ case RTF_CELL:
+ {
+ aColumnName = comphelper::string::strip(aColumnName, ' ');
+ if (aColumnName.isEmpty() || m_bAppendFirstLine )
+ aColumnName = DBA_RES(STR_COLUMN_NAME);
+
+ CreateDefaultColumn(aColumnName);
+ aColumnName.clear();
+ }
+ break;
+ case RTF_CF:
+ break;
+ case RTF_B:
+ aFont.Weight = css::awt::FontWeight::BOLD;
+ break;
+ case RTF_I:
+ aFont.Slant = css::awt::FontSlant_ITALIC;
+ break;
+ case RTF_UL:
+ aFont.Underline = css::awt::FontUnderline::SINGLE;
+ break;
+ case RTF_STRIKE:
+ aFont.Strikeout = css::awt::FontStrikeout::SINGLE;
+ break;
+ }
+ nToken = GetNextToken();
+ }
+ while(nToken != RTF_TROWD && eState != SvParserState::Error && eState != SvParserState::Accepted);
+
+ bool bOk = !m_vDestVector.empty();
+ if(bOk)
+ {
+ if ( !aColumnName.isEmpty() )
+ {
+ if ( m_bAppendFirstLine )
+ aColumnName = DBA_RES(STR_COLUMN_NAME);
+ CreateDefaultColumn(aColumnName);
+ }
+
+ m_bInTbl = false;
+ m_bFoundTable = true;
+
+ if ( isCheckEnabled() )
+ return true;
+ Any aTextColor;
+ if(!m_vecColor.empty())
+ aTextColor <<= m_vecColor[0];
+
+ bOk = !executeWizard(aTableName,aTextColor,aFont) && m_xTable.is();
+ }
+ return bOk;
+}
+
+TypeSelectionPageFactory ORTFReader::getTypeSelectionPageFactory()
+{
+ return &OWizRTFExtend::Create;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/TableCopyHelper.cxx b/dbaccess/source/ui/misc/TableCopyHelper.cxx
new file mode 100644
index 000000000..c855b3b48
--- /dev/null
+++ b/dbaccess/source/ui/misc/TableCopyHelper.cxx
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableCopyHelper.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <dbaccess/genericcontroller.hxx>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
+#include <com/sun/star/sdb/application/CopyTableWizard.hpp>
+#include <com/sun/star/sdb/DataAccessDescriptorFactory.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+
+#include <TokenWriter.hxx>
+#include <UITools.hxx>
+#include <dbaccess/dataview.hxx>
+#include <svx/dbaexchange.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <unotools/tempfile.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::svx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdb::application;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::ucb;
+
+OTableCopyHelper::OTableCopyHelper(OGenericUnoController* _pController)
+ :m_pController(_pController)
+{
+}
+
+void OTableCopyHelper::insertTable( std::u16string_view i_rSourceDataSource, const Reference<XConnection>& i_rSourceConnection,
+ const OUString& i_rCommand, const sal_Int32 i_nCommandType,
+ const Reference< XResultSet >& i_rSourceRows, const Sequence< Any >& i_rSelection, const bool i_bBookmarkSelection,
+ std::u16string_view i_rDestDataSource, const Reference<XConnection>& i_rDestConnection)
+{
+ if ( CommandType::QUERY != i_nCommandType && CommandType::TABLE != i_nCommandType )
+ {
+ SAL_WARN("dbaccess.ui", "OTableCopyHelper::insertTable: invalid call (no supported format found)!" );
+ return;
+ }
+
+ try
+ {
+ Reference<XConnection> xSrcConnection( i_rSourceConnection );
+ if ( i_rSourceDataSource == i_rDestDataSource )
+ xSrcConnection = i_rDestConnection;
+
+ if ( !xSrcConnection.is() || !i_rDestConnection.is() )
+ {
+ SAL_WARN("dbaccess.ui", "OTableCopyHelper::insertTable: no connection/s!" );
+ return;
+ }
+
+ Reference<XComponentContext> aContext( m_pController->getORB() );
+
+ Reference< XDataAccessDescriptorFactory > xFactory( DataAccessDescriptorFactory::get( aContext ) );
+
+ Reference< XPropertySet > xSource( xFactory->createDataAccessDescriptor(), UNO_SET_THROW );
+ xSource->setPropertyValue( PROPERTY_COMMAND_TYPE, Any( i_nCommandType ) );
+ xSource->setPropertyValue( PROPERTY_COMMAND, Any( i_rCommand ) );
+ xSource->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( xSrcConnection ) );
+ xSource->setPropertyValue( PROPERTY_RESULT_SET, Any( i_rSourceRows ) );
+ xSource->setPropertyValue( PROPERTY_SELECTION, Any( i_rSelection ) );
+ xSource->setPropertyValue( PROPERTY_BOOKMARK_SELECTION, Any( i_bBookmarkSelection ) );
+
+ Reference< XPropertySet > xDest( xFactory->createDataAccessDescriptor(), UNO_SET_THROW );
+ xDest->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( i_rDestConnection ) );
+
+ auto xInteractionHandler = InteractionHandler::createWithParent(aContext, VCLUnoHelper::GetInterface(m_pController->getView()));
+
+ Reference<XCopyTableWizard> xWizard(CopyTableWizard::createWithInteractionHandler(aContext, xSource, xDest, xInteractionHandler), UNO_SET_THROW);
+
+ OUString sTableNameForAppend( GetTableNameForAppend() );
+ xWizard->setDestinationTableName( GetTableNameForAppend() );
+
+ bool bAppendToExisting = !sTableNameForAppend.isEmpty();
+ xWizard->setOperation( bAppendToExisting ? CopyTableOperation::AppendData : CopyTableOperation::CopyDefinitionAndData );
+
+ xWizard->execute();
+ }
+ catch( const SQLException& )
+ {
+ m_pController->showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OTableCopyHelper::pasteTable( const svx::ODataAccessDescriptor& _rPasteData, std::u16string_view i_rDestDataSourceName,
+ const SharedConnection& i_rDestConnection )
+{
+ OUString sSrcDataSourceName = _rPasteData.getDataSource();
+
+ OUString sCommand;
+ _rPasteData[ DataAccessDescriptorProperty::Command ] >>= sCommand;
+
+ Reference<XConnection> xSrcConnection;
+ if ( _rPasteData.has(DataAccessDescriptorProperty::Connection) )
+ {
+ OSL_VERIFY( _rPasteData[DataAccessDescriptorProperty::Connection] >>= xSrcConnection );
+ }
+
+ Reference< XResultSet > xResultSet;
+ if ( _rPasteData.has(DataAccessDescriptorProperty::Cursor) )
+ {
+ OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::Cursor ] >>= xResultSet );
+ }
+
+ Sequence< Any > aSelection;
+ if ( _rPasteData.has( DataAccessDescriptorProperty::Selection ) )
+ {
+ OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::Selection ] >>= aSelection );
+ OSL_ENSURE( _rPasteData.has( DataAccessDescriptorProperty::BookmarkSelection ), "OTableCopyHelper::pasteTable: you should specify BookmarkSelection, too, to be on the safe side!" );
+ }
+
+ bool bBookmarkSelection( true );
+ if ( _rPasteData.has( DataAccessDescriptorProperty::BookmarkSelection ) )
+ {
+ OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::BookmarkSelection ] >>= bBookmarkSelection );
+ }
+ OSL_ENSURE( bBookmarkSelection, "OTableCopyHelper::pasteTable: working with selection-indices (instead of bookmarks) is error-prone, and thus deprecated!" );
+
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ if ( _rPasteData.has(DataAccessDescriptorProperty::CommandType) )
+ _rPasteData[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
+
+ insertTable( sSrcDataSourceName, xSrcConnection, sCommand, nCommandType,
+ xResultSet, aSelection, bBookmarkSelection,
+ i_rDestDataSourceName, i_rDestConnection );
+}
+
+void OTableCopyHelper::pasteTable( SotClipboardFormatId _nFormatId
+ ,const TransferableDataHelper& _rTransData
+ ,std::u16string_view i_rDestDataSource
+ ,const SharedConnection& _xConnection)
+{
+ if ( _nFormatId == SotClipboardFormatId::DBACCESS_TABLE || _nFormatId == SotClipboardFormatId::DBACCESS_QUERY )
+ {
+ if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(_rTransData.GetDataFlavorExVector()) )
+ {
+ svx::ODataAccessDescriptor aPasteData = ODataAccessObjectTransferable::extractObjectDescriptor(_rTransData);
+ pasteTable( aPasteData,i_rDestDataSource,_xConnection);
+ }
+ }
+ else if ( _rTransData.HasFormat(_nFormatId) )
+ {
+ try
+ {
+ DropDescriptor aTrans;
+ bool bOk;
+ if ( _nFormatId != SotClipboardFormatId::RTF )
+ bOk = _rTransData.GetSotStorageStream(SotClipboardFormatId::HTML ,aTrans.aHtmlRtfStorage);
+ else
+ bOk = _rTransData.GetSotStorageStream(SotClipboardFormatId::RTF,aTrans.aHtmlRtfStorage);
+
+ aTrans.nType = E_TABLE;
+ aTrans.bHtml = SotClipboardFormatId::HTML == _nFormatId;
+ aTrans.sDefaultTableName = GetTableNameForAppend();
+ if ( !bOk || !copyTagTable(aTrans,false,_xConnection) )
+ m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any()));
+ }
+ catch(const SQLException&)
+ {
+ m_pController->showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ else
+ m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any()));
+}
+
+void OTableCopyHelper::pasteTable( const TransferableDataHelper& _rTransData
+ ,std::u16string_view i_rDestDataSource
+ ,const SharedConnection& _xConnection)
+{
+ if ( _rTransData.HasFormat(SotClipboardFormatId::DBACCESS_TABLE) || _rTransData.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) )
+ pasteTable( SotClipboardFormatId::DBACCESS_TABLE,_rTransData,i_rDestDataSource,_xConnection);
+ else if ( _rTransData.HasFormat(SotClipboardFormatId::HTML) )
+ pasteTable( SotClipboardFormatId::HTML,_rTransData,i_rDestDataSource,_xConnection);
+ else if ( _rTransData.HasFormat(SotClipboardFormatId::RTF) )
+ pasteTable( SotClipboardFormatId::RTF,_rTransData,i_rDestDataSource,_xConnection);
+}
+
+bool OTableCopyHelper::copyTagTable(OTableCopyHelper::DropDescriptor const & _rDesc, bool _bCheck, const SharedConnection& _xConnection)
+{
+ rtl::Reference<ODatabaseImportExport> pImport;
+ if ( _rDesc.bHtml )
+ pImport = new OHTMLImportExport(_xConnection,getNumberFormatter(_xConnection, m_pController->getORB()),m_pController->getORB());
+ else
+ pImport = new ORTFImportExport(_xConnection,getNumberFormatter(_xConnection, m_pController->getORB()),m_pController->getORB());
+
+ SvStream* pStream = _rDesc.aHtmlRtfStorage.get();
+ if ( _bCheck )
+ pImport->enableCheckOnly();
+
+ //set the selected tablename
+ pImport->setSTableName(_rDesc.sDefaultTableName);
+
+ pImport->setStream(pStream);
+ return pImport->Read();
+}
+
+bool OTableCopyHelper::isTableFormat(const TransferableDataHelper& _rClipboard)
+{
+ bool bTableFormat = _rClipboard.HasFormat(SotClipboardFormatId::DBACCESS_TABLE)
+ || _rClipboard.HasFormat(SotClipboardFormatId::DBACCESS_QUERY)
+ || _rClipboard.HasFormat(SotClipboardFormatId::RTF)
+ || _rClipboard.HasFormat(SotClipboardFormatId::HTML);
+
+ return bTableFormat;
+}
+
+bool OTableCopyHelper::copyTagTable(const TransferableDataHelper& _aDroppedData
+ ,DropDescriptor& _rAsyncDrop
+ ,const SharedConnection& _xConnection)
+{
+ bool bRet = false;
+ bool bHtml = _aDroppedData.HasFormat(SotClipboardFormatId::HTML);
+ if ( bHtml || _aDroppedData.HasFormat(SotClipboardFormatId::RTF) )
+ {
+ bool bOk;
+ if ( bHtml )
+ bOk = _aDroppedData.GetSotStorageStream(SotClipboardFormatId::HTML ,_rAsyncDrop.aHtmlRtfStorage);
+ else
+ bOk = _aDroppedData.GetSotStorageStream(SotClipboardFormatId::RTF,_rAsyncDrop.aHtmlRtfStorage);
+
+ _rAsyncDrop.bHtml = bHtml;
+ _rAsyncDrop.bError = !copyTagTable(_rAsyncDrop,true,_xConnection);
+
+ bRet = ( !_rAsyncDrop.bError && bOk && _rAsyncDrop.aHtmlRtfStorage.is() );
+ if ( bRet )
+ {
+ // now we need to copy the stream
+ ::utl::TempFile aTmp;
+ _rAsyncDrop.aUrl = aTmp.GetURL();
+ ::tools::SvRef<SotTempStream> aNew = new SotTempStream( aTmp.GetFileName() );
+ _rAsyncDrop.aHtmlRtfStorage->Seek(STREAM_SEEK_TO_BEGIN);
+ _rAsyncDrop.aHtmlRtfStorage->CopyTo( aNew.get() );
+ _rAsyncDrop.aHtmlRtfStorage = aNew;
+ }
+ else
+ _rAsyncDrop.aHtmlRtfStorage = nullptr;
+ }
+ return bRet;
+}
+
+void OTableCopyHelper::asyncCopyTagTable( DropDescriptor& _rDesc
+ ,std::u16string_view i_rDestDataSource
+ ,const SharedConnection& _xConnection)
+{
+ if ( _rDesc.aHtmlRtfStorage.is() )
+ {
+ copyTagTable(_rDesc,false,_xConnection);
+ _rDesc.aHtmlRtfStorage = nullptr;
+ // we now have to delete the temp file created in executeDrop
+ INetURLObject aURL;
+ aURL.SetURL(_rDesc.aUrl);
+ ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ }
+ else if ( !_rDesc.bError )
+ pasteTable(_rDesc.aDroppedData,i_rDestDataSource,_xConnection);
+ else
+ m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any()));
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/TokenWriter.cxx b/dbaccess/source/ui/misc/TokenWriter.cxx
new file mode 100644
index 000000000..974337e8a
--- /dev/null
+++ b/dbaccess/source/ui/misc/TokenWriter.cxx
@@ -0,0 +1,965 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TokenWriter.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/stream.hxx>
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <RtfReader.hxx>
+#include <HtmlReader.hxx>
+#include <strings.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/document/DocumentProperties.hpp>
+#include <svtools/htmlkywd.hxx>
+#include <svtools/rtfkeywd.hxx>
+#include <tools/color.hxx>
+#include <svtools/htmlout.hxx>
+#include <sfx2/frmhtmlw.hxx>
+#include <svl/numuno.hxx>
+#include <vcl/svapp.hxx>
+#include <UITools.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <svtools/rtfout.hxx>
+#include <svtools/htmlcfg.hxx>
+#include <o3tl/string_view.hxx>
+#include <connectivity/formattedcolumnvalue.hxx>
+#include <memory>
+
+using namespace dbaui;
+using namespace dbtools;
+using namespace svx;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::util;
+
+#define CELL_X 1437
+
+ODatabaseImportExport::ODatabaseImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor,
+ const Reference< XComponentContext >& _rM,
+ const Reference< css::util::XNumberFormatter >& _rxNumberF)
+ :m_bBookmarkSelection( false )
+ ,m_pStream(nullptr)
+ ,m_xFormatter(_rxNumberF)
+ ,m_xContext(_rM)
+ ,m_nCommandType(CommandType::TABLE)
+ ,m_bNeedToReInitialize(false)
+ ,m_bInInitialize(false)
+ ,m_bCheckOnly(false)
+{
+ m_eDestEnc = osl_getThreadTextEncoding();
+
+ osl_atomic_increment( &m_refCount );
+ impl_initFromDescriptor( _aDataDescriptor, false );
+ osl_atomic_decrement( &m_refCount );
+}
+
+// import data
+ODatabaseImportExport::ODatabaseImportExport( const ::dbtools::SharedConnection& _rxConnection,
+ const Reference< XNumberFormatter >& _rxNumberF, const Reference< XComponentContext >& _rM )
+ :m_bBookmarkSelection( false )
+ ,m_pStream(nullptr)
+ ,m_xConnection(_rxConnection)
+ ,m_xFormatter(_rxNumberF)
+ ,m_xContext(_rM)
+ ,m_nCommandType(css::sdb::CommandType::TABLE)
+ ,m_bNeedToReInitialize(false)
+ ,m_bInInitialize(false)
+ ,m_bCheckOnly(false)
+{
+ m_eDestEnc = osl_getThreadTextEncoding();
+}
+
+ODatabaseImportExport::~ODatabaseImportExport()
+{
+ acquire();
+ dispose();
+}
+
+void ODatabaseImportExport::dispose()
+{
+ // remove me as listener
+ Reference< XComponent > xComponent(m_xConnection, UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference< XEventListener> xEvt(this);
+ xComponent->removeEventListener(xEvt);
+ }
+ m_xConnection.clear();
+
+ ::comphelper::disposeComponent(m_xRow);
+
+ m_xObject.clear();
+ m_xResultSetMetaData.clear();
+ m_xResultSet.clear();
+ m_xRow.clear();
+ m_xRowLocate.clear();
+ m_xFormatter.clear();
+}
+
+void SAL_CALL ODatabaseImportExport::disposing( const EventObject& Source )
+{
+ Reference<XConnection> xCon(Source.Source,UNO_QUERY);
+ if(m_xConnection.is() && m_xConnection == xCon)
+ {
+ m_xConnection.clear();
+ dispose();
+ m_bNeedToReInitialize = true;
+ }
+}
+
+void ODatabaseImportExport::initialize( const ODataAccessDescriptor& _aDataDescriptor )
+{
+ impl_initFromDescriptor( _aDataDescriptor, true );
+}
+
+void ODatabaseImportExport::impl_initFromDescriptor( const ODataAccessDescriptor& _aDataDescriptor, bool _bPlusDefaultInit)
+{
+ if ( !_bPlusDefaultInit )
+ {
+ m_sDataSourceName = _aDataDescriptor.getDataSource();
+ _aDataDescriptor[DataAccessDescriptorProperty::CommandType] >>= m_nCommandType;
+ _aDataDescriptor[DataAccessDescriptorProperty::Command] >>= m_sName;
+ // some additional information
+ if(_aDataDescriptor.has(DataAccessDescriptorProperty::Connection))
+ {
+ Reference< XConnection > xPureConn( _aDataDescriptor[DataAccessDescriptorProperty::Connection], UNO_QUERY );
+ m_xConnection.reset( xPureConn, SharedConnection::NoTakeOwnership );
+ Reference< XEventListener> xEvt(this);
+ Reference< XComponent > xComponent(m_xConnection, UNO_QUERY);
+ if (xComponent.is() && xEvt.is())
+ xComponent->addEventListener(xEvt);
+ }
+
+ if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Selection ) )
+ _aDataDescriptor[ DataAccessDescriptorProperty::Selection ] >>= m_aSelection;
+
+ if ( _aDataDescriptor.has( DataAccessDescriptorProperty::BookmarkSelection ) )
+ _aDataDescriptor[ DataAccessDescriptorProperty::BookmarkSelection ] >>= m_bBookmarkSelection;
+
+ if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Cursor ) )
+ {
+ _aDataDescriptor[ DataAccessDescriptorProperty::Cursor ] >>= m_xResultSet;
+ m_xRowLocate.set( m_xResultSet, UNO_QUERY );
+ }
+
+ if ( m_aSelection.hasElements() )
+ {
+ if ( !m_xResultSet.is() )
+ {
+ SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: selection without result set is nonsense!" );
+ m_aSelection.realloc( 0 );
+ }
+ }
+
+ if ( m_aSelection.hasElements() )
+ {
+ if ( m_bBookmarkSelection && !m_xRowLocate.is() )
+ {
+ SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: no XRowLocate -> no bookmarks!" );
+ m_aSelection.realloc( 0 );
+ }
+ }
+ }
+ else
+ initialize();
+}
+
+void ODatabaseImportExport::initialize()
+{
+ m_bInInitialize = true;
+ m_bNeedToReInitialize = false;
+
+ if ( !m_xConnection.is() )
+ { // we need a connection
+ OSL_ENSURE(!m_sDataSourceName.isEmpty(),"There must be a datsource name!");
+ Reference<XNameAccess> xDatabaseContext( DatabaseContext::create(m_xContext), UNO_QUERY_THROW);
+ Reference< XEventListener> xEvt(this);
+
+ Reference< XConnection > xConnection;
+ SQLExceptionInfo aInfo = ::dbaui::createConnection( m_sDataSourceName, xDatabaseContext, m_xContext, xEvt, xConnection );
+ m_xConnection.reset( xConnection );
+
+ if(aInfo.isValid() && aInfo.getType() == SQLExceptionInfo::TYPE::SQLException)
+ throw *static_cast<const SQLException*>(aInfo);
+ }
+
+ Reference<XNameAccess> xNameAccess;
+ switch(m_nCommandType)
+ {
+ case CommandType::TABLE:
+ {
+ // only for tables
+ Reference<XTablesSupplier> xSup(m_xConnection,UNO_QUERY);
+ if(xSup.is())
+ xNameAccess = xSup->getTables();
+ }
+ break;
+ case CommandType::QUERY:
+ {
+ Reference<XQueriesSupplier> xSup(m_xConnection,UNO_QUERY);
+ if(xSup.is())
+ xNameAccess = xSup->getQueries();
+ }
+ break;
+ }
+ if(xNameAccess.is() && xNameAccess->hasByName(m_sName))
+ {
+ xNameAccess->getByName(m_sName) >>= m_xObject;
+ }
+
+ if(m_xObject.is())
+ {
+ try
+ {
+ if(m_xObject->getPropertySetInfo()->hasPropertyByName(PROPERTY_FONT))
+ m_xObject->getPropertyValue(PROPERTY_FONT) >>= m_aFont;
+
+ // the result set may be already set with the datadescriptor
+ if ( !m_xResultSet.is() )
+ {
+ m_xResultSet.set( m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.sdb.RowSet", m_xContext), UNO_QUERY );
+ Reference< XPropertySet > xProp( m_xResultSet, UNO_QUERY_THROW );
+ xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( m_xConnection.getTyped() ) );
+ xProp->setPropertyValue( PROPERTY_COMMAND_TYPE, Any( m_nCommandType ) );
+ xProp->setPropertyValue( PROPERTY_COMMAND, Any( m_sName ) );
+ Reference< XRowSet > xRowSet( xProp, UNO_QUERY );
+ xRowSet->execute();
+ }
+ if ( !m_xRow.is() && m_xResultSet.is() )
+ {
+ m_xRow.set( m_xResultSet, UNO_QUERY );
+ m_xRowLocate.set( m_xResultSet, UNO_QUERY );
+ m_xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(m_xRow,UNO_QUERY_THROW)->getMetaData();
+ Reference<XColumnsSupplier> xSup(m_xResultSet,UNO_QUERY_THROW);
+ m_xRowSetColumns.set(xSup->getColumns(),UNO_QUERY_THROW);
+ }
+ }
+ catch(Exception& )
+ {
+ m_xRow = nullptr;
+ m_xResultSetMetaData = nullptr;
+ ::comphelper::disposeComponent(m_xResultSet);
+ throw;
+ }
+ }
+ if ( m_aFont.Name.isEmpty() )
+ {
+ vcl::Font aApplicationFont = OutputDevice::GetDefaultFont(
+ DefaultFontType::SANS_UNICODE,
+ Application::GetSettings().GetUILanguageTag().getLanguageType(),
+ GetDefaultFontFlags::OnlyOne
+ );
+ m_aFont = VCLUnoHelper::CreateFontDescriptor( aApplicationFont );
+ }
+
+ m_bInInitialize = false;
+}
+
+bool ODatabaseImportExport::Write()
+{
+ if ( m_bNeedToReInitialize )
+ {
+ if ( !m_bInInitialize )
+ initialize();
+ }
+ return true;
+}
+
+bool ODatabaseImportExport::Read()
+{
+ if ( m_bNeedToReInitialize )
+ {
+ if ( !m_bInInitialize )
+ initialize();
+ }
+ return true;
+}
+
+bool ORTFImportExport::Write()
+{
+ ODatabaseImportExport::Write();
+ m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RTF );
+ m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSI);
+ if (sal_uInt32 nCpg = rtl_getWindowsCodePageFromTextEncoding(m_eDestEnc); nCpg && nCpg != 65001)
+ {
+ m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSICPG).WriteUInt32AsString(nCpg);
+ }
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING);
+
+ bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight );
+ bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant );
+ bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline );
+ bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout );
+
+ ::Color aColor;
+ if(m_xObject.is())
+ m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor;
+
+ OString aFonts(OUStringToOString(m_aFont.Name, RTL_TEXTENCODING_MS_1252));
+ if (aFonts.isEmpty())
+ {
+ OUString aName = Application::GetSettings().GetStyleSettings().GetAppFont().GetFamilyName();
+ aFonts = OUStringToOString(aName, RTL_TEXTENCODING_MS_1252);
+ }
+
+ m_pStream->WriteCharPtr( "{\\fonttbl" );
+ if (!aFonts.isEmpty())
+ {
+ sal_Int32 nIdx{0};
+ sal_Int32 nTok{-1}; // to compensate pre-increment
+ do {
+ m_pStream->WriteCharPtr( "\\f" );
+ m_pStream->WriteInt32AsString(++nTok);
+ m_pStream->WriteCharPtr( "\\fcharset0\\fnil " );
+ m_pStream->WriteOString( o3tl::getToken(aFonts, 0, ';', nIdx) );
+ m_pStream->WriteChar( ';' );
+ } while (nIdx>=0);
+ }
+ m_pStream->WriteChar( '}' ) ;
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+ // write the rtf color table
+ m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_COLORTBL ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RED );
+ m_pStream->WriteUInt32AsString(aColor.GetRed());
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_GREEN );
+ m_pStream->WriteUInt32AsString(aColor.GetGreen());
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_BLUE );
+ m_pStream->WriteUInt32AsString(aColor.GetBlue());
+
+ m_pStream->WriteCharPtr( ";\\red255\\green255\\blue255;\\red192\\green192\\blue192;}" )
+ .WriteCharPtr( SAL_NEWLINE_STRING );
+
+ static char const aCell1[] = "\\clbrdrl\\brdrs\\brdrcf0\\clbrdrt\\brdrs\\brdrcf0\\clbrdrb\\brdrs\\brdrcf0\\clbrdrr\\brdrs\\brdrcf0\\clshdng10000\\clcfpat2\\cellx";
+
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH );
+ m_pStream->WriteInt32AsString(40);
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+
+ if(m_xObject.is())
+ {
+ Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY);
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ Sequence< OUString> aNames(xColumns->getElementNames());
+ const OUString* pIter = aNames.getConstArray();
+
+ sal_Int32 nCount = aNames.getLength();
+ bool bUseResultMetaData = false;
+ if ( !nCount )
+ {
+ nCount = m_xResultSetMetaData->getColumnCount();
+ bUseResultMetaData = true;
+ }
+
+ for( sal_Int32 i=1; i<=nCount; ++i )
+ {
+ m_pStream->WriteCharPtr( aCell1 );
+ m_pStream->WriteInt32AsString(i*CELL_X);
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+ }
+
+ // column description
+ m_pStream->WriteChar( '{' ).WriteCharPtr( SAL_NEWLINE_STRING );
+ m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" );
+
+ std::unique_ptr<OString[]> pHorzChar(new OString[nCount]);
+
+ for ( sal_Int32 i=1; i <= nCount; ++i )
+ {
+ sal_Int32 nAlign = 0;
+ OUString sColumnName;
+ if ( bUseResultMetaData )
+ sColumnName = m_xResultSetMetaData->getColumnName(i);
+ else
+ {
+ sColumnName = *pIter;
+ Reference<XPropertySet> xColumn;
+ xColumns->getByName(sColumnName) >>= xColumn;
+ xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
+ ++pIter;
+ }
+
+ const char* pChar;
+ switch( nAlign )
+ {
+ case 1: pChar = OOO_STRING_SVTOOLS_RTF_QC; break;
+ case 2: pChar = OOO_STRING_SVTOOLS_RTF_QR; break;
+ case 0:
+ default:pChar = OOO_STRING_SVTOOLS_RTF_QL; break;
+ }
+
+ pHorzChar[i-1] = pChar; // to avoid to always rummage in the ITEMSET later on
+
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+ m_pStream->WriteChar( '{' );
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QC ); // column header always centered
+
+ if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B );
+ if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I );
+ if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL );
+ if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE );
+
+ m_pStream->WriteCharPtr( "\\fs20\\f0\\cf0\\cb2" );
+ m_pStream->WriteChar( ' ' );
+ RTFOutFuncs::Out_String(*m_pStream, sColumnName, m_eDestEnc);
+
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL );
+ m_pStream->WriteChar( '}' );
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL );
+ }
+
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW );
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ).WriteChar( '}' );
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+
+ sal_Int32 k=1;
+ sal_Int32 kk=0;
+ if ( m_aSelection.hasElements() )
+ {
+ const Any* pSelIter = m_aSelection.getConstArray();
+ const Any* pEnd = pSelIter + m_aSelection.getLength();
+
+ bool bContinue = true;
+ for( ; pSelIter != pEnd && bContinue; ++pSelIter )
+ {
+ if ( m_bBookmarkSelection )
+ {
+ bContinue = m_xRowLocate->moveToBookmark( *pSelIter );
+ }
+ else
+ {
+ sal_Int32 nPos = -1;
+ OSL_VERIFY( *pSelIter >>= nPos );
+ bContinue = ( m_xResultSet->absolute( nPos ) );
+ }
+
+ if ( bContinue )
+ appendRow( pHorzChar.get(), nCount, k, kk );
+ }
+ }
+ else
+ {
+ m_xResultSet->beforeFirst(); // set back before the first row
+ while(m_xResultSet->next())
+ {
+ appendRow(pHorzChar.get(),nCount,k,kk);
+ }
+ }
+ }
+
+ m_pStream->WriteChar( '}' ).WriteCharPtr( SAL_NEWLINE_STRING );
+ m_pStream->WriteUChar( 0 );
+ return ((*m_pStream).GetError() == ERRCODE_NONE);
+}
+
+void ORTFImportExport::appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk)
+{
+ ++kk;
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH );
+ m_pStream->WriteInt32AsString(40);
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+
+ static char const aCell2[] = "\\clbrdrl\\brdrs\\brdrcf2\\clbrdrt\\brdrs\\brdrcf2\\clbrdrb\\brdrs\\brdrcf2\\clbrdrr\\brdrs\\brdrcf2\\clshdng10000\\clcfpat1\\cellx";
+
+ for ( sal_Int32 i=1; i<=_nColumnCount; ++i )
+ {
+ m_pStream->WriteCharPtr( aCell2 );
+ m_pStream->WriteInt32AsString(i*CELL_X);
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+ }
+
+ const bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight );
+ const bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant );
+ const bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline );
+ const bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout );
+ Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY);
+
+ m_pStream->WriteChar( '{' );
+ m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" );
+ for ( sal_Int32 i=1; i <= _nColumnCount; ++i )
+ {
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+ m_pStream->WriteChar( '{' );
+ m_pStream->WriteOString( pHorzChar[i-1] );
+
+ if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B );
+ if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I );
+ if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL );
+ if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE );
+
+ m_pStream->WriteCharPtr( "\\fs20\\f1\\cf0\\cb1 " );
+
+ try
+ {
+ Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW);
+ dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn);
+ OUString sValue = aFormatedValue.getFormattedValue();
+ if ( !sValue.isEmpty() )
+ RTFOutFuncs::Out_String(*m_pStream,sValue,m_eDestEnc);
+ }
+ catch (Exception&)
+ {
+ SAL_WARN("dbaccess.ui","RTF WRITE!");
+ }
+
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL );
+ m_pStream->WriteChar( '}' );
+ m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL );
+ }
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ).WriteCharPtr( SAL_NEWLINE_STRING );
+ m_pStream->WriteChar( '}' );
+ ++k;
+}
+
+bool ORTFImportExport::Read()
+{
+ ODatabaseImportExport::Read();
+ SvParserState eState = SvParserState::Error;
+ if ( m_pStream )
+ {
+ tools::SvRef<ORTFReader> xReader(new ORTFReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext));
+ if ( isCheckEnabled() )
+ xReader->enableCheckOnly();
+ eState = xReader->CallParser();
+ }
+
+ return eState != SvParserState::Error;
+}
+
+const sal_Int16 OHTMLImportExport::nCellSpacing = 0;
+const char OHTMLImportExport::sIndentSource[nIndentMax+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
+OHTMLImportExport::OHTMLImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor,
+ const Reference< XComponentContext >& _rM,
+ const Reference< css::util::XNumberFormatter >& _rxNumberF)
+ : ODatabaseImportExport(_aDataDescriptor,_rM,_rxNumberF)
+ ,m_nIndent(0)
+#if OSL_DEBUG_LEVEL > 0
+ ,m_bCheckFont(false)
+#endif
+{
+ // set HTML configuration
+ m_eDestEnc = RTL_TEXTENCODING_UTF8;
+ strncpy( sIndent, sIndentSource ,std::min(sizeof(sIndent),sizeof(sIndentSource)));
+ sIndent[0] = 0;
+}
+
+bool OHTMLImportExport::Write()
+{
+ ODatabaseImportExport::Write();
+ if(m_xObject.is())
+ {
+ m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype5 ).WriteChar( '>' ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING );
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ WriteHeader();
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ WriteBody();
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ return ((*m_pStream).GetError() == ERRCODE_NONE);
+ }
+ return false;
+}
+
+bool OHTMLImportExport::Read()
+{
+ ODatabaseImportExport::Read();
+ SvParserState eState = SvParserState::Error;
+ if ( m_pStream )
+ {
+ tools::SvRef<OHTMLReader> xReader(new OHTMLReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext));
+ if ( isCheckEnabled() )
+ xReader->enableCheckOnly();
+ xReader->SetTableName(m_sDefaultTableName);
+ eState = xReader->CallParser();
+ }
+
+ return eState != SvParserState::Error;
+}
+
+void OHTMLImportExport::WriteHeader()
+{
+ uno::Reference<document::XDocumentProperties> xDocProps(
+ document::DocumentProperties::create( m_xContext ) );
+ if (xDocProps.is()) {
+ xDocProps->setTitle(m_sName);
+ }
+
+ IncIndent(1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_head).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ SfxFrameHTMLWriter::Out_DocInfo( (*m_pStream), OUString(),
+ xDocProps, sIndent );
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ IncIndent(-1);
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_head, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+}
+
+void OHTMLImportExport::WriteBody()
+{
+ IncIndent(1);
+ m_pStream->WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" );
+
+ m_pStream->WriteCharPtr( "<!-- " );
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteCharPtr( " { " ).WriteCharPtr( "font-family: " ).WriteChar( '"' ).WriteOString( OUStringToOString(m_aFont.Name, osl_getThreadTextEncoding()) ).WriteChar( '\"' );
+ // TODO : think about the encoding of the font name
+ m_pStream->WriteCharPtr( "; " ).WriteCharPtr( "font-size: " );
+ m_pStream->WriteInt32AsString(m_aFont.Height);
+ m_pStream->WriteChar( '}' );
+
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ m_pStream->WriteCharPtr( " -->" );
+ IncIndent(-1);
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_style, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ // default Textcolour black
+ m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_text ).WriteChar( '=' );
+ ::Color aColor;
+ if(m_xObject.is())
+ m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor;
+ HTMLOutFuncs::Out_Color( (*m_pStream), aColor );
+
+ m_pStream->WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_bgcolor "=" );
+ HTMLOutFuncs::Out_Color( (*m_pStream), aColor );
+
+ m_pStream->WriteChar( '>' );
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ WriteTables();
+
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_body, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+}
+
+void OHTMLImportExport::WriteTables()
+{
+ OString aStrOut = OOO_STRING_SVTOOLS_HTML_table
+ " "
+ OOO_STRING_SVTOOLS_HTML_frame
+ "="
+ OOO_STRING_SVTOOLS_HTML_TF_void;
+
+ Sequence< OUString> aNames;
+ Reference<XNameAccess> xColumns;
+ bool bUseResultMetaData = false;
+ if(m_xObject.is())
+ {
+ Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY);
+ xColumns = xColSup->getColumns();
+ aNames = xColumns->getElementNames();
+ if ( !aNames.hasElements() )
+ {
+ sal_Int32 nCount = m_xResultSetMetaData->getColumnCount();
+ aNames.realloc(nCount);
+ auto aNamesRange = asNonConstRange(aNames);
+ for (sal_Int32 i= 0; i < nCount; ++i)
+ aNamesRange[i] = m_xResultSetMetaData->getColumnName(i+1);
+ bUseResultMetaData = true;
+ }
+ }
+
+ aStrOut += " "
+ OOO_STRING_SVTOOLS_HTML_O_align
+ "="
+ OOO_STRING_SVTOOLS_HTML_AL_left
+ " "
+ OOO_STRING_SVTOOLS_HTML_O_cellspacing
+ "=" +
+ OString::number(nCellSpacing) +
+ " "
+ OOO_STRING_SVTOOLS_HTML_O_cols
+ "=" +
+ OString::number(aNames.getLength()) +
+ " "
+ OOO_STRING_SVTOOLS_HTML_O_border
+ "=1";
+
+ IncIndent(1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, aStrOut.getStr());
+
+ FontOn();
+
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_caption);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold);
+
+ m_pStream->WriteOString( OUStringToOString(m_sName, osl_getThreadTextEncoding()) );
+ // TODO : think about the encoding of the name
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold, false);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_caption, false);
+
+ FontOff();
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ // </FONT>
+
+ IncIndent(1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ IncIndent(1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ if(m_xObject.is())
+ {
+ std::unique_ptr<sal_Int32[]> pFormat(new sal_Int32[aNames.getLength()]);
+
+ std::unique_ptr<const char *[]> pHorJustify(new const char*[aNames.getLength()]);
+ std::unique_ptr<sal_Int32[]> pColWidth(new sal_Int32[aNames.getLength()]);
+
+ sal_Int32 nHeight = 0;
+ m_xObject->getPropertyValue(PROPERTY_ROW_HEIGHT) >>= nHeight;
+
+ // 1. writing the column description
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+
+ for( sal_Int32 i=0;pIter != pEnd; ++pIter,++i )
+ {
+ sal_Int32 nAlign = 0;
+ pFormat[i] = 0;
+ pColWidth[i] = 100;
+ if ( !bUseResultMetaData )
+ {
+ Reference<XPropertySet> xColumn;
+ xColumns->getByName(*pIter) >>= xColumn;
+ xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
+ pFormat[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_FORMATKEY));
+ pColWidth[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_WIDTH));
+ }
+
+ switch( nAlign )
+ {
+ case 1: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_center; break;
+ case 2: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_right; break;
+ default: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_left; break;
+ }
+
+ if(i == aNames.getLength()-1)
+ IncIndent(-1);
+
+ WriteCell(pFormat[i],pColWidth[i],nHeight,pHorJustify[i],*pIter,OOO_STRING_SVTOOLS_HTML_tableheader);
+ }
+
+ IncIndent(-1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ IncIndent(1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ // 2. and now the data
+ Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY);
+ m_xResultSet->beforeFirst(); // set back before the first row
+ while(m_xResultSet->next())
+ {
+ IncIndent(1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ for(sal_Int32 i=1;i<=aNames.getLength();++i)
+ {
+ if(i == aNames.getLength())
+ IncIndent(-1);
+
+ OUString aValue;
+ try
+ {
+ Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW);
+ dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn);
+ OUString sValue = aFormatedValue.getFormattedValue();
+ if (!sValue.isEmpty())
+ {
+ aValue = sValue;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ WriteCell(pFormat[i-1],pColWidth[i-1],nHeight,pHorJustify[i-1],aValue,OOO_STRING_SVTOOLS_HTML_tabledata);
+ }
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ }
+ }
+ else
+ {
+ IncIndent(-1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+
+ IncIndent(1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ }
+
+ IncIndent(-1);
+ m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+ IncIndent(-1);
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_table, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+}
+
+void OHTMLImportExport::WriteCell( sal_Int32 nFormat, sal_Int32 nWidthPixel, sal_Int32 nHeightPixel, const char* pChar,
+ const OUString& rValue, const char* pHtmlTag)
+{
+ OString aStrTD = pHtmlTag;
+
+ nWidthPixel = nWidthPixel ? nWidthPixel : 86;
+ nHeightPixel = nHeightPixel ? nHeightPixel : 17;
+
+ // despite the <TABLE COLS=n> and <COL WIDTH=x> designation necessary,
+ // as Netscape is not paying attention to them.
+ // column width
+ aStrTD += " "
+ OOO_STRING_SVTOOLS_HTML_O_width
+ "=" +
+ OString::number(nWidthPixel) +
+ // line height
+ " "
+ OOO_STRING_SVTOOLS_HTML_O_height
+ "=" +
+ OString::number(nHeightPixel) +
+ " "
+ OOO_STRING_SVTOOLS_HTML_O_align
+ "=" +
+ pChar;
+
+ SvNumberFormatsSupplierObj* pSupplierImpl = m_xFormatter.is() ? comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(m_xFormatter->getNumberFormatsSupplier()) : nullptr;
+ SvNumberFormatter* pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr;
+ if(pFormatter)
+ {
+ double fVal = 0.0;
+
+ try
+ {
+ fVal = m_xFormatter->convertStringToNumber(nFormat,rValue);
+ HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter);
+ }
+ catch(const Exception&)
+ {
+ HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter);
+ }
+ }
+
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, aStrTD.getStr());
+
+ FontOn();
+
+ bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight );
+ bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant );
+ bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline );
+ bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout );
+
+ if ( bBold ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold);
+ if ( bItalic ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_italic);
+ if ( bUnderline ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_underline);
+ if ( bStrikeout ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_strike);
+
+ if ( rValue.isEmpty() )
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_linebreak); // no completely empty cell
+ else
+ HTMLOutFuncs::Out_String( (*m_pStream), rValue );
+
+ if ( bStrikeout ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_strike, false);
+ if ( bUnderline ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_underline, false);
+ if ( bItalic ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_italic, false);
+ if ( bBold ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold, false);
+
+ FontOff();
+
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, pHtmlTag, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr());
+}
+
+void OHTMLImportExport::FontOn()
+{
+#if OSL_DEBUG_LEVEL > 0
+ m_bCheckFont = true;
+#endif
+
+ // <FONT FACE="xxx">
+ OString aStrOut = "<"
+ OOO_STRING_SVTOOLS_HTML_font
+ " "
+ OOO_STRING_SVTOOLS_HTML_O_face
+ "="
+ "\"" +
+ OUStringToOString(m_aFont.Name,osl_getThreadTextEncoding()) +
+ // TODO : think about the encoding of the font name
+ "\""
+ " "
+ OOO_STRING_SVTOOLS_HTML_O_color
+ "=";
+ m_pStream->WriteOString( aStrOut );
+
+ ::Color aColor;
+ if(m_xObject.is())
+ m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor;
+
+ HTMLOutFuncs::Out_Color( (*m_pStream), aColor );
+ m_pStream->WriteCharPtr( ">" );
+}
+
+inline void OHTMLImportExport::FontOff()
+{
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE(m_bCheckFont,"No FontOn() called");
+#endif
+ HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_font, false);
+#if OSL_DEBUG_LEVEL > 0
+ m_bCheckFont = false;
+#endif
+}
+
+void OHTMLImportExport::IncIndent( sal_Int16 nVal )
+{
+ sIndent[m_nIndent] = '\t';
+ m_nIndent = m_nIndent + nVal;
+ if ( m_nIndent < 0 )
+ m_nIndent = 0;
+ else if ( m_nIndent > nIndentMax )
+ m_nIndent = nIndentMax;
+ sIndent[m_nIndent] = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/UITools.cxx b/dbaccess/source/ui/misc/UITools.cxx
new file mode 100644
index 000000000..7a9553e49
--- /dev/null
+++ b/dbaccess/source/ui/misc/UITools.cxx
@@ -0,0 +1,1370 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <UITools.hxx>
+#include <sfx2/docfilt.hxx>
+#include <core_resource.hxx>
+#include <dlgsave.hxx>
+#include <defaultobjectnamecheck.hxx>
+#include <strings.hxx>
+#include <comphelper/extract.hxx>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+#include <vcl/syswin.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <TypeInfo.hxx>
+#include <FieldDescriptions.hxx>
+#include <comphelper/stl_types.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/propertysequence.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <sal/log.hxx>
+#include <svl/numformat.hxx>
+#include <svl/itempool.hxx>
+#include <helpids.h>
+#include <svl/itemset.hxx>
+#include <sbagrid.hrc>
+#include <svl/rngitem.hxx>
+#include <svl/intitem.hxx>
+#include <svx/numinf.hxx>
+#include <svl/zforlist.hxx>
+#include <dlgattr.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <strings.hrc>
+#include <sqlmessage.hxx>
+#include <dlgsize.hxx>
+#include <svtools/editbrowsebox.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+#include <svl/numuno.hxx>
+#include <svl/filenotation.hxx>
+#include <connectivity/FValue.hxx>
+
+#include <editeng/justifyitem.hxx>
+#include <memory>
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::comphelper;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::svt;
+using ::com::sun::star::ucb::InteractiveIOException;
+using ::com::sun::star::ucb::IOErrorCode_NO_FILE;
+using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING;
+
+SQLExceptionInfo createConnection( const OUString& _rsDataSourceName,
+ const Reference< css::container::XNameAccess >& _xDatabaseContext,
+ const Reference< css::uno::XComponentContext >& _rxContext,
+ Reference< css::lang::XEventListener> const & _rEvtLst,
+ Reference< css::sdbc::XConnection>& _rOUTConnection )
+{
+ Reference<XPropertySet> xProp;
+ try
+ {
+ xProp.set(_xDatabaseContext->getByName(_rsDataSourceName),UNO_QUERY);
+ }
+ catch(const Exception&)
+ {
+ }
+
+ return createConnection(xProp,_rxContext,_rEvtLst,_rOUTConnection);
+}
+
+SQLExceptionInfo createConnection( const Reference< css::beans::XPropertySet>& _xDataSource,
+ const Reference< css::uno::XComponentContext >& _rxContext,
+ Reference< css::lang::XEventListener> const & _rEvtLst,
+ Reference< css::sdbc::XConnection>& _rOUTConnection )
+{
+ SQLExceptionInfo aInfo;
+ if ( !_xDataSource.is() )
+ {
+ SAL_WARN("dbaccess.ui", "createConnection: could not retrieve the data source!");
+ return aInfo;
+ }
+
+ OUString sPwd, sUser;
+ bool bPwdReq = false;
+ try
+ {
+ _xDataSource->getPropertyValue(PROPERTY_PASSWORD) >>= sPwd;
+ bPwdReq = ::cppu::any2bool(_xDataSource->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED));
+ _xDataSource->getPropertyValue(PROPERTY_USER) >>= sUser;
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess.ui", "createConnection: error while retrieving data source properties!");
+ }
+
+ try
+ {
+ if(bPwdReq && sPwd.isEmpty())
+ { // password required, but empty -> connect using an interaction handler
+ Reference<XCompletedConnection> xConnectionCompletion(_xDataSource, UNO_QUERY);
+ if (!xConnectionCompletion.is())
+ {
+ SAL_WARN("dbaccess.ui", "createConnection: missing an interface ... need an error message here!");
+ }
+ else
+ { // instantiate the default SDB interaction handler
+ Reference< XInteractionHandler > xHandler = InteractionHandler::createWithParent(_rxContext, nullptr);
+ _rOUTConnection = xConnectionCompletion->connectWithCompletion(xHandler);
+ }
+ }
+ else
+ {
+ Reference<XDataSource> xDataSource(_xDataSource,UNO_QUERY);
+ _rOUTConnection = xDataSource->getConnection(sUser, sPwd);
+ }
+ // be notified when connection is in disposing
+ Reference< XComponent > xComponent(_rOUTConnection, UNO_QUERY);
+ if (xComponent.is() && _rEvtLst.is())
+ xComponent->addEventListener(_rEvtLst);
+ }
+ catch(const SQLContext& e) { aInfo = SQLExceptionInfo(e); }
+ catch(const SQLWarning& e) { aInfo = SQLExceptionInfo(e); }
+ catch(const SQLException& e) { aInfo = SQLExceptionInfo(e); }
+ catch(const Exception&) {
+ TOOLS_WARN_EXCEPTION("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: could not connect - unknown exception");
+ }
+
+ return aInfo;
+}
+
+Reference< XDataSource > getDataSourceByName( const OUString& _rDataSourceName,
+ weld::Window* _pErrorMessageParent, const Reference< XComponentContext >& _rxContext, ::dbtools::SQLExceptionInfo* _pErrorInfo )
+{
+ Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create(_rxContext);
+
+ Reference< XDataSource > xDatasource;
+ SQLExceptionInfo aSQLError;
+ try
+ {
+ xDatabaseContext->getByName( _rDataSourceName ) >>= xDatasource;
+ }
+ catch(const WrappedTargetException& e)
+ {
+ InteractiveIOException aIOException;
+ if ( ( e.TargetException >>= aIOException )
+ && ( ( aIOException.Code == IOErrorCode_NO_FILE )
+ || ( aIOException.Code == IOErrorCode_NOT_EXISTING )
+ )
+ )
+ {
+ OUString sErrorMessage( DBA_RES( STR_FILE_DOES_NOT_EXIST ) );
+ OFileNotation aTransformer( e.Message );
+ sErrorMessage = sErrorMessage.replaceFirst( "$file$", aTransformer.get( OFileNotation::N_SYSTEM ) );
+ aSQLError = SQLExceptionInfo( sErrorMessage ).get();
+ }
+ else
+ {
+ aSQLError = SQLExceptionInfo( e.TargetException );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( xDatasource.is() )
+ return xDatasource;
+
+ if ( aSQLError.isValid() )
+ {
+ if ( _pErrorInfo )
+ {
+ *_pErrorInfo = aSQLError;
+ }
+ else
+ {
+ showError( aSQLError, _pErrorMessageParent ? _pErrorMessageParent->GetXWindow() : nullptr, _rxContext );
+ }
+ }
+
+ return Reference<XDataSource>();
+}
+
+Reference< XInterface > getDataSourceOrModel(const Reference< XInterface >& _xObject)
+{
+ Reference< XInterface > xRet;
+ Reference<XDocumentDataSource> xDocumentDataSource(_xObject,UNO_QUERY);
+ if ( xDocumentDataSource.is() )
+ xRet = xDocumentDataSource->getDatabaseDocument();
+
+ if ( !xRet.is() )
+ {
+ Reference<XOfficeDatabaseDocument> xOfficeDoc(_xObject,UNO_QUERY);
+ if ( xOfficeDoc.is() )
+ xRet = xOfficeDoc->getDataSource();
+ }
+
+ return xRet;
+}
+
+TOTypeInfoSP getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo,
+ sal_Int32 _nType,
+ const OUString& _sTypeName,
+ const OUString& _sCreateParams,
+ sal_Int32 _nPrecision,
+ sal_Int32 _nScale,
+ bool _bAutoIncrement,
+ bool& _brForceToType)
+{
+ TOTypeInfoSP pTypeInfo;
+ _brForceToType = false;
+ // search for type
+ std::pair<OTypeInfoMap::const_iterator, OTypeInfoMap::const_iterator> aPair = _rTypeInfo.equal_range(_nType);
+ OTypeInfoMap::const_iterator aIter = aPair.first;
+ if(aIter != _rTypeInfo.end()) // compare with end is correct here
+ {
+ for(;aIter != aPair.second;++aIter)
+ {
+ // search the best matching type
+ #ifdef DBG_UTIL
+ OUString sDBTypeName = aIter->second->aTypeName; (void)sDBTypeName;
+ #endif
+ if ( (
+ _sTypeName.isEmpty()
+ || (aIter->second->aTypeName.equalsIgnoreAsciiCase(_sTypeName))
+ )
+ && (
+ (
+ !aIter->second->aCreateParams.getLength()
+ && _sCreateParams.isEmpty()
+ )
+ || (
+ (aIter->second->nPrecision >= _nPrecision)
+ && (aIter->second->nMaximumScale >= _nScale)
+ && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
+ )
+ )
+ )
+ break;
+ }
+
+ if (aIter == aPair.second)
+ {
+ for(aIter = aPair.first; aIter != aPair.second; ++aIter)
+ {
+ sal_Int32 nPrec = aIter->second->nPrecision;
+ sal_Int32 nScale = aIter->second->nMaximumScale;
+ // search the best matching type (now comparing the local names)
+ if ( (aIter->second->aLocalTypeName.equalsIgnoreAsciiCase(_sTypeName))
+ && (nPrec >= _nPrecision)
+ && (nScale >= _nScale)
+ && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
+ )
+ {
+ SAL_WARN("dbaccess.ui", "getTypeInfoFromType: assuming column type " <<
+ aIter->second->aTypeName << "\" (expected type name " <<
+ _sTypeName << " matches the type's local name).");
+ break;
+ }
+ }
+ }
+
+ if (aIter == aPair.second)
+ { // no match for the names, no match for the local names
+ // -> drop the precision and the scale restriction, accept any type with the property
+ // type id (nType)
+
+ for(aIter = aPair.first; aIter != aPair.second; ++aIter)
+ {
+ // search the best matching type (now comparing the local names)
+ sal_Int32 nPrec = aIter->second->nPrecision;
+ sal_Int32 nScale = aIter->second->nMaximumScale;
+ if ( (nPrec >= _nPrecision)
+ && (nScale >= _nScale)
+ && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement )
+ )
+ break;
+ }
+ }
+ if (aIter == aPair.second)
+ {
+ if ( _bAutoIncrement )
+ {
+ for(aIter = aPair.first; aIter != aPair.second; ++aIter)
+ {
+ // search the best matching type (now comparing the local names)
+ sal_Int32 nScale = aIter->second->nMaximumScale;
+ if ( (nScale >= _nScale)
+ && (aIter->second->bAutoIncrement == _bAutoIncrement)
+ )
+ break;
+ }
+ if ( aIter == aPair.second )
+ {
+ // try it without the auto increment flag
+ pTypeInfo = getTypeInfoFromType(_rTypeInfo,
+ _nType,
+ _sTypeName,
+ _sCreateParams,
+ _nPrecision,
+ _nScale,
+ false,
+ _brForceToType);
+ }
+ else
+ pTypeInfo = aIter->second;
+ }
+ else
+ {
+ pTypeInfo = aPair.first->second;
+ _brForceToType = true;
+ }
+ }
+ else
+ pTypeInfo = aIter->second;
+ }
+ else
+ {
+ ::comphelper::UStringMixEqual aCase(false);
+ // search for typeinfo where the typename is equal _sTypeName
+ for (auto const& elem : _rTypeInfo)
+ {
+ if ( aCase( elem.second->getDBName() , _sTypeName ) )
+ {
+ pTypeInfo = elem.second;
+ break;
+ }
+ }
+ }
+
+ OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!");
+ return pTypeInfo;
+}
+
+void fillTypeInfo( const Reference< css::sdbc::XConnection>& _rxConnection,
+ std::u16string_view _rsTypeNames,
+ OTypeInfoMap& _rTypeInfoMap,
+ std::vector<OTypeInfoMap::iterator>& _rTypeInfoIters)
+{
+ if(!_rxConnection.is())
+ return;
+ Reference< XResultSet> xRs = _rxConnection->getMetaData ()->getTypeInfo ();
+ Reference< XRow> xRow(xRs,UNO_QUERY);
+ // Information for a single SQL type
+ if(!xRs.is())
+ return;
+
+ Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xRs,UNO_QUERY_THROW)->getMetaData();
+ ::connectivity::ORowSetValue aValue;
+ std::vector<sal_Int32> aTypes;
+ std::vector<bool> aNullable;
+ // Loop on the result set until we reach end of file
+ while (xRs->next())
+ {
+ TOTypeInfoSP pInfo = std::make_shared<OTypeInfo>();
+ sal_Int32 nPos = 1;
+ if ( aTypes.empty() )
+ {
+ sal_Int32 nCount = xResultSetMetaData->getColumnCount();
+ if ( nCount < 1 )
+ nCount = 18;
+ aTypes.reserve(nCount+1);
+ aTypes.push_back(-1);
+ aNullable.push_back(false);
+ for (sal_Int32 j = 1; j <= nCount ; ++j)
+ {
+ aTypes.push_back(xResultSetMetaData->getColumnType(j));
+ aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS);
+ }
+ }
+
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->aTypeName = aValue.getString();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->nType = aValue.getInt32();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->nPrecision = aValue.getInt32();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); // LiteralPrefix
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->aCreateParams = aValue.getString();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->bNullable = aValue.getInt32() == ColumnValue::NULLABLE;
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ // bCaseSensitive
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->nSearchType = aValue.getInt16();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ // bUnsigned
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->bCurrency = aValue.getBool();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->bAutoIncrement = aValue.getBool();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->aLocalTypeName = aValue.getString();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->nMinimumScale = aValue.getInt16();
+ ++nPos;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->nMaximumScale = aValue.getInt16();
+ assert(nPos == 15);
+ // 16 and 17 are unused
+ nPos = 18;
+ aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow);
+ pInfo->nNumPrecRadix = aValue.getInt32();
+
+ // check if values are less than zero like it happens in a oracle jdbc driver
+ if( pInfo->nPrecision < 0)
+ pInfo->nPrecision = 0;
+ if( pInfo->nMinimumScale < 0)
+ pInfo->nMinimumScale = 0;
+ if( pInfo->nMaximumScale < 0)
+ pInfo->nMaximumScale = 0;
+ if( pInfo->nNumPrecRadix <= 1)
+ pInfo->nNumPrecRadix = 10;
+
+ std::u16string_view aName;
+ switch(pInfo->nType)
+ {
+ case DataType::CHAR:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_CHAR, ';');
+ break;
+ case DataType::VARCHAR:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_TEXT, ';');
+ break;
+ case DataType::DECIMAL:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_DECIMAL, ';');
+ break;
+ case DataType::NUMERIC:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_NUMERIC, ';');
+ break;
+ case DataType::BIGINT:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_BIGINT, ';');
+ break;
+ case DataType::FLOAT:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_FLOAT, ';');
+ break;
+ case DataType::DOUBLE:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_DOUBLE, ';');
+ break;
+ case DataType::LONGVARCHAR:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_MEMO, ';');
+ break;
+ case DataType::LONGVARBINARY:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_IMAGE, ';');
+ break;
+ case DataType::DATE:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_DATE, ';');
+ break;
+ case DataType::TIME:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_TIME, ';');
+ break;
+ case DataType::TIMESTAMP:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_DATETIME, ';');
+ break;
+ case DataType::BIT:
+ if ( !pInfo->aCreateParams.isEmpty() )
+ {
+ aName = o3tl::getToken(_rsTypeNames, TYPE_BIT, ';');
+ break;
+ }
+ [[fallthrough]];
+ case DataType::BOOLEAN:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_BOOL, ';');
+ break;
+ case DataType::TINYINT:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_TINYINT, ';');
+ break;
+ case DataType::SMALLINT:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_SMALLINT, ';');
+ break;
+ case DataType::INTEGER:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_INTEGER, ';');
+ break;
+ case DataType::REAL:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_REAL, ';');
+ break;
+ case DataType::BINARY:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_BINARY, ';');
+ break;
+ case DataType::VARBINARY:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_VARBINARY, ';');
+ break;
+ case DataType::SQLNULL:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_SQLNULL, ';');
+ break;
+ case DataType::OBJECT:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_OBJECT, ';');
+ break;
+ case DataType::DISTINCT:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_DISTINCT, ';');
+ break;
+ case DataType::STRUCT:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_STRUCT, ';');
+ break;
+ case DataType::ARRAY:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_ARRAY, ';');
+ break;
+ case DataType::BLOB:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_BLOB, ';');
+ break;
+ case DataType::CLOB:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_CLOB, ';');
+ break;
+ case DataType::REF:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_REF, ';');
+ break;
+ case DataType::OTHER:
+ aName = o3tl::getToken(_rsTypeNames, TYPE_OTHER, ';');
+ break;
+ }
+ if ( !aName.empty() )
+ {
+ pInfo->aUIName = aName;
+ pInfo->aUIName += " [ ";
+ }
+ pInfo->aUIName += pInfo->aTypeName;
+ if ( !aName.empty() )
+ pInfo->aUIName += " ]";
+ // Now that we have the type info, save it in the multimap
+ _rTypeInfoMap.emplace(pInfo->nType,pInfo);
+ }
+ // for a faster index access
+ _rTypeInfoIters.reserve(_rTypeInfoMap.size());
+
+ OTypeInfoMap::iterator aIter = _rTypeInfoMap.begin();
+ OTypeInfoMap::const_iterator aEnd = _rTypeInfoMap.end();
+ for(;aIter != aEnd;++aIter)
+ _rTypeInfoIters.push_back(aIter);
+
+ // Close the result set/statement.
+
+ ::comphelper::disposeComponent(xRs);
+}
+
+void setColumnProperties(const Reference<XPropertySet>& _rxColumn,const OFieldDescription* _pFieldDesc)
+{
+ _rxColumn->setPropertyValue(PROPERTY_NAME,Any(_pFieldDesc->GetName()));
+ _rxColumn->setPropertyValue(PROPERTY_TYPENAME,Any(_pFieldDesc->getTypeInfo()->aTypeName));
+ _rxColumn->setPropertyValue(PROPERTY_TYPE,Any(_pFieldDesc->GetType()));
+ _rxColumn->setPropertyValue(PROPERTY_PRECISION,Any(_pFieldDesc->GetPrecision()));
+ _rxColumn->setPropertyValue(PROPERTY_SCALE,Any(_pFieldDesc->GetScale()));
+ _rxColumn->setPropertyValue(PROPERTY_ISNULLABLE, Any(_pFieldDesc->GetIsNullable()));
+ _rxColumn->setPropertyValue(PROPERTY_ISAUTOINCREMENT, css::uno::Any(_pFieldDesc->IsAutoIncrement()));
+ _rxColumn->setPropertyValue(PROPERTY_DESCRIPTION,Any(_pFieldDesc->GetDescription()));
+ if ( _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISCURRENCY) && _pFieldDesc->IsCurrency() )
+ _rxColumn->setPropertyValue(PROPERTY_ISCURRENCY, css::uno::Any(_pFieldDesc->IsCurrency()));
+ // set autoincrement value when available
+ // and only set when the entry is not empty, that lets the value in the column untouched
+ if ( _pFieldDesc->IsAutoIncrement() && !_pFieldDesc->GetAutoIncrementValue().isEmpty() && _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) )
+ _rxColumn->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,Any(_pFieldDesc->GetAutoIncrementValue()));
+}
+
+OUString createDefaultName(const Reference< XDatabaseMetaData>& _xMetaData,const Reference<XNameAccess>& _xTables,const OUString& _sName)
+{
+ OSL_ENSURE(_xMetaData.is(),"No MetaData!");
+ OUString sDefaultName = _sName;
+ try
+ {
+ OUString sCatalog,sSchema,sCompsedName;
+ if(_xMetaData->supportsCatalogsInTableDefinitions())
+ {
+ try
+ {
+ Reference< XConnection> xCon = _xMetaData->getConnection();
+ if ( xCon.is() )
+ sCatalog = xCon->getCatalog();
+ if ( sCatalog.isEmpty() )
+ {
+ Reference<XResultSet> xRes = _xMetaData->getCatalogs();
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ while(xRes.is() && xRes->next())
+ {
+ sCatalog = xRow->getString(1);
+ if(!xRow->wasNull())
+ break;
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ if(_xMetaData->supportsSchemasInTableDefinitions())
+ {
+ sSchema = _xMetaData->getUserName();
+ }
+ sCompsedName = ::dbtools::composeTableName( _xMetaData, sCatalog, sSchema, _sName, false, ::dbtools::EComposeRule::InDataManipulation );
+ sDefaultName = ::dbtools::createUniqueName(_xTables,sCompsedName);
+ }
+ catch(const SQLException&)
+ {
+ }
+ return sDefaultName;
+}
+
+bool checkDataSourceAvailable(const OUString& _sDataSourceName,const Reference< css::uno::XComponentContext >& _xContext)
+{
+ Reference< XDatabaseContext > xDataBaseContext = DatabaseContext::create(_xContext);
+ bool bRet = xDataBaseContext->hasByName(_sDataSourceName);
+ if ( !bRet )
+ { // try if this one is a URL
+ try
+ {
+ bRet = xDataBaseContext->getByName(_sDataSourceName).hasValue();
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ return bRet;
+}
+
+sal_Int32 mapTextAlign(const SvxCellHorJustify& _eAlignment)
+{
+ sal_Int32 nAlignment = css::awt::TextAlign::LEFT;
+ switch (_eAlignment)
+ {
+ case SvxCellHorJustify::Standard:
+ case SvxCellHorJustify::Left: nAlignment = css::awt::TextAlign::LEFT; break;
+ case SvxCellHorJustify::Center: nAlignment = css::awt::TextAlign::CENTER; break;
+ case SvxCellHorJustify::Right: nAlignment = css::awt::TextAlign::RIGHT; break;
+ default:
+ SAL_WARN("dbaccess.ui", "Invalid TextAlign!");
+ }
+ return nAlignment;
+}
+
+SvxCellHorJustify mapTextJustify(sal_Int32 _nAlignment)
+{
+ SvxCellHorJustify eJustify = SvxCellHorJustify::Left;
+ switch (_nAlignment)
+ {
+ case css::awt::TextAlign::LEFT : eJustify = SvxCellHorJustify::Left; break;
+ case css::awt::TextAlign::CENTER : eJustify = SvxCellHorJustify::Center; break;
+ case css::awt::TextAlign::RIGHT : eJustify = SvxCellHorJustify::Right; break;
+ default:
+ SAL_WARN("dbaccess.ui", "Invalid TextAlign!");
+ }
+ return eJustify;
+}
+
+void callColumnFormatDialog(const Reference<XPropertySet>& xAffectedCol,
+ const Reference<XPropertySet>& xField,
+ SvNumberFormatter* _pFormatter,
+ weld::Widget* _pParent)
+{
+ if (!(xAffectedCol.is() && xField.is()))
+ return;
+
+ try
+ {
+ Reference< XPropertySetInfo > xInfo = xAffectedCol->getPropertySetInfo();
+ bool bHasFormat = xInfo->hasPropertyByName(PROPERTY_FORMATKEY);
+ sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(PROPERTY_TYPE));
+
+ SvxCellHorJustify eJustify(SvxCellHorJustify::Standard);
+ Any aAlignment = xAffectedCol->getPropertyValue(PROPERTY_ALIGN);
+ if (aAlignment.hasValue())
+ eJustify = dbaui::mapTextJustify(::comphelper::getINT16(aAlignment));
+ sal_Int32 nFormatKey = 0;
+ if ( bHasFormat )
+ nFormatKey = ::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY));
+
+ if(callColumnFormatDialog(_pParent,_pFormatter,nDataType,nFormatKey,eJustify,bHasFormat))
+ {
+ xAffectedCol->setPropertyValue(PROPERTY_ALIGN, Any(static_cast<sal_Int16>(dbaui::mapTextAlign(eJustify))));
+ if (bHasFormat)
+ xAffectedCol->setPropertyValue(PROPERTY_FORMATKEY, Any(nFormatKey));
+
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+bool callColumnFormatDialog(weld::Widget* _pParent,
+ SvNumberFormatter* _pFormatter,
+ sal_Int32 _nDataType,
+ sal_Int32& _nFormatKey,
+ SvxCellHorJustify& _eJustify,
+ bool _bHasFormat)
+{
+ bool bRet = false;
+
+ // UNO->ItemSet
+ static SfxItemInfo aItemInfos[] =
+ {
+ { 0, false },
+ { SID_ATTR_NUMBERFORMAT_VALUE, true },
+ { SID_ATTR_ALIGN_HOR_JUSTIFY, true },
+ { SID_ATTR_NUMBERFORMAT_INFO, true },
+ { SID_ATTR_NUMBERFORMAT_ONE_AREA, true }
+ };
+ static const auto aAttrMap = svl::Items<
+ SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY,
+ SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO,
+ SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA
+ >;
+
+ std::vector<SfxPoolItem*> pDefaults
+ {
+ new SfxRangeItem(SBA_DEF_RANGEFORMAT, SBA_DEF_FMTVALUE, SBA_ATTR_ALIGN_HOR_JUSTIFY),
+ new SfxUInt32Item(SBA_DEF_FMTVALUE),
+ new SvxHorJustifyItem(SvxCellHorJustify::Standard, SBA_ATTR_ALIGN_HOR_JUSTIFY),
+ new SvxNumberInfoItem(SID_ATTR_NUMBERFORMAT_INFO),
+ new SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, false)
+ };
+
+ rtl::Reference<SfxItemPool> pPool(new SfxItemPool("GridBrowserProperties", SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, aItemInfos, &pDefaults));
+ pPool->SetDefaultMetric( MapUnit::MapTwip ); // ripped, don't understand why
+ pPool->FreezeIdRanges(); // the same
+
+ std::optional<SfxItemSet> pFormatDescriptor(SfxItemSet(*pPool, aAttrMap));
+ // fill it
+ pFormatDescriptor->Put(SvxHorJustifyItem(_eJustify, SBA_ATTR_ALIGN_HOR_JUSTIFY));
+ bool bText = false;
+ if (_bHasFormat)
+ {
+ // if the col is bound to a text field we have to disallow all non-text formats
+ if ((DataType::CHAR == _nDataType) || (DataType::VARCHAR == _nDataType) || (DataType::LONGVARCHAR == _nDataType) || (DataType::CLOB == _nDataType))
+ {
+ bText = true;
+ pFormatDescriptor->Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, true));
+ if (!_pFormatter->IsTextFormat(_nFormatKey))
+ // text fields can only have text formats
+ _nFormatKey = _pFormatter->GetStandardFormat(SvNumFormatType::TEXT, Application::GetSettings().GetLanguageTag().getLanguageType());
+ }
+
+ pFormatDescriptor->Put(SfxUInt32Item(SBA_DEF_FMTVALUE, _nFormatKey));
+ }
+
+ if (!bText)
+ {
+ SvxNumberInfoItem aFormatter(_pFormatter, 1234.56789, SID_ATTR_NUMBERFORMAT_INFO);
+ pFormatDescriptor->Put(aFormatter);
+ }
+
+ { // want the dialog to be destroyed before our set
+ SbaSbAttrDlg aDlg(_pParent, &*pFormatDescriptor, _pFormatter, _bHasFormat);
+ if (RET_OK == aDlg.run())
+ {
+ // ItemSet->UNO
+ // UNO-properties
+ const SfxItemSet* pSet = aDlg.GetExampleSet();
+ // (of course we could put the modified items directly into the column, but then the UNO-model
+ // won't reflect these changes, and why do we have a model, then ?)
+
+ // horizontal justify
+ const SvxHorJustifyItem* pHorJustify = pSet->GetItem<SvxHorJustifyItem>(SBA_ATTR_ALIGN_HOR_JUSTIFY);
+
+ _eJustify = pHorJustify->GetValue();
+
+ // format key
+ if (_bHasFormat)
+ {
+ const SfxUInt32Item* pFormat = pSet->GetItem<SfxUInt32Item>(SBA_DEF_FMTVALUE);
+ _nFormatKey = static_cast<sal_Int32>(pFormat->GetValue());
+ }
+ bRet = true;
+ }
+ // deleted formats
+ const SfxItemSet* pResult = aDlg.GetOutputItemSet();
+ if (pResult)
+ {
+ const SfxPoolItem* pItem = pResult->GetItem( SID_ATTR_NUMBERFORMAT_INFO );
+ const SvxNumberInfoItem* pInfoItem = static_cast<const SvxNumberInfoItem*>(pItem);
+ if (pInfoItem)
+ {
+ for (sal_uInt32 key : pInfoItem->GetDelFormats())
+ _pFormatter->DeleteEntry(key);
+ }
+ }
+ }
+
+ pFormatDescriptor.reset();
+ pPool.clear();
+ for (SfxPoolItem* pDefault : pDefaults)
+ delete pDefault;
+
+ return bRet;
+}
+
+std::shared_ptr<const SfxFilter> getStandardDatabaseFilter()
+{
+ std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)");
+ OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!");
+ return pFilter;
+}
+
+bool appendToFilter(const Reference<XConnection>& _xConnection,
+ const OUString& _sName,
+ const Reference< XComponentContext >& _rxContext,
+ weld::Window* pParent)
+{
+ bool bRet = false;
+ Reference< XChild> xChild(_xConnection,UNO_QUERY);
+ if(xChild.is())
+ {
+ Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY);
+ if(xProp.is())
+ {
+ Sequence< OUString > aFilter;
+ xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= aFilter;
+ // first check if we have something like SCHEMA.%
+ bool bHasToInsert = true;
+ for (const OUString& rItem : std::as_const(aFilter))
+ {
+ if(rItem.indexOf('%') != -1)
+ {
+ sal_Int32 nLen = rItem.lastIndexOf('.');
+ if(nLen != -1 && !rItem.compareTo(_sName,nLen))
+ bHasToInsert = false;
+ else if(rItem.getLength() == 1)
+ bHasToInsert = false;
+ }
+ }
+
+ bRet = true;
+ if(bHasToInsert)
+ {
+ if(! ::dbaui::checkDataSourceAvailable(::comphelper::getString(xProp->getPropertyValue(PROPERTY_NAME)),_rxContext))
+ {
+ OUString aMessage(DBA_RES(STR_TABLEDESIGN_DATASOURCE_DELETED));
+ OSQLWarningBox aWarning(pParent, aMessage);
+ aWarning.run();
+ bRet = false;
+ }
+ else
+ {
+ aFilter.realloc(aFilter.getLength()+1);
+ aFilter.getArray()[aFilter.getLength()-1] = _sName;
+ xProp->setPropertyValue(PROPERTY_TABLEFILTER,Any(aFilter));
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+void notifySystemWindow(vcl::Window const * _pWindow, vcl::Window* _pToRegister, const ::comphelper::mem_fun1_t<TaskPaneList,vcl::Window*>& _rMemFunc)
+{
+ OSL_ENSURE(_pWindow,"Window can not be null!");
+ SystemWindow* pSystemWindow = _pWindow ? _pWindow->GetSystemWindow() : nullptr;
+ if ( pSystemWindow )
+ {
+ _rMemFunc( pSystemWindow->GetTaskPaneList(), _pToRegister );
+ }
+}
+
+void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId )
+{
+ sal_Int32 nColSize = -1;
+ sal_uInt32 nDefaultWidth = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) );
+ if ( nDefaultWidth != _pBox->GetColumnWidth( _nColId ) )
+ {
+ Size aSizeMM = _pBox->PixelToLogic( Size( _pBox->GetColumnWidth( _nColId ), 0 ), MapMode( MapUnit::MapMM ) );
+ nColSize = aSizeMM.Width() * 10;
+ }
+
+ Size aDefaultMM = _pBox->PixelToLogic( Size( nDefaultWidth, 0 ), MapMode( MapUnit::MapMM ) );
+
+ DlgSize aColumnSizeDlg(_pBox->GetFrameWeld(), nColSize, false, aDefaultMM.Width() * 10);
+ if (aColumnSizeDlg.run() != RET_OK)
+ return;
+
+ sal_Int32 nValue = aColumnSizeDlg.GetValue();
+ if ( -1 == nValue )
+ { // default width
+ nValue = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) );
+ }
+ else
+ {
+ Size aSizeMM( nValue / 10, 0 );
+ nValue = _pBox->LogicToPixel( aSizeMM, MapMode( MapUnit::MapMM ) ).Width();
+ }
+ _pBox->SetColumnWidth( _nColId, nValue );
+}
+
+// check if SQL92 name checking is enabled
+bool isSQL92CheckEnabled(const Reference<XConnection>& _xConnection)
+{
+ return ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_ENABLESQL92CHECK );
+}
+
+bool isAppendTableAliasEnabled(const Reference<XConnection>& _xConnection)
+{
+ return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_APPEND_TABLE_ALIAS );
+}
+
+bool generateAsBeforeTableAlias(const Reference<XConnection>& _xConnection)
+{
+ return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_AS_BEFORE_CORRELATION_NAME );
+}
+
+void fillAutoIncrementValue(const Reference<XPropertySet>& _xDatasource,
+ bool& _rAutoIncrementValueEnabled,
+ OUString& _rsAutoIncrementValue)
+{
+ if ( !_xDatasource.is() )
+ return;
+
+ OSL_ENSURE(_xDatasource->getPropertySetInfo()->hasPropertyByName(PROPERTY_INFO),"NO datasource supplied!");
+ Sequence<PropertyValue> aInfo;
+ _xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo;
+
+ // search the right propertyvalue
+ const PropertyValue* pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo),
+ [](const PropertyValue& lhs)
+ {return lhs.Name == PROPERTY_AUTOINCREMENTCREATION;} );
+
+ if ( pValue != std::cend(aInfo) )
+ pValue->Value >>= _rsAutoIncrementValue;
+ pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo),
+ [](const PropertyValue& lhs)
+ {return lhs.Name == "IsAutoRetrievingEnabled";} );
+
+ if ( pValue != std::cend(aInfo) )
+ pValue->Value >>= _rAutoIncrementValueEnabled;
+}
+
+void fillAutoIncrementValue(const Reference<XConnection>& _xConnection,
+ bool& _rAutoIncrementValueEnabled,
+ OUString& _rsAutoIncrementValue)
+{
+ Reference< XChild> xChild(_xConnection,UNO_QUERY);
+ if(xChild.is())
+ {
+ Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY);
+ fillAutoIncrementValue(xProp,_rAutoIncrementValueEnabled,_rsAutoIncrementValue);
+ }
+}
+
+OUString getStrippedDatabaseName(const Reference<XPropertySet>& _xDataSource,OUString& _rsDatabaseName)
+{
+ if ( _rsDatabaseName.isEmpty() && _xDataSource.is() )
+ {
+ try
+ {
+ _xDataSource->getPropertyValue(PROPERTY_NAME) >>= _rsDatabaseName;
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ OUString sName = _rsDatabaseName;
+ INetURLObject aURL(sName);
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ sName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::Unambiguous);
+ return sName;
+}
+
+void setEvalDateFormatForFormatter(Reference< css::util::XNumberFormatter > const & _rxFormatter)
+{
+ OSL_ENSURE( _rxFormatter.is(),"setEvalDateFormatForFormatter: Formatter is NULL!");
+ if ( !_rxFormatter.is() )
+ return;
+
+ Reference< css::util::XNumberFormatsSupplier > xSupplier = _rxFormatter->getNumberFormatsSupplier();
+
+ auto pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xSupplier);
+ OSL_ENSURE(pSupplierImpl,"No Supplier!");
+
+ if ( pSupplierImpl )
+ {
+ SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter();
+ pFormatter->SetEvalDateFormat(NF_EVALDATEFORMAT_FORMAT);
+ }
+}
+
+TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo)
+{
+ TOTypeInfoSP pTypeInfo;
+ // first we search for a type which supports autoIncrement
+ for (auto const& elem : _rTypeInfo)
+ {
+ // OJ: we don't want to set an autoincrement column to be key
+ // because we don't have the possibility to know how to create
+ // such auto increment column later on
+ // so until we know how to do it, we create a column without autoincrement
+ // therefore we have searched
+ if ( elem.second->nType == DataType::INTEGER )
+ {
+ pTypeInfo = elem.second; // alternative
+ break;
+ }
+ else if ( !pTypeInfo && elem.second->nType == DataType::DOUBLE )
+ pTypeInfo = elem.second; // alternative
+ else if ( !pTypeInfo && elem.second->nType == DataType::REAL )
+ pTypeInfo = elem.second; // alternative
+ }
+ if ( !pTypeInfo ) // just a fallback
+ pTypeInfo = queryTypeInfoByType(DataType::VARCHAR,_rTypeInfo);
+
+ OSL_ENSURE(pTypeInfo,"checkColumns: can't find a type which is usable as a key!");
+ return pTypeInfo;
+}
+
+TOTypeInfoSP queryTypeInfoByType(sal_Int32 _nDataType,const OTypeInfoMap& _rTypeInfo)
+{
+ OTypeInfoMap::const_iterator aIter = _rTypeInfo.find(_nDataType);
+ if(aIter != _rTypeInfo.end())
+ return aIter->second;
+ // fall back if the type is unknown
+ TOTypeInfoSP pTypeInfo;
+ switch(_nDataType)
+ {
+ case DataType::TINYINT:
+ if( (pTypeInfo = queryTypeInfoByType(DataType::SMALLINT,_rTypeInfo) ) )
+ break;
+ [[fallthrough]];
+ case DataType::SMALLINT:
+ if( (pTypeInfo = queryTypeInfoByType(DataType::INTEGER,_rTypeInfo) ) )
+ break;
+ [[fallthrough]];
+ case DataType::INTEGER:
+ if( (pTypeInfo = queryTypeInfoByType(DataType::FLOAT,_rTypeInfo) ) )
+ break;
+ [[fallthrough]];
+ case DataType::FLOAT:
+ if( (pTypeInfo = queryTypeInfoByType(DataType::REAL,_rTypeInfo) ) )
+ break;
+ [[fallthrough]];
+ case DataType::DATE:
+ case DataType::TIME:
+ if( DataType::DATE == _nDataType || DataType::TIME == _nDataType )
+ {
+ if( (pTypeInfo = queryTypeInfoByType(DataType::TIMESTAMP,_rTypeInfo) ) )
+ break;
+ }
+ [[fallthrough]];
+ case DataType::TIMESTAMP:
+ case DataType::REAL:
+ case DataType::BIGINT:
+ if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) )
+ break;
+ [[fallthrough]];
+ case DataType::DOUBLE:
+ if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) )
+ break;
+ [[fallthrough]];
+ case DataType::NUMERIC:
+ pTypeInfo = queryTypeInfoByType(DataType::DECIMAL,_rTypeInfo);
+ break;
+ case DataType::DECIMAL:
+ if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) )
+ break;
+ if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) )
+ break;
+ break;
+ case DataType::VARCHAR:
+ if ( (pTypeInfo = queryTypeInfoByType(DataType::LONGVARCHAR,_rTypeInfo) ) )
+ break;
+ break;
+ case DataType::LONGVARCHAR:
+ if ( (pTypeInfo = queryTypeInfoByType(DataType::CLOB,_rTypeInfo) ) )
+ break;
+ break;
+ default:
+ ;
+ }
+ if ( !pTypeInfo )
+ {
+ bool bForce = true;
+ pTypeInfo = ::dbaui::getTypeInfoFromType(_rTypeInfo,DataType::VARCHAR,OUString(),"x",50,0,false,bForce);
+ }
+ OSL_ENSURE(pTypeInfo,"Wrong DataType supplied!");
+ return pTypeInfo;
+}
+
+sal_Int32 askForUserAction(weld::Window* pParent, TranslateId pTitle, TranslateId pText, bool _bAll, std::u16string_view _sName)
+{
+ SolarMutexGuard aGuard;
+ OUString aMsg = DBA_RES(pText);
+ aMsg = aMsg.replaceFirst("%1", _sName);
+ OSQLMessageBox aAsk(pParent, DBA_RES(pTitle), aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, MessageType::Query);
+ if ( _bAll )
+ {
+ aAsk.add_button(DBA_RES(STR_BUTTON_TEXT_ALL), RET_ALL, HID_CONFIRM_DROP_BUTTON_ALL);
+ }
+ return aAsk.run();
+}
+
+namespace
+{
+ OUString lcl_createSDBCLevelStatement( const OUString& _rStatement, const Reference< XConnection >& _rxConnection )
+ {
+ OUString sSDBCLevelStatement( _rStatement );
+ try
+ {
+ Reference< XMultiServiceFactory > xAnalyzerFactory( _rxConnection, UNO_QUERY_THROW );
+ Reference< XSingleSelectQueryAnalyzer > xAnalyzer( xAnalyzerFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+ xAnalyzer->setQuery( _rStatement );
+ sSDBCLevelStatement = xAnalyzer->getQueryWithSubstitution();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sSDBCLevelStatement;
+ }
+}
+
+Reference< XPropertySet > createView( const OUString& _rName, const Reference< XConnection >& _rxConnection,
+ const OUString& _rCommand )
+{
+ Reference<XViewsSupplier> xSup(_rxConnection,UNO_QUERY);
+ Reference< XNameAccess > xViews;
+ if(xSup.is())
+ xViews = xSup->getViews();
+ Reference<XDataDescriptorFactory> xFact(xViews,UNO_QUERY);
+ OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!");
+ if(!xFact.is())
+ return nullptr;
+
+ Reference<XPropertySet> xView = xFact->createDataDescriptor();
+ if ( !xView.is() )
+ return nullptr;
+
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(_rxConnection->getMetaData(),
+ _rName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ xView->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog));
+ xView->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema));
+ xView->setPropertyValue(PROPERTY_NAME,Any(sTable));
+
+ xView->setPropertyValue( PROPERTY_COMMAND, Any( _rCommand ) );
+
+ Reference<XAppend> xAppend(xViews,UNO_QUERY);
+ if(xAppend.is())
+ xAppend->appendByDescriptor(xView);
+
+ xView = nullptr;
+ // we need to reget the view because after appending it, it is no longer valid
+ // but this time it isn't a view object it is a table object with type "VIEW"
+ Reference<XTablesSupplier> xTabSup(_rxConnection,UNO_QUERY);
+ Reference< XNameAccess > xTables;
+ if ( xTabSup.is() )
+ {
+ xTables = xTabSup->getTables();
+ if ( xTables.is() && xTables->hasByName( _rName ) )
+ xTables->getByName( _rName ) >>= xView;
+ }
+
+ return xView;
+}
+
+Reference<XPropertySet> createView( const OUString& _rName, const Reference< XConnection >& _rxConnection
+ ,const Reference<XPropertySet>& _rxSourceObject)
+{
+ OUString sCommand;
+ Reference< XPropertySetInfo > xPSI( _rxSourceObject->getPropertySetInfo(), UNO_SET_THROW );
+ if ( xPSI->hasPropertyByName( PROPERTY_COMMAND ) )
+ {
+ _rxSourceObject->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand;
+
+ bool bEscapeProcessing( false );
+ OSL_VERIFY( _rxSourceObject->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
+ if ( bEscapeProcessing )
+ sCommand = lcl_createSDBCLevelStatement( sCommand, _rxConnection );
+ }
+ else
+ {
+ sCommand = "SELECT * FROM " + composeTableNameForSelect( _rxConnection, _rxSourceObject );
+ }
+ return createView( _rName, _rxConnection, sCommand );
+}
+
+bool insertHierarchyElement(weld::Window* pParent, const Reference< XComponentContext >& _rxContext,
+ const Reference<XHierarchicalNameContainer>& _xNames,
+ const OUString& _sParentFolder,
+ bool _bForm,
+ bool _bCollection,
+ const Reference<XContent>& _xContent,
+ bool _bMove)
+{
+ OSL_ENSURE( _xNames.is(), "insertHierarchyElement: illegal name container!" );
+ if ( !_xNames.is() )
+ return false;
+
+ Reference<XNameAccess> xNameAccess( _xNames, UNO_QUERY );
+ if ( _xNames->hasByHierarchicalName(_sParentFolder) )
+ {
+ Reference<XChild> xChild(_xNames->getByHierarchicalName(_sParentFolder),UNO_QUERY);
+ xNameAccess.set(xChild,UNO_QUERY);
+ if ( !xNameAccess.is() && xChild.is() )
+ xNameAccess.set(xChild->getParent(),UNO_QUERY);
+ }
+
+ OSL_ENSURE( xNameAccess.is(), "insertHierarchyElement: could not find the proper name container!" );
+ if ( !xNameAccess.is() )
+ return false;
+
+ OUString sNewName;
+ Reference<XPropertySet> xProp(_xContent,UNO_QUERY);
+ if ( xProp.is() )
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sNewName;
+
+ if ( !_bMove || sNewName.isEmpty() )
+ {
+ if ( sNewName.isEmpty() || xNameAccess->hasByName(sNewName) )
+ {
+ OUString sLabel, sTargetName;
+ if ( !sNewName.isEmpty() )
+ sTargetName = sNewName;
+ else
+ sTargetName = DBA_RES( _bCollection ? STR_NEW_FOLDER : ((_bForm) ? RID_STR_FORM : RID_STR_REPORT));
+ sLabel = DBA_RES( _bCollection ? STR_FOLDER_LABEL : ((_bForm) ? STR_FRM_LABEL : STR_RPT_LABEL));
+ sTargetName = ::dbtools::createUniqueName(xNameAccess,sTargetName);
+
+ // here we have everything needed to create a new query object ...
+ HierarchicalNameCheck aNameChecker( _xNames, _sParentFolder );
+ // ... ehm, except a new name
+ OSaveAsDlg aAskForName(pParent,
+ _rxContext,
+ sTargetName,
+ sLabel,
+ aNameChecker,
+ SADFlags::AdditionalDescription | SADFlags::TitlePasteAs);
+ if ( RET_OK != aAskForName.run() )
+ // cancelled by the user
+ return false;
+
+ sNewName = aAskForName.getName();
+ }
+ }
+ else if ( xNameAccess->hasByName(sNewName) )
+ {
+ OUString sError(DBA_RES(STR_NAME_ALREADY_EXISTS));
+ sError = sError.replaceFirst("#",sNewName);
+ throw SQLException(sError,nullptr,"S1000",0,Any());
+ }
+
+ try
+ {
+ Reference<XMultiServiceFactory> xORB( xNameAccess, UNO_QUERY_THROW );
+ uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"Name", uno::Any(sNewName)}, // set as folder
+ {"Parent", uno::Any(xNameAccess)},
+ {PROPERTY_EMBEDDEDOBJECT, uno::Any(_xContent)},
+ }));
+ OUString sServiceName(_bCollection ? (_bForm ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION)) : OUString(SERVICE_SDB_DOCUMENTDEFINITION));
+
+ Reference<XContent > xNew( xORB->createInstanceWithArguments( sServiceName, aArguments ), UNO_QUERY_THROW );
+ Reference< XNameContainer > xNameContainer( xNameAccess, UNO_QUERY_THROW );
+ xNameContainer->insertByName( sNewName, Any( xNew ) );
+ }
+ catch( const IllegalArgumentException& e )
+ {
+ ::dbtools::throwGenericSQLException( e.Message, e.Context );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ return false;
+ }
+
+ return true;
+}
+
+Reference< XNumberFormatter > getNumberFormatter(const Reference< XConnection >& _rxConnection, const Reference< css::uno::XComponentContext >& _rxContext )
+{
+ // create a formatter working with the connections format supplier
+ Reference< XNumberFormatter > xFormatter;
+
+ try
+ {
+ Reference< css::util::XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(_rxConnection, true, _rxContext));
+
+ if ( xSupplier.is() )
+ {
+ // create a new formatter
+ xFormatter.set(util::NumberFormatter::create( _rxContext ), UNO_QUERY_THROW);
+ xFormatter->attachNumberFormatsSupplier(xSupplier);
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xFormatter;
+}
+
+} // dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/UpdateHelperImpl.hxx b/dbaccess/source/ui/misc/UpdateHelperImpl.hxx
new file mode 100644
index 000000000..9f8d0d399
--- /dev/null
+++ b/dbaccess/source/ui/misc/UpdateHelperImpl.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <IUpdateHelper.hxx>
+
+namespace dbaui
+{
+ class OParameterUpdateHelper : public IUpdateHelper
+ {
+ css::uno::Reference< css::sdbc::XPreparedStatement > m_xPrepared;
+ css::uno::Reference< css::sdbc::XParameters > m_xParameters;
+
+ public:
+ explicit OParameterUpdateHelper(const css::uno::Reference< css::sdbc::XPreparedStatement >& _xPrepared)
+ :m_xPrepared(_xPrepared)
+ ,m_xParameters(_xPrepared,css::uno::UNO_QUERY)
+ {
+ }
+ virtual ~OParameterUpdateHelper() {}
+ virtual void updateString(sal_Int32 _nPos, const OUString& _sValue) override
+ {
+ m_xParameters->setString(_nPos, _sValue);
+ }
+ virtual void updateDouble(sal_Int32 _nPos,const double& _nValue) override
+ {
+ m_xParameters->setDouble(_nPos, _nValue);
+ }
+ virtual void updateDate(sal_Int32 _nPos,const css::util::Date& _nValue) override
+ {
+ m_xParameters->setDate(_nPos, _nValue);
+ }
+ virtual void updateTime(sal_Int32 _nPos,const css::util::Time& _nValue) override
+ {
+ m_xParameters->setTime(_nPos, _nValue);
+ }
+ virtual void updateTimestamp(sal_Int32 _nPos,const css::util::DateTime& _nValue) override
+ {
+ m_xParameters->setTimestamp(_nPos, _nValue);
+ }
+ virtual void updateInt(sal_Int32 _nPos, sal_Int32 _nValue) override
+ {
+ m_xParameters->setInt(_nPos, _nValue);
+ }
+ virtual void updateNull(sal_Int32 _nPos, ::sal_Int32 sqlType) override
+ {
+ m_xParameters->setNull(_nPos,sqlType);
+ }
+ virtual void insertRow() override
+ {
+ m_xPrepared->executeUpdate();
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/WCPage.cxx b/dbaccess/source/ui/misc/WCPage.cxx
new file mode 100644
index 000000000..602edd2d6
--- /dev/null
+++ b/dbaccess/source/ui/misc/WCPage.cxx
@@ -0,0 +1,325 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <WCPage.hxx>
+#include <WCopyTable.hxx>
+
+#include <defaultobjectnamecheck.hxx>
+#include <strings.hrc>
+#include <core_resource.hxx>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+
+using namespace ::dbaui;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+
+namespace CopyTableOperation = css::sdb::application::CopyTableOperation;
+
+OCopyTable::OCopyTable(weld::Container* pPage, OCopyTableWizard* pWizard)
+ : OWizardPage(pPage, pWizard, "dbaccess/ui/copytablepage.ui", "CopyTablePage")
+ , m_bPKeyAllowed(false)
+ , m_bUseHeaderAllowed(true)
+ , m_nOldOperation(0)
+ , m_xEdTableName(m_xBuilder->weld_entry("name"))
+ , m_xRB_DefData(m_xBuilder->weld_radio_button("defdata"))
+ , m_xRB_Def(m_xBuilder->weld_radio_button("def"))
+ , m_xRB_View(m_xBuilder->weld_radio_button("view"))
+ , m_xRB_AppendData(m_xBuilder->weld_radio_button("data"))
+ , m_xCB_UseHeaderLine(m_xBuilder->weld_check_button("firstline"))
+ , m_xCB_PrimaryColumn(m_xBuilder->weld_check_button("primarykey"))
+ , m_xFT_KeyName(m_xBuilder->weld_label("keynamelabel"))
+ , m_xEdKeyName(m_xBuilder->weld_entry("keyname"))
+{
+ if ( m_pParent->m_xDestConnection.is() )
+ {
+ if (!m_pParent->supportsViews())
+ m_xRB_View->set_sensitive(false);
+
+ m_xCB_UseHeaderLine->set_active(true);
+ m_bPKeyAllowed = m_pParent->supportsPrimaryKey();
+
+ m_xCB_PrimaryColumn->set_sensitive(m_bPKeyAllowed);
+
+ m_xRB_AppendData->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) );
+ m_xRB_DefData->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) );
+ m_xRB_Def->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) );
+ m_xRB_View->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) );
+
+ m_xCB_PrimaryColumn->connect_toggled(LINK( this, OCopyTable, KeyClickHdl ) );
+
+ m_xFT_KeyName->set_sensitive(false);
+ m_xEdKeyName->set_sensitive(false);
+ m_xEdKeyName->set_text(m_pParent->createUniqueName("ID"));
+
+ const sal_Int32 nMaxLen = m_pParent->getMaxColumnNameLength();
+ m_xEdKeyName->set_max_length(nMaxLen);
+ }
+
+ SetPageTitle(DBA_RES(STR_COPYTABLE_TITLE_COPY));
+}
+
+OCopyTable::~OCopyTable()
+{
+}
+
+void OCopyTable::SetAppendDataRadio()
+{
+ m_pParent->EnableNextButton(true);
+ m_xFT_KeyName->set_sensitive(false);
+ m_xCB_PrimaryColumn->set_sensitive(false);
+ m_xEdKeyName->set_sensitive(false);
+ m_pParent->setOperation(CopyTableOperation::AppendData);
+}
+
+IMPL_LINK(OCopyTable, RadioChangeHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+ if (m_xRB_AppendData->get_active())
+ {
+ SetAppendDataRadio();
+ return;
+ }
+ m_pParent->EnableNextButton(!m_xRB_View->get_active());
+ bool bKey = m_bPKeyAllowed && !m_xRB_View->get_active();
+ m_xFT_KeyName->set_sensitive(bKey && m_xCB_PrimaryColumn->get_active());
+ m_xEdKeyName->set_sensitive(bKey && m_xCB_PrimaryColumn->get_active());
+ m_xCB_PrimaryColumn->set_sensitive(bKey);
+ m_xCB_UseHeaderLine->set_sensitive(m_bUseHeaderAllowed && IsOptionDefData());
+
+ // set type what to do
+ if( IsOptionDefData() )
+ m_pParent->setOperation( CopyTableOperation::CopyDefinitionAndData );
+ else if( IsOptionDef() )
+ m_pParent->setOperation( CopyTableOperation::CopyDefinitionOnly );
+ else if( IsOptionView() )
+ m_pParent->setOperation( CopyTableOperation::CreateAsView );
+}
+
+IMPL_LINK_NOARG( OCopyTable, KeyClickHdl, weld::Toggleable&, void )
+{
+ m_xEdKeyName->set_sensitive(m_xCB_PrimaryColumn->get_active());
+ m_xFT_KeyName->set_sensitive(m_xCB_PrimaryColumn->get_active());
+}
+
+bool OCopyTable::LeavePage()
+{
+ m_pParent->m_bCreatePrimaryKeyColumn = m_bPKeyAllowed && m_xCB_PrimaryColumn->get_sensitive() && m_xCB_PrimaryColumn->get_active();
+ m_pParent->m_aKeyName = m_pParent->m_bCreatePrimaryKeyColumn ? m_xEdKeyName->get_text() : OUString();
+ m_pParent->setUseHeaderLine( m_xCB_UseHeaderLine->get_active() );
+
+ // first check if the table already exists in the database
+ if( m_pParent->getOperation() != CopyTableOperation::AppendData )
+ {
+ m_pParent->clearDestColumns();
+ DynamicTableOrQueryNameCheck aNameCheck( m_pParent->m_xDestConnection, CommandType::TABLE );
+ SQLExceptionInfo aErrorInfo;
+ if ( !aNameCheck.isNameValid( m_xEdTableName->get_text(), aErrorInfo ) )
+ {
+ aErrorInfo.append( SQLExceptionInfo::TYPE::SQLContext, DBA_RES( STR_SUGGEST_APPEND_TABLE_DATA ) );
+ m_pParent->showError(aErrorInfo.get());
+
+ return false;
+ }
+
+ // have to check the length of the table name
+ Reference< XDatabaseMetaData > xMeta = m_pParent->m_xDestConnection->getMetaData();
+ OUString sCatalog;
+ OUString sSchema;
+ OUString sTable;
+ ::dbtools::qualifiedNameComponents( xMeta,
+ m_xEdTableName->get_text(),
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ sal_Int32 nMaxLength = xMeta->getMaxTableNameLength();
+ if ( nMaxLength && sTable.getLength() > nMaxLength )
+ {
+ m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME_LENGTH));
+ return false;
+ }
+
+ // now we have to check if the name of the primary key already exists
+ if ( m_pParent->m_bCreatePrimaryKeyColumn
+ && m_pParent->m_aKeyName != m_pParent->createUniqueName(m_pParent->m_aKeyName) )
+ {
+ m_pParent->showError(DBA_RES(STR_WIZ_NAME_ALREADY_DEFINED) + " " + m_pParent->m_aKeyName);
+ return false;
+ }
+ }
+
+ if (m_xEdTableName->get_value_changed_from_saved())
+ { // table exists and name has changed
+ if ( m_pParent->getOperation() == CopyTableOperation::AppendData )
+ {
+ if(!checkAppendData())
+ return false;
+ }
+ else if ( m_nOldOperation == CopyTableOperation::AppendData )
+ {
+ m_xEdTableName->save_value();
+ return LeavePage();
+ }
+ }
+ else
+ { // table exist and is not new or doesn't exist and so on
+ if ( CopyTableOperation::AppendData == m_pParent->getOperation() )
+ {
+ if( !checkAppendData() )
+ return false;
+ }
+ }
+ m_pParent->m_sName = m_xEdTableName->get_text();
+ m_xEdTableName->save_value();
+
+ if(m_pParent->m_sName.isEmpty())
+ {
+ m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME));
+ return false;
+ }
+
+ return true;
+}
+
+void OCopyTable::Activate()
+{
+ m_pParent->GetOKButton().set_sensitive(true);
+ m_nOldOperation = m_pParent->getOperation();
+ m_xEdTableName->grab_focus();
+ m_xCB_UseHeaderLine->set_active(m_pParent->UseHeaderLine());
+}
+
+OUString OCopyTable::GetTitle() const
+{
+ return DBA_RES(STR_WIZ_TABLE_COPY);
+}
+
+void OCopyTable::Reset()
+{
+ m_bFirstTime = false;
+
+ m_xEdTableName->set_text( m_pParent->m_sName );
+ m_xEdTableName->save_value();
+}
+
+bool OCopyTable::checkAppendData()
+{
+ m_pParent->clearDestColumns();
+ Reference< XPropertySet > xTable;
+ Reference< XTablesSupplier > xSup( m_pParent->m_xDestConnection, UNO_QUERY );
+ Reference<XNameAccess> xTables;
+ if (xSup.is())
+ xTables = xSup->getTables();
+ if (xTables.is() && xTables->hasByName(m_xEdTableName->get_text()))
+ {
+ const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector();
+ const sal_uInt32 nSrcSize = rSrcColumns.size();
+ m_pParent->m_vColumnPositions.resize( nSrcSize, ODatabaseExport::TPositions::value_type( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ) );
+ m_pParent->m_vColumnTypes.resize( nSrcSize , COLUMN_POSITION_NOT_FOUND );
+
+ // set new destination
+ xTables->getByName( m_xEdTableName->get_text() ) >>= xTable;
+ ObjectCopySource aTableCopySource( m_pParent->m_xDestConnection, xTable );
+ m_pParent->loadData( aTableCopySource, m_pParent->m_vDestColumns, m_pParent->m_aDestVec );
+ const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector();
+ const sal_uInt32 nMinSrcDestSize = std::min<sal_uInt32>(nSrcSize, rDestColumns.size());
+ sal_uInt32 i = 0;
+ for (auto const& column : rDestColumns)
+ {
+ if (i >= nMinSrcDestSize)
+ break;
+ bool bNotConvert = true;
+ m_pParent->m_vColumnPositions[i] = ODatabaseExport::TPositions::value_type(i+1,i+1);
+ TOTypeInfoSP pTypeInfo = m_pParent->convertType(column->second->getSpecialTypeInfo(),bNotConvert);
+ if ( !bNotConvert )
+ {
+ m_pParent->showColumnTypeNotSupported(column->first);
+ return false;
+ }
+
+ if ( pTypeInfo )
+ m_pParent->m_vColumnTypes[i] = pTypeInfo->nType;
+ else
+ m_pParent->m_vColumnTypes[i] = DataType::VARCHAR;
+ ++i;
+ }
+
+ }
+
+ if ( !xTable.is() )
+ {
+ m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME));
+ return false;
+ }
+ return true;
+}
+
+void OCopyTable::setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName )
+{
+ bool bCreatePK = m_bPKeyAllowed && _bDoCreate;
+ m_xCB_PrimaryColumn->set_active( bCreatePK );
+ m_xEdKeyName->set_text( _rSuggestedName );
+
+ m_xFT_KeyName->set_sensitive( bCreatePK );
+ m_xEdKeyName->set_sensitive( bCreatePK );
+}
+
+void OCopyTable::setCreateStyleAction()
+{
+ // reselect the last action before
+ switch (m_pParent->getOperation())
+ {
+ case CopyTableOperation::CopyDefinitionAndData:
+ m_xRB_DefData->set_active(true);
+ RadioChangeHdl(*m_xRB_DefData);
+ break;
+ case CopyTableOperation::CopyDefinitionOnly:
+ m_xRB_Def->set_active(true);
+ RadioChangeHdl(*m_xRB_Def);
+ break;
+ case CopyTableOperation::AppendData:
+ m_xRB_AppendData->set_active(true);
+ SetAppendDataRadio();
+ break;
+ case CopyTableOperation::CreateAsView:
+ if (m_xRB_View->get_sensitive())
+ {
+ m_xRB_View->set_active(true);
+ RadioChangeHdl(*m_xRB_View);
+ }
+ else
+ {
+ m_xRB_DefData->set_active(true);
+ RadioChangeHdl(*m_xRB_DefData);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/WColumnSelect.cxx b/dbaccess/source/ui/misc/WColumnSelect.cxx
new file mode 100644
index 000000000..8937cfb2d
--- /dev/null
+++ b/dbaccess/source/ui/misc/WColumnSelect.cxx
@@ -0,0 +1,403 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <WColumnSelect.hxx>
+#include <strings.hrc>
+#include <osl/diagnose.h>
+#include <WCopyTable.hxx>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <core_resource.hxx>
+#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace dbaui;
+
+namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
+
+OUString OWizColumnSelect::GetTitle() const { return DBA_RES(STR_WIZ_COLUMN_SELECT_TITLE); }
+
+OWizardPage::OWizardPage(weld::Container* pPage, OCopyTableWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID)
+ : ::vcl::OWizardPage(pPage, pWizard, rUIXMLDescription, rID)
+ , m_pParent(pWizard)
+ , m_bFirstTime(true)
+{
+}
+
+OWizardPage::~OWizardPage()
+{
+}
+
+// OWizColumnSelect
+OWizColumnSelect::OWizColumnSelect(weld::Container* pPage, OCopyTableWizard* pWizard)
+ : OWizardPage(pPage, pWizard, "dbaccess/ui/applycolpage.ui", "ApplyColPage")
+ , m_xOrgColumnNames(m_xBuilder->weld_tree_view("from"))
+ , m_xColumn_RH(m_xBuilder->weld_button("colrh"))
+ , m_xColumns_RH(m_xBuilder->weld_button("colsrh"))
+ , m_xColumn_LH(m_xBuilder->weld_button("collh"))
+ , m_xColumns_LH(m_xBuilder->weld_button("colslh"))
+ , m_xNewColumnNames(m_xBuilder->weld_tree_view("to"))
+{
+ m_xColumn_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
+ m_xColumn_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
+ m_xColumns_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
+ m_xColumns_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
+
+ m_xOrgColumnNames->set_selection_mode(SelectionMode::Multiple);
+ m_xNewColumnNames->set_selection_mode(SelectionMode::Multiple);
+
+ m_xOrgColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl));
+ m_xNewColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl));
+}
+
+OWizColumnSelect::~OWizColumnSelect()
+{
+ while (m_xNewColumnNames->n_children())
+ {
+ delete weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(0));
+ m_xNewColumnNames->remove(0);
+ }
+}
+
+void OWizColumnSelect::Reset()
+{
+ // restore original state
+ clearListBox(*m_xOrgColumnNames);
+ clearListBox(*m_xNewColumnNames);
+ m_pParent->m_mNameMapping.clear();
+
+ // insert the source columns in the left listbox
+ const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector();
+
+ for (auto const& column : rSrcColumns)
+ {
+ OUString sId(weld::toId(column->second));
+ m_xOrgColumnNames->append(sId, column->first);
+ }
+
+ if (m_xOrgColumnNames->n_children())
+ m_xOrgColumnNames->select(0);
+
+ m_bFirstTime = false;
+}
+
+void OWizColumnSelect::Activate( )
+{
+ // if there are no dest columns reset the left side with the original columns
+ if(m_pParent->getDestColumns().empty())
+ Reset();
+
+ clearListBox(*m_xNewColumnNames);
+
+ const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector();
+
+ // tdf#113923, the added columns must exist in the table
+ // in the case where:
+ // 1: we enabled the creation of a primary key
+ // 2: we come back here from the "Back" button of the next page,
+ // we want to avoid to list the new column generated in the next page
+ const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns();
+
+ for (auto const& column : rDestColumns)
+ {
+ if (rSrcColumns.find(column->first) != rSrcColumns.end())
+ {
+ OUString sId(weld::toId(new OFieldDescription(*(column->second))));
+ m_xNewColumnNames->append(sId, column->first);
+ int nRemove = m_xOrgColumnNames->find_text(column->first);
+ if (nRemove != -1)
+ m_xOrgColumnNames->remove(nRemove);
+ }
+ }
+ m_pParent->GetOKButton().set_sensitive(m_xNewColumnNames->n_children() != 0);
+ m_pParent->EnableNextButton(m_xNewColumnNames->n_children() && m_pParent->getOperation() != CopyTableOperation::AppendData);
+ m_xColumns_RH->grab_focus();
+}
+
+bool OWizColumnSelect::LeavePage()
+{
+
+ m_pParent->clearDestColumns();
+
+ for(sal_Int32 i=0 ; i< m_xNewColumnNames->n_children();++i)
+ {
+ OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(i));
+ OSL_ENSURE(pField,"The field information can not be null!");
+ m_pParent->insertColumn(i,pField);
+ }
+
+ clearListBox(*m_xNewColumnNames);
+
+ if ( m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_NEXT
+ || m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_FINISH
+ )
+ return !m_pParent->getDestColumns().empty();
+ else
+ return true;
+}
+
+IMPL_LINK(OWizColumnSelect, ButtonClickHdl, weld::Button&, rButton, void)
+{
+ weld::TreeView *pLeft = nullptr;
+ weld::TreeView *pRight = nullptr;
+ bool bAll = false;
+
+ if (&rButton == m_xColumn_RH.get())
+ {
+ pLeft = m_xOrgColumnNames.get();
+ pRight = m_xNewColumnNames.get();
+ }
+ else if (&rButton == m_xColumn_LH.get())
+ {
+ pLeft = m_xNewColumnNames.get();
+ pRight = m_xOrgColumnNames.get();
+ }
+ else if (&rButton == m_xColumns_RH.get())
+ {
+ pLeft = m_xOrgColumnNames.get();
+ pRight = m_xNewColumnNames.get();
+ bAll = true;
+ }
+ else if (&rButton == m_xColumns_LH.get())
+ {
+ pLeft = m_xNewColumnNames.get();
+ pRight = m_xOrgColumnNames.get();
+ bAll = true;
+ }
+
+ if (!pLeft || !pRight)
+ return;
+
+ Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() );
+ OUString sExtraChars = xMetaData->getExtraNameCharacters();
+ sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength();
+
+ ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers());
+ std::vector< OUString> aRightColumns;
+ fillColumns(pRight,aRightColumns);
+
+ if(!bAll)
+ {
+ auto aRows = pLeft->get_selected_rows();
+ std::sort(aRows.begin(), aRows.end());
+
+ for (auto it = aRows.begin(); it != aRows.end(); ++it)
+ moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase);
+
+ for (auto it = aRows.rbegin(); it != aRows.rend(); ++it)
+ pLeft->remove(*it);
+ }
+ else
+ {
+ const sal_Int32 nEntries = pLeft->n_children();
+ for(sal_Int32 i=0; i < nEntries; ++i)
+ moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(i),sExtraChars,nMaxNameLen,aCase);
+ for(sal_Int32 j=pLeft->n_children(); j ; )
+ pLeft->remove(--j);
+ }
+
+ enableButtons();
+
+ if (m_xOrgColumnNames->n_children())
+ m_xOrgColumnNames->select(0);
+}
+
+IMPL_LINK( OWizColumnSelect, ListDoubleClickHdl, weld::TreeView&, rListBox, bool )
+{
+ weld::TreeView *pLeft,*pRight;
+ if (&rListBox == m_xOrgColumnNames.get())
+ {
+ pLeft = m_xOrgColumnNames.get();
+ pRight = m_xNewColumnNames.get();
+ }
+ else
+ {
+ pRight = m_xOrgColumnNames.get();
+ pLeft = m_xNewColumnNames.get();
+ }
+
+ // If database is able to process PrimaryKeys, set PrimaryKey
+ Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() );
+ OUString sExtraChars = xMetaData->getExtraNameCharacters();
+ sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength();
+
+ ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers());
+ std::vector< OUString> aRightColumns;
+ fillColumns(pRight,aRightColumns);
+
+ auto aRows = pLeft->get_selected_rows();
+ std::sort(aRows.begin(), aRows.end());
+
+ for (auto it = aRows.begin(); it != aRows.end(); ++it)
+ moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase);
+
+ for (auto it = aRows.rbegin(); it != aRows.rend(); ++it)
+ pLeft->remove(*it);
+
+ enableButtons();
+
+ return true;
+}
+
+void OWizColumnSelect::clearListBox(weld::TreeView& rListBox)
+{
+ rListBox.clear();
+}
+
+void OWizColumnSelect::fillColumns(weld::TreeView const * pRight,std::vector< OUString> &_rRightColumns)
+{
+ const sal_Int32 nCount = pRight->n_children();
+ _rRightColumns.reserve(nCount);
+ for (sal_Int32 i=0; i < nCount; ++i)
+ _rRightColumns.push_back(pRight->get_text(i));
+}
+
+void OWizColumnSelect::createNewColumn( weld::TreeView* _pListbox,
+ OFieldDescription const * _pSrcField,
+ std::vector< OUString>& _rRightColumns,
+ const OUString& _sColumnName,
+ std::u16string_view _sExtraChars,
+ sal_Int32 _nMaxNameLen,
+ const ::comphelper::UStringMixEqual& _aCase)
+{
+ OUString sConvertedName = m_pParent->convertColumnName(TMultiListBoxEntryFindFunctor(&_rRightColumns,_aCase),
+ _sColumnName,
+ _sExtraChars,
+ _nMaxNameLen);
+ OFieldDescription* pNewField = new OFieldDescription(*_pSrcField);
+ pNewField->SetName(sConvertedName);
+ bool bNotConvert = true;
+ pNewField->SetType(m_pParent->convertType(_pSrcField->getSpecialTypeInfo(),bNotConvert));
+ if ( !m_pParent->supportsPrimaryKey() )
+ pNewField->SetPrimaryKey(false);
+
+ _pListbox->append(weld::toId(pNewField), sConvertedName);
+ _rRightColumns.push_back(sConvertedName);
+
+ if ( !bNotConvert )
+ m_pParent->showColumnTypeNotSupported(sConvertedName);
+}
+
+void OWizColumnSelect::moveColumn( weld::TreeView* _pRight,
+ weld::TreeView const * _pLeft,
+ std::vector< OUString>& _rRightColumns,
+ const OUString& _sColumnName,
+ std::u16string_view _sExtraChars,
+ sal_Int32 _nMaxNameLen,
+ const ::comphelper::UStringMixEqual& _aCase)
+{
+ if(_pRight == m_xNewColumnNames.get())
+ {
+ // we copy the column into the new format for the dest
+ OFieldDescription* pSrcField = weld::fromId<OFieldDescription*>(_pLeft->get_id(_pLeft->find_text(_sColumnName)));
+ createNewColumn(_pRight,pSrcField,_rRightColumns,_sColumnName,_sExtraChars,_nMaxNameLen,_aCase);
+ }
+ else
+ {
+ // find the new column in the dest name mapping to obtain the old column
+ OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(),
+ [&_aCase, &_sColumnName] (const OCopyTableWizard::TNameMapping::value_type& nameMap) {
+ return _aCase(nameMap.second, _sColumnName);
+ });
+
+ OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined");
+ if ( aIter == m_pParent->m_mNameMapping.end() )
+ return; // do nothing
+ const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns();
+ ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first);
+ if ( aSrcIter != rSrcColumns.end() )
+ {
+ // we need also the old position of this column to insert it back on that position again
+ const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector();
+ ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter);
+ OSL_ENSURE( aPos != rSrcVector.end(),"Invalid position for the iterator here!");
+ ODatabaseExport::TColumnVector::size_type nPos = (aPos - rSrcVector.begin()) - adjustColumnPosition(_pLeft, _sColumnName, (aPos - rSrcVector.begin()), _aCase);
+
+ OUString sId(weld::toId(aSrcIter->second));
+ const OUString& rStr = (*aIter).first;
+ _pRight->insert(nullptr, nPos, &rStr, &sId, nullptr, nullptr, false, nullptr);
+ _rRightColumns.push_back(rStr);
+ m_pParent->removeColumnNameFromNameMap(_sColumnName);
+ }
+ }
+}
+
+// Simply returning fields back to their original position is
+// not enough. We need to take into account what fields have
+// been removed earlier and adjust accordingly. Based on the
+// algorithm employed in moveColumn().
+sal_Int32 OWizColumnSelect::adjustColumnPosition(weld::TreeView const * _pLeft,
+ std::u16string_view _sColumnName,
+ ODatabaseExport::TColumnVector::size_type nCurrentPos,
+ const ::comphelper::UStringMixEqual& _aCase)
+{
+ sal_Int32 nAdjustedPos = 0;
+
+ // if returning all entries to their original position,
+ // then there is no need to adjust the positions.
+ if (m_xColumns_LH->has_focus())
+ return nAdjustedPos;
+
+ const sal_Int32 nCount = _pLeft->n_children();
+ OUString sColumnString;
+ for(sal_Int32 i=0; i < nCount; ++i)
+ {
+ sColumnString = _pLeft->get_text(i);
+ if(_sColumnName != sColumnString)
+ {
+ // find the new column in the dest name mapping to obtain the old column
+ OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(),
+ [&_aCase, &sColumnString] (const OCopyTableWizard::TNameMapping::value_type& nameMap) {
+ return _aCase(nameMap.second, sColumnString);
+ });
+
+ OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined");
+ const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns();
+ ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first);
+ if ( aSrcIter != rSrcColumns.end() )
+ {
+ // we need also the old position of this column to insert it back on that position again
+ const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector();
+ ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter);
+ ODatabaseExport::TColumnVector::size_type nPos = aPos - rSrcVector.begin();
+ if( nPos < nCurrentPos)
+ {
+ nAdjustedPos++;
+ }
+ }
+ }
+ }
+
+ return nAdjustedPos;
+}
+
+void OWizColumnSelect::enableButtons()
+{
+ bool bEntries = m_xNewColumnNames->n_children() != 0;
+ if (!bEntries)
+ m_pParent->m_mNameMapping.clear();
+
+ m_pParent->GetOKButton().set_sensitive(bEntries);
+ m_pParent->EnableNextButton(bEntries && m_pParent->getOperation() != CopyTableOperation::AppendData);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/WCopyTable.cxx b/dbaccess/source/ui/misc/WCopyTable.cxx
new file mode 100644
index 000000000..64301bccd
--- /dev/null
+++ b/dbaccess/source/ui/misc/WCopyTable.cxx
@@ -0,0 +1,1554 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <sqlmessage.hxx>
+#include <UITools.hxx>
+#include <WColumnSelect.hxx>
+#include <WCopyTable.hxx>
+#include <WCPage.hxx>
+#include <WExtendPages.hxx>
+#include <WNameMatch.hxx>
+#include <WTypeSelect.hxx>
+
+#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+
+#include <comphelper/interaction.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <algorithm>
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::task;
+using namespace dbtools;
+
+namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
+
+#define MAX_PAGES 4 // max. number of pages, which are shown
+
+namespace
+{
+ void clearColumns(ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColumnsVec)
+ {
+ for (auto const& column : _rColumns)
+ delete column.second;
+
+ _rColumnsVec.clear();
+ _rColumns.clear();
+ }
+}
+
+// ICopyTableSourceObject
+ICopyTableSourceObject::~ICopyTableSourceObject()
+{
+}
+
+// ObjectCopySource
+ObjectCopySource::ObjectCopySource( const Reference< XConnection >& _rxConnection, const Reference< XPropertySet >& _rxObject )
+ :m_xConnection( _rxConnection, UNO_SET_THROW )
+ ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW )
+ ,m_xObject( _rxObject, UNO_SET_THROW )
+ ,m_xObjectPSI( _rxObject->getPropertySetInfo(), UNO_SET_THROW )
+ ,m_xObjectColumns( Reference< XColumnsSupplier >( _rxObject, UNO_QUERY_THROW )->getColumns(), UNO_SET_THROW )
+{
+}
+
+OUString ObjectCopySource::getQualifiedObjectName() const
+{
+ OUString sName;
+
+ if ( !m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) )
+ sName = ::dbtools::composeTableName( m_xMetaData, m_xObject, ::dbtools::EComposeRule::InDataManipulation, false );
+ else
+ m_xObject->getPropertyValue( PROPERTY_NAME ) >>= sName;
+ return sName;
+}
+
+bool ObjectCopySource::isView() const
+{
+ bool bIsView = false;
+ try
+ {
+ if ( m_xObjectPSI->hasPropertyByName( PROPERTY_TYPE ) )
+ {
+ OUString sObjectType;
+ OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_TYPE ) >>= sObjectType );
+ bIsView = sObjectType == "VIEW";
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bIsView;
+}
+
+void ObjectCopySource::copyUISettingsTo( const Reference< XPropertySet >& _rxObject ) const
+{
+ const OUString aCopyProperties[] = {
+ OUString(PROPERTY_FONT), OUString(PROPERTY_ROW_HEIGHT), OUString(PROPERTY_TEXTCOLOR),OUString(PROPERTY_TEXTLINECOLOR),OUString(PROPERTY_TEXTEMPHASIS),OUString(PROPERTY_TEXTRELIEF)
+ };
+ for (const auto & aCopyProperty : aCopyProperties)
+ {
+ if ( m_xObjectPSI->hasPropertyByName( aCopyProperty ) )
+ _rxObject->setPropertyValue( aCopyProperty, m_xObject->getPropertyValue( aCopyProperty ) );
+ }
+}
+
+void ObjectCopySource::copyFilterAndSortingTo( const Reference< XConnection >& _xConnection,const Reference< XPropertySet >& _rxObject ) const
+{
+ std::pair< OUString, OUString > aProperties[] = {
+ std::pair< OUString, OUString >(PROPERTY_FILTER,OUString(" AND "))
+ ,std::pair< OUString, OUString >(PROPERTY_ORDER,OUString(" ORDER BY "))
+ };
+
+ try
+ {
+ const OUString sSourceName = ::dbtools::composeTableNameForSelect(m_xConnection,m_xObject) + ".";
+ const OUString sTargetName = ::dbtools::composeTableNameForSelect(_xConnection,_rxObject);
+ const OUString sTargetNameTemp = sTargetName + ".";
+
+ OUStringBuffer sStatement = "SELECT * FROM " + sTargetName + " WHERE 0=1";
+
+ for (const std::pair<OUString,OUString> & aProperty : aProperties)
+ {
+ if ( m_xObjectPSI->hasPropertyByName( aProperty.first ) )
+ {
+ OUString sFilter;
+ m_xObject->getPropertyValue( aProperty.first ) >>= sFilter;
+ if ( !sFilter.isEmpty() )
+ {
+ sStatement.append(aProperty.second);
+ sFilter = sFilter.replaceFirst(sSourceName,sTargetNameTemp);
+ _rxObject->setPropertyValue( aProperty.first, Any(sFilter) );
+ sStatement.append(sFilter);
+ }
+ }
+ }
+
+ _xConnection->createStatement()->executeQuery(sStatement.makeStringAndClear());
+
+ if ( m_xObjectPSI->hasPropertyByName( PROPERTY_APPLYFILTER ) )
+ _rxObject->setPropertyValue( PROPERTY_APPLYFILTER, m_xObject->getPropertyValue( PROPERTY_APPLYFILTER ) );
+ }
+ catch(Exception&)
+ {
+ }
+}
+
+Sequence< OUString > ObjectCopySource::getColumnNames() const
+{
+ return m_xObjectColumns->getElementNames();
+}
+
+Sequence< OUString > ObjectCopySource::getPrimaryKeyColumnNames() const
+{
+ const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(m_xObject);
+ Sequence< OUString > aKeyColNames;
+ if ( xPrimaryKeyColumns.is() )
+ aKeyColNames = xPrimaryKeyColumns->getElementNames();
+ return aKeyColNames;
+}
+
+OFieldDescription* ObjectCopySource::createFieldDescription( const OUString& _rColumnName ) const
+{
+ Reference< XPropertySet > xColumn( m_xObjectColumns->getByName( _rColumnName ), UNO_QUERY_THROW );
+ return new OFieldDescription( xColumn );
+}
+
+OUString ObjectCopySource::getSelectStatement() const
+{
+ OUString sSelectStatement;
+ if ( m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) )
+ { // query
+ OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_COMMAND ) >>= sSelectStatement );
+ }
+ else
+ { // table
+ OUStringBuffer aSQL;
+ aSQL.append( "SELECT " );
+
+ // we need to create the sql stmt with column names
+ // otherwise it is possible that names don't match
+ const OUString sQuote = m_xMetaData->getIdentifierQuoteString();
+
+ Sequence< OUString > aColumnNames = getColumnNames();
+ const OUString* pColumnName = aColumnNames.getConstArray();
+ const OUString* pEnd = pColumnName + aColumnNames.getLength();
+ for ( ; pColumnName != pEnd; )
+ {
+ aSQL.append( ::dbtools::quoteName( sQuote, *pColumnName++ ) );
+
+ if ( pColumnName == pEnd )
+ aSQL.append( " " );
+ else
+ aSQL.append( ", " );
+ }
+
+ aSQL.append( "FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, m_xObject ) );
+
+ sSelectStatement = aSQL.makeStringAndClear();
+ }
+
+ return sSelectStatement;
+}
+
+::utl::SharedUNOComponent< XPreparedStatement > ObjectCopySource::getPreparedSelectStatement() const
+{
+ ::utl::SharedUNOComponent< XPreparedStatement > xStatement(
+ m_xConnection->prepareStatement( getSelectStatement() ),
+ ::utl::SharedUNOComponent< XPreparedStatement >::TakeOwnership
+ );
+ return xStatement;
+}
+
+// NamedTableCopySource
+NamedTableCopySource::NamedTableCopySource( const Reference< XConnection >& _rxConnection, const OUString& _rTableName )
+ :m_xConnection( _rxConnection, UNO_SET_THROW )
+ ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW )
+ ,m_sTableName( _rTableName )
+{
+ ::dbtools::qualifiedNameComponents( m_xMetaData, m_sTableName, m_sTableCatalog, m_sTableSchema, m_sTableBareName, ::dbtools::EComposeRule::Complete );
+ impl_ensureColumnInfo_throw();
+}
+
+OUString NamedTableCopySource::getQualifiedObjectName() const
+{
+ return m_sTableName;
+}
+
+bool NamedTableCopySource::isView() const
+{
+ OUString sTableType;
+ try
+ {
+ Reference< XResultSet > xTableDesc( m_xMetaData->getTables( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName,
+ Sequence< OUString >() ) );
+ Reference< XRow > xTableDescRow( xTableDesc, UNO_QUERY_THROW );
+ OSL_VERIFY( xTableDesc->next() );
+ sTableType = xTableDescRow->getString( 4 );
+ OSL_ENSURE( !xTableDescRow->wasNull(), "NamedTableCopySource::isView: invalid table type!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sTableType == "VIEW";
+}
+
+void NamedTableCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const
+{
+ // not supported: we do not have UI settings to copy
+}
+
+void NamedTableCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const
+{
+}
+
+void NamedTableCopySource::impl_ensureColumnInfo_throw()
+{
+ if ( !m_aColumnInfo.empty() )
+ return;
+
+ Reference< XResultSetMetaDataSupplier > xStatementMetaSupp( impl_ensureStatement_throw().getTyped(), UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xStatementMeta( xStatementMetaSupp->getMetaData(), UNO_SET_THROW );
+
+ sal_Int32 nColCount( xStatementMeta->getColumnCount() );
+ for ( sal_Int32 i = 1; i <= nColCount; ++i )
+ {
+ OFieldDescription aDesc;
+
+ aDesc.SetName( xStatementMeta->getColumnName( i ) );
+ aDesc.SetHelpText( xStatementMeta->getColumnLabel( i ) );
+ aDesc.SetTypeValue( xStatementMeta->getColumnType( i ) );
+ aDesc.SetTypeName( xStatementMeta->getColumnTypeName( i ) );
+ aDesc.SetPrecision( xStatementMeta->getPrecision( i ) );
+ aDesc.SetScale( xStatementMeta->getScale( i ) );
+ aDesc.SetIsNullable( xStatementMeta->isNullable( i ) );
+ aDesc.SetCurrency( xStatementMeta->isCurrency( i ) );
+ aDesc.SetAutoIncrement( xStatementMeta->isAutoIncrement( i ) );
+
+ m_aColumnInfo.push_back( aDesc );
+ }
+}
+
+::utl::SharedUNOComponent< XPreparedStatement > const & NamedTableCopySource::impl_ensureStatement_throw()
+{
+ if ( !m_xStatement.is() )
+ m_xStatement.set( m_xConnection->prepareStatement( getSelectStatement() ), UNO_SET_THROW );
+ return m_xStatement;
+}
+
+Sequence< OUString > NamedTableCopySource::getColumnNames() const
+{
+ Sequence< OUString > aNames( m_aColumnInfo.size() );
+ std::transform(m_aColumnInfo.begin(), m_aColumnInfo.end(), aNames.getArray(),
+ [](const auto& elem) { return elem.GetName(); });
+
+ return aNames;
+}
+
+Sequence< OUString > NamedTableCopySource::getPrimaryKeyColumnNames() const
+{
+ Sequence< OUString > aPKColNames;
+
+ try
+ {
+ Reference< XResultSet > xPKDesc( m_xMetaData->getPrimaryKeys( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName ) );
+ Reference< XRow > xPKDescRow( xPKDesc, UNO_QUERY_THROW );
+ while ( xPKDesc->next() )
+ {
+ sal_Int32 len( aPKColNames.getLength() );
+ aPKColNames.realloc( len + 1 );
+ aPKColNames.getArray()[ len ] = xPKDescRow->getString( 4 ); // COLUMN_NAME
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return aPKColNames;
+}
+
+OFieldDescription* NamedTableCopySource::createFieldDescription( const OUString& _rColumnName ) const
+{
+ for (auto const& elem : m_aColumnInfo)
+ if ( elem.GetName() == _rColumnName )
+ return new OFieldDescription(elem);
+
+ return nullptr;
+}
+
+OUString NamedTableCopySource::getSelectStatement() const
+{
+ return "SELECT * FROM " +
+ ::dbtools::composeTableNameForSelect( m_xConnection, m_sTableCatalog, m_sTableSchema, m_sTableBareName );
+}
+
+::utl::SharedUNOComponent< XPreparedStatement > NamedTableCopySource::getPreparedSelectStatement() const
+{
+ return const_cast< NamedTableCopySource* >( this )->impl_ensureStatement_throw();
+}
+
+namespace {
+
+// DummyCopySource
+class DummyCopySource : public ICopyTableSourceObject
+{
+public:
+ DummyCopySource() { }
+
+ static const DummyCopySource& Instance();
+
+ // ICopyTableSourceObject overridables
+ virtual OUString getQualifiedObjectName() const override;
+ virtual bool isView() const override;
+ virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
+ virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
+ virtual css::uno::Sequence< OUString >
+ getColumnNames() const override;
+ virtual css::uno::Sequence< OUString >
+ getPrimaryKeyColumnNames() const override;
+ virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override;
+ virtual OUString getSelectStatement() const override;
+ virtual ::utl::SharedUNOComponent< XPreparedStatement >
+ getPreparedSelectStatement() const override;
+};
+
+}
+
+const DummyCopySource& DummyCopySource::Instance()
+{
+ static DummyCopySource s_aTheInstance;
+ return s_aTheInstance;
+}
+
+OUString DummyCopySource::getQualifiedObjectName() const
+{
+ SAL_WARN("dbaccess.ui", "DummyCopySource::getQualifiedObjectName: not to be called!" );
+ return OUString();
+}
+
+bool DummyCopySource::isView() const
+{
+ SAL_WARN("dbaccess.ui", "DummyCopySource::isView: not to be called!" );
+ return false;
+}
+
+void DummyCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const
+{
+ // no support
+}
+
+void DummyCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const
+{
+}
+
+Sequence< OUString > DummyCopySource::getColumnNames() const
+{
+ return Sequence< OUString >();
+}
+
+Sequence< OUString > DummyCopySource::getPrimaryKeyColumnNames() const
+{
+ SAL_WARN("dbaccess.ui", "DummyCopySource::getPrimaryKeyColumnNames: not to be called!" );
+ return Sequence< OUString >();
+}
+
+OFieldDescription* DummyCopySource::createFieldDescription( const OUString& /*_rColumnName*/ ) const
+{
+ SAL_WARN("dbaccess.ui", "DummyCopySource::createFieldDescription: not to be called!" );
+ return nullptr;
+}
+
+OUString DummyCopySource::getSelectStatement() const
+{
+ SAL_WARN("dbaccess.ui", "DummyCopySource::getSelectStatement: not to be called!" );
+ return OUString();
+}
+
+::utl::SharedUNOComponent< XPreparedStatement > DummyCopySource::getPreparedSelectStatement() const
+{
+ SAL_WARN("dbaccess.ui", "DummyCopySource::getPreparedSelectStatement: not to be called!" );
+ return ::utl::SharedUNOComponent< XPreparedStatement >();
+}
+
+namespace
+{
+ bool lcl_canCreateViewFor_nothrow( const Reference< XConnection >& _rxConnection )
+ {
+ Reference< XViewsSupplier > xSup( _rxConnection, UNO_QUERY );
+ Reference< XDataDescriptorFactory > xViewFac;
+ if ( xSup.is() )
+ xViewFac.set( xSup->getViews(), UNO_QUERY );
+ return xViewFac.is();
+ }
+
+ bool lcl_sameConnection_throw( const Reference< XConnection >& _rxLHS, const Reference< XConnection >& _rxRHS )
+ {
+ Reference< XDatabaseMetaData > xMetaLHS( _rxLHS->getMetaData(), UNO_SET_THROW );
+ Reference< XDatabaseMetaData > xMetaRHS( _rxRHS->getMetaData(), UNO_SET_THROW );
+ return xMetaLHS->getURL() == xMetaRHS->getURL();
+ }
+}
+
+// OCopyTableWizard
+OCopyTableWizard::OCopyTableWizard(weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation,
+ const ICopyTableSourceObject& _rSourceObject, const Reference< XConnection >& _xSourceConnection,
+ const Reference< XConnection >& _xConnection, const Reference< XComponentContext >& _rxContext,
+ const Reference< XInteractionHandler>& _xInteractionHandler)
+ : vcl::RoadmapWizardMachine(pParent)
+ , m_mNameMapping(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers())
+ , m_xDestConnection( _xConnection )
+ , m_rSourceObject( _rSourceObject )
+ , m_xFormatter( getNumberFormatter( _xConnection, _rxContext ) )
+ , m_xContext(_rxContext)
+ , m_xInteractionHandler(_xInteractionHandler)
+ , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES))
+ , m_nPageCount(0)
+ , m_bDeleteSourceColumns(true)
+ , m_bInterConnectionCopy( _xSourceConnection != _xConnection )
+ , m_sName( _rDefaultName )
+ , m_nOperation( _nOperation )
+ , m_ePressed( WIZARD_NONE )
+ , m_bCreatePrimaryKeyColumn(false)
+ , m_bUseHeaderLine(false)
+{
+ construct();
+
+ // extract table name
+ OUString sInitialTableName( _rDefaultName );
+ try
+ {
+ m_sSourceName = m_rSourceObject.getQualifiedObjectName();
+ OSL_ENSURE( !m_sSourceName.isEmpty(), "OCopyTableWizard::OCopyTableWizard: unable to retrieve the source object's name!" );
+
+ if ( sInitialTableName.isEmpty() )
+ sInitialTableName = m_sSourceName;
+
+ if ( m_sName.isEmpty() )
+ {
+ if ( _xSourceConnection == m_xDestConnection )
+ {
+ Reference< XTablesSupplier > xSup( m_xDestConnection, UNO_QUERY_THROW );
+ m_sName = ::dbtools::createUniqueName( xSup->getTables(), sInitialTableName, false );
+ }
+ else
+ m_sName = sInitialTableName;
+ }
+ }
+ catch ( const Exception& )
+ {
+ m_sName = sInitialTableName;
+ }
+
+ ::dbaui::fillTypeInfo( _xSourceConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex );
+ ::dbaui::fillTypeInfo( m_xDestConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex );
+ loadData( m_rSourceObject, m_vSourceColumns, m_vSourceVec );
+
+ bool bAllowViews = true;
+ // if the source is a, don't allow creating views
+ if ( m_rSourceObject.isView() )
+ bAllowViews = false;
+ // no views if the target connection does not support creating them
+ if ( !lcl_canCreateViewFor_nothrow( m_xDestConnection ) )
+ bAllowViews = false;
+ // no views if we're copying to a different database
+ if ( !lcl_sameConnection_throw( _xSourceConnection, m_xDestConnection ) )
+ bAllowViews = false;
+
+ if ( m_bInterConnectionCopy )
+ {
+ Reference< XDatabaseMetaData > xSrcMeta = _xSourceConnection->getMetaData();
+ OUString sCatalog;
+ OUString sSchema;
+ OUString sTable;
+ ::dbtools::qualifiedNameComponents( xSrcMeta,
+ m_sName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ m_sName = ::dbtools::composeTableName(m_xDestConnection->getMetaData(),sCatalog,sSchema,sTable,false,::dbtools::EComposeRule::InTableDefinitions);
+ }
+
+ std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this));
+ xPage1->disallowUseHeaderLine();
+ if ( !bAllowViews )
+ xPage1->disallowViews();
+ xPage1->setCreateStyleAction();
+ AddWizardPage(std::move(xPage1));
+
+ AddWizardPage( std::make_unique<OWizNameMatching>(CreatePageContainer(), this));
+ AddWizardPage( std::make_unique<OWizColumnSelect>(CreatePageContainer(), this));
+ AddWizardPage( std::make_unique<OWizNormalExtend>(CreatePageContainer(), this));
+ ActivatePage();
+
+ m_xAssistant->set_current_page(0);
+}
+
+weld::Container* OCopyTableWizard::CreatePageContainer()
+{
+ OString sIdent(OString::number(m_nPageCount));
+ weld::Container* pPageContainer = m_xAssistant->append_page(sIdent);
+ return pPageContainer;
+}
+
+OCopyTableWizard::OCopyTableWizard( weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation,
+ ODatabaseExport::TColumns&& _rSourceColumns, const ODatabaseExport::TColumnVector& _rSourceColVec,
+ const Reference< XConnection >& _xConnection, const Reference< XNumberFormatter >& _xFormatter,
+ TypeSelectionPageFactory _pTypeSelectionPageFactory, SvStream& _rTypeSelectionPageArg, const Reference< XComponentContext >& _rxContext )
+ : vcl::RoadmapWizardMachine(pParent)
+ , m_vSourceColumns(std::move(_rSourceColumns))
+ , m_mNameMapping(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers())
+ , m_xDestConnection( _xConnection )
+ , m_rSourceObject( DummyCopySource::Instance() )
+ , m_xFormatter(_xFormatter)
+ , m_xContext(_rxContext)
+ , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES))
+ , m_nPageCount(0)
+ , m_bDeleteSourceColumns(false)
+ , m_bInterConnectionCopy( false )
+ , m_sName(_rDefaultName)
+ , m_nOperation( _nOperation )
+ , m_ePressed( WIZARD_NONE )
+ , m_bCreatePrimaryKeyColumn(false)
+ , m_bUseHeaderLine(false)
+{
+ construct();
+ for (auto const& sourceCol : _rSourceColVec)
+ {
+ m_vSourceVec.emplace_back(m_vSourceColumns.find(sourceCol->first));
+ }
+
+ ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex );
+ ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex );
+
+ m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr);
+
+ std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this));
+ xPage1->disallowViews();
+ xPage1->setCreateStyleAction();
+ AddWizardPage(std::move(xPage1));
+
+ AddWizardPage(std::make_unique<OWizNameMatching>(CreatePageContainer(), this));
+ AddWizardPage(std::make_unique<OWizColumnSelect>(CreatePageContainer(), this));
+ AddWizardPage((*_pTypeSelectionPageFactory)(CreatePageContainer(), this, _rTypeSelectionPageArg));
+
+ ActivatePage();
+
+ m_xAssistant->set_current_page(0);
+}
+
+void OCopyTableWizard::construct()
+{
+ m_xAssistant->set_size_request(700, 350);
+
+ m_xPrevPage->set_label(DBA_RES(STR_WIZ_PB_PREV));
+ m_xNextPage->set_label(DBA_RES(STR_WIZ_PB_NEXT));
+ m_xFinish->set_label(DBA_RES(STR_WIZ_PB_OK));
+
+ m_xHelp->show();
+ m_xCancel->show();
+ m_xPrevPage->show();
+ m_xNextPage->show();
+ m_xFinish->show();
+
+ m_xPrevPage->connect_clicked( LINK( this, OCopyTableWizard, ImplPrevHdl ) );
+ m_xNextPage->connect_clicked( LINK( this, OCopyTableWizard, ImplNextHdl ) );
+ m_xFinish->connect_clicked( LINK( this, OCopyTableWizard, ImplOKHdl ) );
+
+ m_xNextPage->grab_focus();
+
+ if (!m_vDestColumns.empty())
+ // source is a html or rtf table
+ m_xAssistant->change_default_widget(nullptr, m_xNextPage.get());
+ else
+ m_xAssistant->change_default_widget(nullptr, m_xFinish.get());
+
+ m_pTypeInfo = std::make_shared<OTypeInfo>();
+ m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';');
+ m_bAddPKFirstTime = true;
+}
+
+OCopyTableWizard::~OCopyTableWizard()
+{
+ if ( m_bDeleteSourceColumns )
+ clearColumns(m_vSourceColumns,m_vSourceVec);
+
+ clearColumns(m_vDestColumns,m_aDestVec);
+
+ // clear the type information
+ m_aTypeInfoIndex.clear();
+ m_aTypeInfo.clear();
+ m_aDestTypeInfoIndex.clear();
+ m_aDestTypeInfo.clear();
+}
+
+IMPL_LINK_NOARG(OCopyTableWizard, ImplPrevHdl, weld::Button&, void)
+{
+ m_ePressed = WIZARD_PREV;
+ if ( GetCurLevel() )
+ {
+ if ( getOperation() != CopyTableOperation::AppendData )
+ {
+ if(GetCurLevel() == 2)
+ ShowPage(GetCurLevel()-2);
+ else
+ ShowPrevPage();
+ }
+ else
+ ShowPrevPage();
+ }
+}
+
+IMPL_LINK_NOARG(OCopyTableWizard, ImplNextHdl, weld::Button&, void)
+{
+ m_ePressed = WIZARD_NEXT;
+ if ( GetCurLevel() < MAX_PAGES )
+ {
+ if ( getOperation() != CopyTableOperation::AppendData )
+ {
+ if(GetCurLevel() == 0)
+ ShowPage(GetCurLevel()+2);
+ else
+ ShowNextPage();
+ }
+ else
+ ShowNextPage();
+ }
+}
+
+bool OCopyTableWizard::CheckColumns(sal_Int32& _rnBreakPos)
+{
+ bool bRet = true;
+ m_vColumnPositions.clear();
+ m_vColumnTypes.clear();
+
+ OSL_ENSURE( m_xDestConnection.is(), "OCopyTableWizard::CheckColumns: No connection!" );
+ // If database is able to process PrimaryKeys, set PrimaryKey
+ if ( m_xDestConnection.is() )
+ {
+ bool bPKeyAllowed = supportsPrimaryKey();
+
+ bool bContainsColumns = !m_vDestColumns.empty();
+
+ if ( bPKeyAllowed && shouldCreatePrimaryKey() )
+ {
+ // add extra column for the primary key
+ TOTypeInfoSP pTypeInfo = queryPrimaryKeyType(m_aDestTypeInfo);
+ if ( pTypeInfo )
+ {
+ if ( m_bAddPKFirstTime )
+ {
+ // tdf#114955: since we chose to create a primary key
+ // be sure all other columns won't be in primary key
+ for (auto const& elem : m_vDestColumns)
+ elem.second->SetPrimaryKey(false);
+ OFieldDescription* pField = new OFieldDescription();
+ pField->SetName(m_aKeyName);
+ pField->FillFromTypeInfo(pTypeInfo,true,true);
+ pField->SetPrimaryKey(true);
+ m_bAddPKFirstTime = false;
+ insertColumn(0,pField);
+ }
+ m_vColumnPositions.emplace_back(1,1);
+ m_vColumnTypes.push_back(pTypeInfo->nType);
+ }
+ }
+
+ if ( bContainsColumns )
+ { // we have dest columns so look for the matching column
+ for (auto const& elemSource : m_vSourceVec)
+ {
+ ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(m_mNameMapping[elemSource->first]);
+
+ if ( aDestIter != m_vDestColumns.end() )
+ {
+ ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter);
+ assert(aFind != m_aDestVec.end());
+ sal_Int32 nPos = (aFind - m_aDestVec.begin())+1;
+ m_vColumnPositions.emplace_back(nPos,nPos);
+ m_vColumnTypes.push_back((*aFind)->second->GetType());
+ }
+ else
+ {
+ m_vColumnPositions.emplace_back( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND );
+ m_vColumnTypes.push_back(0);
+ }
+ }
+ }
+ else
+ {
+ Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData() );
+ OUString sExtraChars = xMetaData->getExtraNameCharacters();
+ sal_Int32 nMaxNameLen = getMaxColumnNameLength();
+
+ _rnBreakPos=0;
+ for (auto const& elemSource : m_vSourceVec)
+ {
+ OFieldDescription* pField = new OFieldDescription(*elemSource->second);
+ pField->SetName(convertColumnName(TExportColumnFindFunctor(&m_vDestColumns),elemSource->first,sExtraChars,nMaxNameLen));
+ TOTypeInfoSP pType = convertType(elemSource->second->getSpecialTypeInfo(),bRet);
+ pField->SetType(pType);
+ if ( !bPKeyAllowed )
+ pField->SetPrimaryKey(false);
+
+ // now create a column
+ insertColumn(m_vDestColumns.size(),pField);
+ m_vColumnPositions.emplace_back(m_vDestColumns.size(),m_vDestColumns.size());
+ m_vColumnTypes.push_back(elemSource->second->GetType());
+ ++_rnBreakPos;
+ if (!bRet)
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+IMPL_LINK_NOARG(OCopyTableWizard, ImplOKHdl, weld::Button&, void)
+{
+ m_ePressed = WIZARD_FINISH;
+ bool bFinish = DeactivatePage();
+
+ if(!bFinish)
+ return;
+
+ weld::WaitObject aWait(m_xAssistant.get());
+ switch(getOperation())
+ {
+ case CopyTableOperation::CopyDefinitionAndData:
+ case CopyTableOperation::CopyDefinitionOnly:
+ {
+ bool bOnFirstPage = GetCurLevel() == 0;
+ if ( bOnFirstPage )
+ {
+ // we came from the first page so we have to clear
+ // all column information already collected
+ clearDestColumns();
+ m_mNameMapping.clear();
+ }
+ sal_Int32 nBreakPos = 0;
+ bool bCheckOk = CheckColumns(nBreakPos);
+ if ( bOnFirstPage && !bCheckOk )
+ {
+ showColumnTypeNotSupported(m_vSourceVec[nBreakPos-1]->first);
+ OWizTypeSelect* pPage = static_cast<OWizTypeSelect*>(GetPage(3));
+ if ( pPage )
+ {
+ m_mNameMapping.clear();
+ pPage->setDisplayRow(nBreakPos);
+ ShowPage(3);
+ return;
+ }
+ }
+ if ( m_xDestConnection.is() )
+ {
+ if ( supportsPrimaryKey() )
+ {
+ bool noPrimaryKey = std::none_of(m_vDestColumns.begin(),m_vDestColumns.end(),
+ [] (const ODatabaseExport::TColumns::value_type& tCol) { return tCol.second->IsPrimaryKey(); });
+ if ( noPrimaryKey && m_xInteractionHandler.is() )
+ {
+
+ OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY));
+ SQLContext aError;
+ aError.Message = sMsg;
+ ::rtl::Reference xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) );
+ ::rtl::Reference xYes = new ::comphelper::OInteractionApprove;
+ xRequest->addContinuation( xYes );
+ xRequest->addContinuation( new ::comphelper::OInteractionDisapprove );
+ ::rtl::Reference< ::comphelper::OInteractionAbort > xAbort = new ::comphelper::OInteractionAbort;
+ xRequest->addContinuation( xAbort );
+
+ m_xInteractionHandler->handle( xRequest );
+
+ if ( xYes->wasSelected() )
+ {
+ OCopyTable* pPage = static_cast<OCopyTable*>(GetPage(0));
+ m_bCreatePrimaryKeyColumn = true;
+ m_aKeyName = pPage->GetKeyName();
+ if ( m_aKeyName.isEmpty() )
+ m_aKeyName = "ID";
+ m_aKeyName = createUniqueName( m_aKeyName );
+ sal_Int32 nBreakPos2 = 0;
+ CheckColumns(nBreakPos2);
+ }
+ else if ( xAbort->wasSelected() )
+ {
+ ShowPage(3);
+ return;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case CopyTableOperation::AppendData:
+ case CopyTableOperation::CreateAsView:
+ break;
+ default:
+ {
+ SAL_WARN("dbaccess.ui", "OCopyTableWizard::ImplOKHdl: invalid creation style!");
+ }
+ }
+
+ m_xAssistant->response(RET_OK);
+}
+
+void OCopyTableWizard::setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName )
+{
+ m_bCreatePrimaryKeyColumn = _bDoCreate;
+ if ( !_rSuggestedName.isEmpty() )
+ m_aKeyName = _rSuggestedName;
+
+ OCopyTable* pSettingsPage = dynamic_cast< OCopyTable* >( GetPage( 0 ) );
+ OSL_ENSURE( pSettingsPage, "OCopyTableWizard::setCreatePrimaryKey: page should have been added in the ctor!" );
+ if ( pSettingsPage )
+ pSettingsPage->setCreatePrimaryKey( _bDoCreate, _rSuggestedName );
+}
+
+void OCopyTableWizard::ActivatePage()
+{
+ OWizardPage* pCurrent = static_cast<OWizardPage*>(GetPage(GetCurLevel()));
+ if (pCurrent)
+ {
+ bool bFirstTime = pCurrent->IsFirstTime();
+ if(bFirstTime)
+ pCurrent->Reset();
+
+ CheckButtons();
+
+ m_xAssistant->set_title(pCurrent->GetTitle());
+ }
+}
+
+void OCopyTableWizard::CheckButtons()
+{
+ if(GetCurLevel() == 0) // the first page has no back button
+ {
+ if(m_nPageCount > 1)
+ m_xNextPage->set_sensitive(true);
+ else
+ m_xNextPage->set_sensitive(false);
+
+ m_xPrevPage->set_sensitive(false);
+ }
+ else if(GetCurLevel() == m_nPageCount-1) // the last page has no next button
+ {
+ m_xNextPage->set_sensitive(false);
+ m_xPrevPage->set_sensitive(true);
+ }
+ else
+ {
+ m_xPrevPage->set_sensitive(true);
+ // next already has its state
+ }
+}
+
+void OCopyTableWizard::EnableNextButton(bool bEnable)
+{
+ m_xNextPage->set_sensitive(bEnable);
+}
+
+bool OCopyTableWizard::DeactivatePage()
+{
+ OWizardPage* pPage = static_cast<OWizardPage*>(GetPage(GetCurLevel()));
+ return pPage && pPage->LeavePage();
+}
+
+void OCopyTableWizard::AddWizardPage(std::unique_ptr<OWizardPage> xPage)
+{
+ AddPage(std::move(xPage));
+ ++m_nPageCount;
+}
+
+void OCopyTableWizard::insertColumn(sal_Int32 _nPos,OFieldDescription* _pField)
+{
+ OSL_ENSURE(_pField,"FieldDescrioption is null!");
+ if ( !_pField )
+ return;
+
+ ODatabaseExport::TColumns::const_iterator aFind = m_vDestColumns.find(_pField->GetName());
+ if ( aFind != m_vDestColumns.end() )
+ {
+ delete aFind->second;
+ m_vDestColumns.erase(aFind);
+ }
+
+ m_aDestVec.insert(m_aDestVec.begin() + _nPos,
+ m_vDestColumns.emplace(_pField->GetName(),_pField).first);
+ m_mNameMapping[_pField->GetName()] = _pField->GetName();
+}
+
+void OCopyTableWizard::replaceColumn(sal_Int32 _nPos,OFieldDescription* _pField,const OUString& _sOldName)
+{
+ OSL_ENSURE(_pField,"FieldDescrioption is null!");
+ if ( _pField )
+ {
+ m_vDestColumns.erase(_sOldName);
+ OSL_ENSURE( m_vDestColumns.find(_pField->GetName()) == m_vDestColumns.end(),"Column with that name already exist!");
+
+ m_aDestVec[_nPos] = m_vDestColumns.emplace(_pField->GetName(),_pField).first;
+ }
+}
+
+void OCopyTableWizard::loadData( const ICopyTableSourceObject& _rSourceObject, ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColVector )
+{
+ for (auto const& column : _rColumns)
+ delete column.second;
+
+ _rColVector.clear();
+ _rColumns.clear();
+
+ OFieldDescription* pActFieldDescr = nullptr;
+ OUString const sCreateParam("x");
+ // ReadOnly-Flag
+ // On drop no line must be editable.
+ // On add only empty lines must be editable.
+ // On Add and Drop all lines can be edited.
+ Sequence< OUString > aColumns( _rSourceObject.getColumnNames() );
+ const OUString* pColumn = aColumns.getConstArray();
+ const OUString* pColumnEnd = pColumn + aColumns.getLength();
+
+ for ( ; pColumn != pColumnEnd; ++pColumn )
+ {
+ // get the properties of the column
+ pActFieldDescr = _rSourceObject.createFieldDescription( *pColumn );
+ OSL_ENSURE( pActFieldDescr, "OCopyTableWizard::loadData: illegal field description!" );
+ if ( !pActFieldDescr )
+ continue;
+
+ sal_Int32 nType = pActFieldDescr->GetType();
+ sal_Int32 nScale = pActFieldDescr->GetScale();
+ sal_Int32 nPrecision = pActFieldDescr->GetPrecision();
+ bool bAutoIncrement = pActFieldDescr->IsAutoIncrement();
+ OUString sTypeName = pActFieldDescr->GetTypeName();
+
+ // search for type
+ bool bForce;
+ TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreateParam,nPrecision,nScale,bAutoIncrement,bForce);
+ if ( !pTypeInfo )
+ pTypeInfo = m_pTypeInfo;
+
+ pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false);
+ _rColVector.emplace_back(_rColumns.emplace(pActFieldDescr->GetName(),pActFieldDescr).first);
+ }
+
+ // determine which columns belong to the primary key
+ Sequence< OUString > aPrimaryKeyColumns( _rSourceObject.getPrimaryKeyColumnNames() );
+ const OUString* pKeyColName = aPrimaryKeyColumns.getConstArray();
+ const OUString* pKeyColEnd = pKeyColName + aPrimaryKeyColumns.getLength();
+
+ for( ; pKeyColName != pKeyColEnd; ++pKeyColName )
+ {
+ ODatabaseExport::TColumns::const_iterator keyPos = _rColumns.find( *pKeyColName );
+ if ( keyPos != _rColumns.end() )
+ {
+ keyPos->second->SetPrimaryKey( true );
+ keyPos->second->SetIsNullable( ColumnValue::NO_NULLS );
+ }
+ }
+}
+
+void OCopyTableWizard::clearDestColumns()
+{
+ clearColumns(m_vDestColumns,m_aDestVec);
+ m_bAddPKFirstTime = true;
+ m_mNameMapping.clear();
+}
+
+void OCopyTableWizard::appendColumns( Reference<XColumnsSupplier> const & _rxColSup, const ODatabaseExport::TColumnVector* _pVec, bool _bKeyColumns)
+{
+ // now append the columns
+ OSL_ENSURE(_rxColSup.is(),"No columns supplier");
+ if(!_rxColSup.is())
+ return;
+ Reference<XNameAccess> xColumns = _rxColSup->getColumns();
+ OSL_ENSURE(xColumns.is(),"No columns");
+ Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
+
+ Reference<XAppend> xAppend(xColumns,UNO_QUERY);
+ OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
+
+ for (auto const& elem : *_pVec)
+ {
+ OFieldDescription* pField = elem->second;
+ if(!pField)
+ continue;
+
+ Reference<XPropertySet> xColumn;
+ if(pField->IsPrimaryKey() || !_bKeyColumns)
+ xColumn = xColumnFactory->createDataDescriptor();
+ if(xColumn.is())
+ {
+ if(!_bKeyColumns)
+ dbaui::setColumnProperties(xColumn,pField);
+ else
+ xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName()));
+
+ xAppend->appendByDescriptor(xColumn);
+ xColumn = nullptr;
+ // now only the settings are missing
+ if(xColumns->hasByName(pField->GetName()))
+ {
+ xColumn.set(xColumns->getByName(pField->GetName()),UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"OCopyTableWizard::appendColumns: Column is NULL!");
+ if ( xColumn.is() )
+ pField->copyColumnSettingsTo(xColumn);
+ }
+ else
+ {
+ SAL_WARN("dbaccess.ui", "OCopyTableWizard::appendColumns: invalid field name!");
+ }
+
+ }
+ }
+}
+
+void OCopyTableWizard::appendKey( Reference<XKeysSupplier> const & _rxSup, const ODatabaseExport::TColumnVector* _pVec)
+{
+ if(!_rxSup.is())
+ return; // the database doesn't support keys
+ OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
+ Reference<XDataDescriptorFactory> xKeyFactory(_rxSup->getKeys(),UNO_QUERY);
+ OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
+ if ( !xKeyFactory.is() )
+ return;
+ Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
+ OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
+
+ Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
+ OSL_ENSURE(xKey.is(),"Key is null!");
+ xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY));
+
+ Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
+ if(xColSup.is())
+ {
+ appendColumns(xColSup,_pVec,true);
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ if(xColumns.is() && xColumns->getElementNames().hasElements())
+ xAppend->appendByDescriptor(xKey);
+ }
+
+}
+
+Reference< XPropertySet > OCopyTableWizard::createView() const
+{
+ OUString sCommand( m_rSourceObject.getSelectStatement() );
+ OSL_ENSURE( !sCommand.isEmpty(), "OCopyTableWizard::createView: no statement in the source object!" );
+ // there are legitimate cases in which getSelectStatement does not provide a statement,
+ // but in all those cases, this method here should never be called.
+ return ::dbaui::createView( m_sName, m_xDestConnection, sCommand );
+}
+
+Reference< XPropertySet > OCopyTableWizard::returnTable()
+{
+ if ( getOperation() == CopyTableOperation::AppendData )
+ return getTable();
+ else
+ return createTable();
+}
+
+Reference< XPropertySet > OCopyTableWizard::getTable() const
+{
+ Reference< XPropertySet > xTable;
+
+ Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY );
+ Reference< XNameAccess > xTables;
+ if(xSup.is())
+ xTables = xSup->getTables();
+ if(xTables.is() && xTables->hasByName(m_sName))
+ xTables->getByName(m_sName) >>= xTable;
+
+ return xTable;
+}
+
+Reference< XPropertySet > OCopyTableWizard::createTable()
+{
+ Reference< XPropertySet > xTable;
+
+ Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY );
+ Reference< XNameAccess > xTables;
+ if(xSup.is())
+ xTables = xSup->getTables();
+ Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
+ OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!");
+ if(!xFact.is())
+ return nullptr;
+
+ xTable = xFact->createDataDescriptor();
+ OSL_ENSURE(xTable.is(),"Could not create a new object!");
+ if(!xTable.is())
+ return nullptr;
+
+ OUString sCatalog,sSchema,sTable;
+ Reference< XDatabaseMetaData> xMetaData = m_xDestConnection->getMetaData();
+ ::dbtools::qualifiedNameComponents(xMetaData,
+ m_sName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ if ( sCatalog.isEmpty() && xMetaData->supportsCatalogsInTableDefinitions() )
+ {
+ sCatalog = m_xDestConnection->getCatalog();
+ }
+
+ if ( sSchema.isEmpty() && xMetaData->supportsSchemasInTableDefinitions() )
+ {
+ // query of current schema is quite inconsistent. In case of some
+ // DBMS's each user has their own schema.
+ sSchema = xMetaData->getUserName();
+ // In case of mysql it is not that simple
+ if(xMetaData->getDatabaseProductName() == "MySQL")
+ {
+ Reference< XStatement > xSelect = m_xDestConnection->createStatement();
+ Reference< XResultSet > xRs = xSelect->executeQuery("select database()");
+ (void)xRs->next(); // first and only result
+ Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
+ sSchema = xRow->getString(1);
+ }
+ }
+
+ xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog));
+ xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema));
+ xTable->setPropertyValue(PROPERTY_NAME,Any(sTable));
+
+ Reference< XColumnsSupplier > xSuppDestinationColumns( xTable, UNO_QUERY );
+ // now append the columns
+ const ODatabaseExport::TColumnVector& rVec = getDestVector();
+ appendColumns( xSuppDestinationColumns, &rVec );
+ // now append the primary key
+ Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
+ appendKey(xKeySup, &rVec);
+
+ Reference<XAppend> xAppend(xTables,UNO_QUERY);
+ if(xAppend.is())
+ xAppend->appendByDescriptor(xTable);
+
+ // xTable = NULL;
+ // we need to reget the table because after appending it, it is no longer valid
+ if(xTables->hasByName(m_sName))
+ xTables->getByName(m_sName) >>= xTable;
+ else
+ {
+ OUString sComposedName(
+ ::dbtools::composeTableName( m_xDestConnection->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false ) );
+ if(xTables->hasByName(sComposedName))
+ {
+ xTables->getByName(sComposedName) >>= xTable;
+ m_sName = sComposedName;
+ }
+ else
+ xTable = nullptr;
+ }
+
+ if(xTable.is())
+ {
+ xSuppDestinationColumns.set( xTable, UNO_QUERY_THROW );
+ // insert new table name into table filter
+ ::dbaui::appendToFilter(m_xDestConnection, m_sName, GetComponentContext(), m_xAssistant.get());
+
+ // copy ui settings
+ m_rSourceObject.copyUISettingsTo( xTable );
+ //copy filter and sorting
+ m_rSourceObject.copyFilterAndSortingTo(m_xDestConnection,xTable);
+ // set column mappings
+ Reference<XNameAccess> xNameAccess = xSuppDestinationColumns->getColumns();
+ Sequence< OUString> aSeq = xNameAccess->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+
+ for(sal_Int32 nNewPos=1;pIter != pEnd;++pIter,++nNewPos)
+ {
+ ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(*pIter);
+
+ if ( aDestIter != m_vDestColumns.end() )
+ {
+ ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter);
+ sal_Int32 nPos = (aFind - m_aDestVec.begin())+1;
+
+ ODatabaseExport::TPositions::iterator aPosFind = std::find_if(
+ m_vColumnPositions.begin(),
+ m_vColumnPositions.end(),
+ [nPos] (const ODatabaseExport::TPositions::value_type& tPos) {
+ return tPos.first == nPos;
+ }
+ );
+
+ if ( m_vColumnPositions.end() != aPosFind )
+ {
+ aPosFind->second = nNewPos;
+ OSL_ENSURE( m_vColumnTypes.size() > o3tl::make_unsigned( aPosFind - m_vColumnPositions.begin() ),
+ "Invalid index for vector!" );
+ m_vColumnTypes[ aPosFind - m_vColumnPositions.begin() ] = (*aFind)->second->GetType();
+ }
+ }
+ }
+ }
+
+ return xTable;
+}
+
+bool OCopyTableWizard::supportsPrimaryKey( const Reference< XConnection >& _rxConnection )
+{
+ OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsPrimaryKey: invalid connection!" );
+ if ( !_rxConnection.is() )
+ return false;
+
+ ::dbtools::DatabaseMetaData aMetaData( _rxConnection );
+ return aMetaData.supportsPrimaryKeys();
+}
+
+bool OCopyTableWizard::supportsViews( const Reference< XConnection >& _rxConnection )
+{
+ OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsViews: invalid connection!" );
+ if ( !_rxConnection.is() )
+ return false;
+
+ bool bSupportsViews( false );
+ try
+ {
+ Reference< XDatabaseMetaData > xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW );
+ Reference< XViewsSupplier > xViewSups( _rxConnection, UNO_QUERY );
+ bSupportsViews = xViewSups.is();
+ if ( !bSupportsViews )
+ {
+ try
+ {
+ Reference< XResultSet > xRs( xMetaData->getTableTypes(), UNO_SET_THROW );
+ Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
+ while ( xRs->next() )
+ {
+ OUString sValue = xRow->getString( 1 );
+ if ( !xRow->wasNull() && sValue.equalsIgnoreAsciiCase("View") )
+ {
+ bSupportsViews = true;
+ break;
+ }
+ }
+ }
+ catch( const SQLException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSupportsViews;
+}
+
+sal_Int32 OCopyTableWizard::getMaxColumnNameLength() const
+{
+ sal_Int32 nLen = 0;
+ if ( m_xDestConnection.is() )
+ {
+ try
+ {
+ Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
+ nLen = xMetaData->getMaxColumnNameLength();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ return nLen;
+}
+
+void OCopyTableWizard::setOperation( const sal_Int16 _nOperation )
+{
+ m_nOperation = _nOperation;
+}
+
+
+OUString OCopyTableWizard::convertColumnName(const TColumnFindFunctor& _rCmpFunctor,
+ const OUString& _sColumnName,
+ std::u16string_view _sExtraChars,
+ sal_Int32 _nMaxNameLen)
+{
+ OUString sAlias = _sColumnName;
+ if ( isSQL92CheckEnabled( m_xDestConnection ) )
+ sAlias = ::dbtools::convertName2SQLName(_sColumnName,_sExtraChars);
+ if((_nMaxNameLen && sAlias.getLength() > _nMaxNameLen) || _rCmpFunctor(sAlias))
+ {
+ sal_Int32 nDiff = 1;
+ do
+ {
+ ++nDiff;
+ if(_nMaxNameLen && sAlias.getLength() >= _nMaxNameLen)
+ sAlias = sAlias.copy(0,sAlias.getLength() - (sAlias.getLength()-_nMaxNameLen+nDiff));
+
+ OUString sName(sAlias);
+ sal_Int32 nPos = 1;
+ sName += OUString::number(nPos);
+
+ while(_rCmpFunctor(sName))
+ {
+ sName = sAlias + OUString::number(++nPos);
+ }
+ sAlias = sName;
+ // we have to check again, it could happen that the name is already too long
+ }
+ while(_nMaxNameLen && sAlias.getLength() > _nMaxNameLen);
+ }
+ OSL_ENSURE(m_mNameMapping.find(_sColumnName) == m_mNameMapping.end(),"name doubled!");
+ m_mNameMapping[_sColumnName] = sAlias;
+ return sAlias;
+}
+
+void OCopyTableWizard::removeColumnNameFromNameMap(const OUString& _sName)
+{
+ m_mNameMapping.erase(_sName);
+}
+
+bool OCopyTableWizard::supportsType(sal_Int32 _nDataType, sal_Int32& _rNewDataType)
+{
+ bool bRet = m_aDestTypeInfo.find(_nDataType) != m_aDestTypeInfo.end();
+ if ( bRet )
+ _rNewDataType = _nDataType;
+ return bRet;
+}
+
+TOTypeInfoSP OCopyTableWizard::convertType(const TOTypeInfoSP& _pType, bool& _bNotConvert)
+{
+ if ( !m_bInterConnectionCopy )
+ // no need to convert if the source and destination connection are the same
+ return _pType;
+
+ bool bForce;
+ TOTypeInfoSP pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,_pType->nType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce);
+ if ( !pType || bForce )
+ { // no type found so we have to find the correct one ourself
+ sal_Int32 nDefaultType = DataType::VARCHAR;
+ switch(_pType->nType)
+ {
+ case DataType::TINYINT:
+ if(supportsType(DataType::SMALLINT,nDefaultType))
+ break;
+ [[fallthrough]];
+ case DataType::SMALLINT:
+ if(supportsType(DataType::INTEGER,nDefaultType))
+ break;
+ [[fallthrough]];
+ case DataType::INTEGER:
+ if(supportsType(DataType::FLOAT,nDefaultType))
+ break;
+ [[fallthrough]];
+ case DataType::FLOAT:
+ if(supportsType(DataType::REAL,nDefaultType))
+ break;
+ [[fallthrough]];
+ case DataType::DATE:
+ case DataType::TIME:
+ if( DataType::DATE == _pType->nType || DataType::TIME == _pType->nType )
+ {
+ if(supportsType(DataType::TIMESTAMP,nDefaultType))
+ break;
+ }
+ [[fallthrough]];
+ case DataType::TIMESTAMP:
+ case DataType::REAL:
+ case DataType::BIGINT:
+ if ( supportsType(DataType::DOUBLE,nDefaultType) )
+ break;
+ [[fallthrough]];
+ case DataType::DOUBLE:
+ if ( supportsType(DataType::NUMERIC,nDefaultType) )
+ break;
+ [[fallthrough]];
+ case DataType::NUMERIC:
+ supportsType(DataType::DECIMAL,nDefaultType);
+ break;
+ case DataType::DECIMAL:
+ if ( supportsType(DataType::NUMERIC,nDefaultType) )
+ break;
+ if ( supportsType(DataType::DOUBLE,nDefaultType) )
+ break;
+ break;
+ case DataType::VARCHAR:
+ if ( supportsType(DataType::LONGVARCHAR,nDefaultType) )
+ break;
+ break;
+ case DataType::LONGVARCHAR:
+ if ( supportsType(DataType::CLOB,nDefaultType) )
+ break;
+ break;
+ case DataType::BINARY:
+ if ( supportsType(DataType::VARBINARY,nDefaultType) )
+ break;
+ break;
+ case DataType::VARBINARY:
+ if ( supportsType(DataType::LONGVARBINARY,nDefaultType) )
+ break;
+ break;
+ case DataType::LONGVARBINARY:
+ if ( supportsType(DataType::BLOB,nDefaultType) )
+ break;
+ if ( supportsType(DataType::LONGVARCHAR,nDefaultType) )
+ break;
+ if ( supportsType(DataType::CLOB,nDefaultType) )
+ break;
+ break;
+ default:
+ nDefaultType = DataType::VARCHAR;
+ }
+ pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,nDefaultType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce);
+ if ( !pType )
+ {
+ _bNotConvert = false;
+ pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,DataType::VARCHAR,_pType->aTypeName,"x",50,0,false,bForce);
+ if ( !pType )
+ pType = m_pTypeInfo;
+ }
+ else if ( bForce )
+ _bNotConvert = false;
+ }
+ return pType;
+}
+
+OUString OCopyTableWizard::createUniqueName(const OUString& _sName)
+{
+ OUString sName = _sName;
+ Sequence< OUString > aColumnNames( m_rSourceObject.getColumnNames() );
+ if ( aColumnNames.hasElements() )
+ sName = ::dbtools::createUniqueName( aColumnNames, sName, false );
+ else
+ {
+ if ( m_vSourceColumns.find(sName) != m_vSourceColumns.end())
+ {
+ sal_Int32 nPos = 0;
+ while(m_vSourceColumns.find(sName) != m_vSourceColumns.end())
+ {
+ sName = _sName + OUString::number(++nPos);
+ }
+ }
+ }
+ return sName;
+}
+
+void OCopyTableWizard::showColumnTypeNotSupported(std::u16string_view _rColumnName)
+{
+ OUString sMessage( DBA_RES( STR_UNKNOWN_TYPE_FOUND ) );
+ sMessage = sMessage.replaceFirst("#1",_rColumnName);
+ showError(sMessage);
+}
+
+void OCopyTableWizard::showError(const OUString& _sErrorMessage)
+{
+ SQLExceptionInfo aInfo(_sErrorMessage);
+ showError(aInfo.get());
+}
+
+void OCopyTableWizard::showError(const Any& _aError)
+{
+ if ( _aError.hasValue() && m_xInteractionHandler.is() )
+ {
+ try
+ {
+ ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( _aError ) );
+ m_xInteractionHandler->handle( xRequest );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/WExtendPages.cxx b/dbaccess/source/ui/misc/WExtendPages.cxx
new file mode 100644
index 000000000..c7eac9181
--- /dev/null
+++ b/dbaccess/source/ui/misc/WExtendPages.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <WExtendPages.hxx>
+#include <RtfReader.hxx>
+#include <HtmlReader.hxx>
+#include <WCopyTable.hxx>
+
+using namespace com::sun::star;
+
+namespace dbaui
+{
+
+void OWizHTMLExtend::createReaderAndCallParser(sal_Int32 _nRows)
+{
+ tools::SvRef<OHTMLReader> xParser = new OHTMLReader(*m_pParserStream,
+ _nRows,
+ std::vector(m_pParent->GetColumnPositions()),
+ m_pParent->GetFormatter(),
+ m_pParent->GetComponentContext(),
+ &m_pParent->getDestVector(),
+ &m_pParent->getTypeInfo(),
+ m_pParent->shouldCreatePrimaryKey());
+ xParser->CallParser();
+}
+
+void OWizRTFExtend::createReaderAndCallParser(sal_Int32 _nRows)
+{
+ tools::SvRef<ORTFReader> xParser = new ORTFReader(*m_pParserStream,
+ _nRows,
+ std::vector(m_pParent->GetColumnPositions()),
+ m_pParent->GetFormatter(),
+ m_pParent->GetComponentContext(),
+ &m_pParent->getDestVector(),
+ &m_pParent->getTypeInfo(),
+ m_pParent->shouldCreatePrimaryKey());
+ xParser->CallParser();
+}
+
+void OWizNormalExtend::createReaderAndCallParser(sal_Int32 /*_nRows*/)
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/WNameMatch.cxx b/dbaccess/source/ui/misc/WNameMatch.cxx
new file mode 100644
index 000000000..a6bb59da8
--- /dev/null
+++ b/dbaccess/source/ui/misc/WNameMatch.cxx
@@ -0,0 +1,330 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <WNameMatch.hxx>
+#include <osl/diagnose.h>
+#include <FieldDescriptions.hxx>
+#include <WCopyTable.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <com/sun/star/sdbc/DataType.hpp>
+
+using namespace ::dbaui;
+
+// OWizColumnSelect
+OWizNameMatching::OWizNameMatching(weld::Container* pPage, OCopyTableWizard* pWizard)
+ : OWizardPage(pPage, pWizard, "dbaccess/ui/namematchingpage.ui", "NameMatching")
+ , m_xTABLE_LEFT(m_xBuilder->weld_label("leftlabel"))
+ , m_xTABLE_RIGHT(m_xBuilder->weld_label("rightlabel"))
+ , m_xCTRL_LEFT(m_xBuilder->weld_tree_view("left"))
+ , m_xCTRL_RIGHT(m_xBuilder->weld_tree_view("right"))
+ , m_xColumn_up(m_xBuilder->weld_button("up"))
+ , m_xColumn_down(m_xBuilder->weld_button("down"))
+ , m_xColumn_up_right(m_xBuilder->weld_button("up_right"))
+ , m_xColumn_down_right(m_xBuilder->weld_button("down_right"))
+ , m_xAll(m_xBuilder->weld_button("all"))
+ , m_xNone(m_xBuilder->weld_button("none"))
+{
+ OUString aImgUp(BMP_UP);
+ OUString aImgDown(BMP_DOWN);
+ m_xColumn_up->set_from_icon_name(aImgUp);
+ m_xColumn_down->set_from_icon_name(aImgDown);
+ m_xColumn_up_right->set_from_icon_name(aImgUp);
+ m_xColumn_down_right->set_from_icon_name(aImgDown);
+
+ m_xColumn_up->connect_clicked(LINK(this,OWizNameMatching,ButtonClickHdl));
+ m_xColumn_down->connect_clicked(LINK(this,OWizNameMatching,ButtonClickHdl));
+
+ m_xColumn_up_right->connect_clicked(LINK(this,OWizNameMatching,RightButtonClickHdl));
+ m_xColumn_down_right->connect_clicked(LINK(this,OWizNameMatching,RightButtonClickHdl));
+
+ m_xAll->connect_clicked(LINK(this,OWizNameMatching,AllNoneClickHdl));
+ m_xNone->connect_clicked(LINK(this,OWizNameMatching,AllNoneClickHdl));
+
+ m_xCTRL_LEFT->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ m_xCTRL_LEFT->connect_changed(LINK(this,OWizNameMatching,TableListClickHdl));
+ m_xCTRL_RIGHT->connect_changed(LINK(this,OWizNameMatching,TableListRightSelectHdl));
+
+ m_sSourceText = m_xTABLE_LEFT->get_label() + "\n";
+ m_sDestText = m_xTABLE_RIGHT->get_label() + "\n";
+}
+
+OWizNameMatching::~OWizNameMatching()
+{
+}
+
+void OWizNameMatching::Reset()
+{
+ m_bFirstTime = false;
+}
+
+void OWizNameMatching::Activate( )
+{
+ // set source table name
+ OUString aName = m_sSourceText + m_pParent->m_sSourceName;
+
+ m_xTABLE_LEFT->set_label(aName);
+
+ // set dest table name
+ aName = m_sDestText + m_pParent->m_sName;
+ m_xTABLE_RIGHT->set_label(aName);
+
+ FillListBox(*m_xCTRL_LEFT, m_pParent->getSrcVector(), true);
+ FillListBox(*m_xCTRL_RIGHT, m_pParent->getDestVector(), false);
+
+ m_xColumn_up->set_sensitive( m_xCTRL_LEFT->n_children() > 1 );
+ m_xColumn_down->set_sensitive( m_xCTRL_LEFT->n_children() > 1 );
+
+ m_xColumn_up_right->set_sensitive( m_xCTRL_RIGHT->n_children() > 1 );
+ m_xColumn_down_right->set_sensitive( m_xCTRL_RIGHT->n_children() > 1 );
+
+ m_pParent->EnableNextButton(false);
+ m_xCTRL_LEFT->grab_focus();
+ TableListClickHdl(*m_xCTRL_LEFT);
+}
+
+bool OWizNameMatching::LeavePage()
+{
+
+ const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector();
+
+ m_pParent->m_vColumnPositions.clear();
+ m_pParent->m_vColumnTypes.clear();
+ m_pParent->m_vColumnPositions.resize( rSrcColumns.size(), ODatabaseExport::TPositions::value_type( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ) );
+ m_pParent->m_vColumnTypes.resize( rSrcColumns.size(), COLUMN_POSITION_NOT_FOUND );
+
+ std::unique_ptr<weld::TreeIter> xLeftEntry = m_xCTRL_LEFT->make_iterator();
+ std::unique_ptr<weld::TreeIter> xRightEntry = m_xCTRL_RIGHT->make_iterator();
+
+ sal_Int32 nParamPos = 0;
+ bool bLeftEntry = m_xCTRL_LEFT->get_iter_first(*xLeftEntry);
+ bool bRightEntry = m_xCTRL_RIGHT->get_iter_first(*xRightEntry);
+ while (bLeftEntry && bRightEntry)
+ {
+ OFieldDescription* pSrcField = weld::fromId<OFieldDescription*>(m_xCTRL_LEFT->get_id(*xLeftEntry));
+ OSL_ENSURE(pSrcField,"OWizNameMatching: OColumn can not be null!");
+
+ sal_Int32 nPos = 0;
+ for (auto const& column : rSrcColumns)
+ {
+ if (column->second == pSrcField)
+ break;
+ ++nPos;
+ }
+
+ if (m_xCTRL_LEFT->get_toggle(*xLeftEntry) == TRISTATE_TRUE)
+ {
+ OFieldDescription* pDestField = weld::fromId<OFieldDescription*>(m_xCTRL_RIGHT->get_id(*xRightEntry));
+ OSL_ENSURE(pDestField,"OWizNameMatching: OColumn can not be null!");
+ const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector();
+ sal_Int32 nPosDest = 1;
+ bool bDestColumnFound = false;
+ TOTypeInfoSP typeInfoSPFound;
+ for (auto const& column : rDestColumns)
+ {
+ if (column->second == pDestField)
+ {
+ bDestColumnFound = true;
+ typeInfoSPFound = column->second->getSpecialTypeInfo();
+ break;
+ }
+ ++nPosDest;
+ }
+
+ OSL_ENSURE((nPos) < static_cast<sal_Int32>(m_pParent->m_vColumnPositions.size()),"m_pParent->m_vColumnPositions: Illegal index for vector");
+ m_pParent->m_vColumnPositions[nPos].first = ++nParamPos;
+ m_pParent->m_vColumnPositions[nPos].second = nPosDest;
+
+ TOTypeInfoSP pTypeInfo;
+
+ assert(bDestColumnFound);
+ if (bDestColumnFound)
+ {
+ bool bNotConvert = true;
+ pTypeInfo = m_pParent->convertType(typeInfoSPFound, bNotConvert);
+ }
+
+ sal_Int32 nType = css::sdbc::DataType::VARCHAR;
+ if ( pTypeInfo )
+ nType = pTypeInfo->nType;
+ m_pParent->m_vColumnTypes[nPos] = nType;
+ }
+ else
+ {
+ m_pParent->m_vColumnPositions[nPos].first = COLUMN_POSITION_NOT_FOUND;
+ m_pParent->m_vColumnPositions[nPos].second = COLUMN_POSITION_NOT_FOUND;
+ }
+
+ bLeftEntry = m_xCTRL_LEFT->iter_next(*xLeftEntry);
+ bRightEntry = m_xCTRL_RIGHT->iter_next(*xRightEntry);
+ }
+
+ return true;
+}
+
+OUString OWizNameMatching::GetTitle() const { return DBA_RES(STR_WIZ_NAME_MATCHING_TITLE); }
+
+IMPL_LINK(OWizNameMatching, ButtonClickHdl, weld::Button&, rButton, void)
+{
+ int nPos = m_xCTRL_LEFT->get_selected_index();
+ if (nPos == -1)
+ return;
+
+ int nOrigPos = nPos;
+ if (&rButton == m_xColumn_up.get() && nPos)
+ --nPos;
+ else if (&rButton == m_xColumn_down.get() && nPos < m_xCTRL_LEFT->n_children() - 1)
+ ++nPos;
+
+ m_xCTRL_LEFT->swap(nOrigPos, nPos);
+
+ m_xCTRL_LEFT->scroll_to_row(nPos);
+
+ TableListClickHdl(*m_xCTRL_LEFT);
+}
+
+IMPL_LINK( OWizNameMatching, RightButtonClickHdl, weld::Button&, rButton, void )
+{
+ int nPos = m_xCTRL_RIGHT->get_selected_index();
+ if (nPos == -1)
+ return;
+
+ int nOrigPos = nPos;
+ if (&rButton == m_xColumn_up_right.get() && nPos)
+ --nPos;
+ else if (&rButton == m_xColumn_down_right.get() && nPos < m_xCTRL_RIGHT->n_children() - 1)
+ ++nPos;
+
+ m_xCTRL_RIGHT->swap(nOrigPos, nPos);
+
+ m_xCTRL_RIGHT->scroll_to_row(nPos);
+
+ TableListRightSelectHdl(*m_xCTRL_RIGHT);
+}
+
+namespace
+{
+ int GetFirstEntryInView(weld::TreeView& rTreeView)
+ {
+ int nFirstEntryInView = -1;
+
+ rTreeView.visible_foreach([&nFirstEntryInView, &rTreeView](weld::TreeIter& rEntry){
+ nFirstEntryInView = rTreeView.get_iter_index_in_parent(rEntry);
+ // stop after first entry
+ return true;
+ });
+
+ return nFirstEntryInView;
+ }
+}
+
+IMPL_LINK_NOARG(OWizNameMatching, TableListClickHdl, weld::TreeView&, void)
+{
+ int nPos = m_xCTRL_LEFT->get_selected_index();
+ if (nPos == -1)
+ return;
+
+ int nOldEntry = m_xCTRL_RIGHT->get_selected_index();
+ if (nOldEntry != -1 && nPos != nOldEntry)
+ {
+ m_xCTRL_RIGHT->unselect(nOldEntry);
+ if (nPos < m_xCTRL_RIGHT->n_children())
+ {
+ int nNewPos = GetFirstEntryInView(*m_xCTRL_LEFT);
+ if ( nNewPos - nPos == 1 )
+ --nNewPos;
+ m_xCTRL_RIGHT->scroll_to_row(nNewPos);
+ m_xCTRL_RIGHT->select(nPos);
+ }
+ }
+ else if (nOldEntry == -1)
+ {
+ if (nPos < m_xCTRL_RIGHT->n_children())
+ m_xCTRL_RIGHT->select(nPos);
+ }
+}
+
+IMPL_LINK_NOARG( OWizNameMatching, TableListRightSelectHdl, weld::TreeView&, void )
+{
+ int nPos = m_xCTRL_RIGHT->get_selected_index();
+ if (nPos == -1)
+ return;
+
+ OFieldDescription* pColumn = weld::fromId<OFieldDescription*>(m_xCTRL_RIGHT->get_id(nPos));
+ if (pColumn->IsAutoIncrement())
+ {
+ m_xCTRL_RIGHT->unselect(nPos);
+ return;
+ }
+
+ int nOldEntry = m_xCTRL_LEFT->get_selected_index();
+ if (nOldEntry != -1 && nPos != nOldEntry)
+ {
+ m_xCTRL_LEFT->unselect(nOldEntry);
+ if (nPos < m_xCTRL_LEFT->n_children())
+ {
+ int nNewPos = GetFirstEntryInView(*m_xCTRL_RIGHT);
+ if ( nNewPos - nPos == 1 )
+ nNewPos--;
+ m_xCTRL_LEFT->scroll_to_row(nNewPos);
+ m_xCTRL_LEFT->select(nPos);
+ }
+ }
+ else if (nOldEntry == -1)
+ {
+ if (nPos < m_xCTRL_LEFT->n_children())
+ m_xCTRL_LEFT->select(nPos);
+ }
+}
+
+IMPL_LINK(OWizNameMatching, AllNoneClickHdl, weld::Button&, rButton, void)
+{
+ bool bAll = &rButton == m_xAll.get();
+ m_xCTRL_LEFT->all_foreach([this, bAll](weld::TreeIter& rEntry){
+ m_xCTRL_LEFT->set_toggle(rEntry, bAll ? TRISTATE_TRUE : TRISTATE_FALSE);
+ return false;
+ });
+}
+
+void OWizNameMatching::FillListBox(weld::TreeView& rTreeView, const ODatabaseExport::TColumnVector& rList, bool bCheckButtons)
+{
+ rTreeView.clear();
+
+ int nRow(0);
+
+ for (auto const& elem : rList)
+ {
+ rTreeView.append();
+ if (bCheckButtons)
+ {
+ bool bChecked = !elem->second->IsAutoIncrement();
+ rTreeView.set_toggle(nRow, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
+ }
+ rTreeView.set_text(nRow, elem->first, 0);
+ rTreeView.set_id(nRow, weld::toId(elem->second));
+ ++nRow;
+ }
+
+ if (rTreeView.n_children())
+ rTreeView.select(0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/WTypeSelect.cxx b/dbaccess/source/ui/misc/WTypeSelect.cxx
new file mode 100644
index 000000000..d5462ed3f
--- /dev/null
+++ b/dbaccess/source/ui/misc/WTypeSelect.cxx
@@ -0,0 +1,417 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <WTypeSelect.hxx>
+#include <bitmaps.hlst>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <FieldDescriptions.hxx>
+#include <WCopyTable.hxx>
+#include <strings.hrc>
+#include <tools/stream.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <UITools.hxx>
+#include <core_resource.hxx>
+#include <FieldControls.hxx>
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdbc;
+
+// OWizTypeSelectControl
+OWizTypeSelectControl::OWizTypeSelectControl(weld::Container* pPage, OWizTypeSelect* pParentTabPage)
+ : OFieldDescControl(pPage, nullptr)
+ , m_pParentTabPage(pParentTabPage)
+{
+}
+
+OWizTypeSelectControl::~OWizTypeSelectControl()
+{
+}
+
+void OWizTypeSelectControl::ActivateAggregate( EControlType eType )
+{
+ switch(eType )
+ {
+ case tpFormat:
+ case tpDefault:
+ case tpAutoIncrement:
+ case tpAutoIncrementValue:
+ break;
+ default:
+ OFieldDescControl::ActivateAggregate( eType );
+ }
+}
+
+void OWizTypeSelectControl::DeactivateAggregate( EControlType eType )
+{
+ switch(eType )
+ {
+ case tpFormat:
+ case tpDefault:
+ case tpAutoIncrement:
+ case tpAutoIncrementValue:
+ break;
+ default:
+ OFieldDescControl::DeactivateAggregate( eType );
+ }
+}
+
+void OWizTypeSelectControl::CellModified(sal_Int32 nRow, sal_uInt16 nColId )
+{
+ OSL_ENSURE(nRow == -1,"nRow must be -1!");
+
+ weld::TreeView* pListBox = m_pParentTabPage->m_xColumnNames->GetWidget();
+
+ OFieldDescription* pCurFieldDescr = getCurrentFieldDescData();
+
+ const sal_Int32 nPos = pListBox->find_text(pCurFieldDescr->GetName());
+ pCurFieldDescr = weld::fromId<OFieldDescription*>(pListBox->get_id(nPos));
+ OSL_ENSURE( pCurFieldDescr, "OWizTypeSelectControl::CellModified: Columnname/type not found in the listbox!" );
+ if ( !pCurFieldDescr )
+ return;
+ setCurrentFieldDescData( pCurFieldDescr );
+
+ OUString sName = pCurFieldDescr->GetName();
+ OUString sNewName;
+ const OPropColumnEditCtrl* pColumnName = getColumnCtrl();
+ if ( pColumnName )
+ sNewName = pColumnName->get_text();
+
+ switch(nColId)
+ {
+ case FIELD_PROPERTY_COLUMNNAME:
+ {
+ OCopyTableWizard* pWiz = m_pParentTabPage->m_pParent;
+ // first we have to check if this name already exists
+ bool bDoubleName = false;
+ bool bCase = true;
+ if ( getMetaData().is() && !getMetaData()->supportsMixedCaseQuotedIdentifiers() )
+ {
+ bCase = false;
+ const sal_Int32 nCount = pListBox->n_children();
+ for (sal_Int32 i=0 ; !bDoubleName && i < nCount ; ++i)
+ {
+ OUString sEntry(pListBox->get_text(i));
+ bDoubleName = sNewName.equalsIgnoreAsciiCase(sEntry);
+ }
+ if ( !bDoubleName && pWiz->shouldCreatePrimaryKey() )
+ bDoubleName = sNewName.equalsIgnoreAsciiCase(pWiz->getPrimaryKeyName());
+
+ }
+ else
+ bDoubleName = ((pListBox->find_text(sNewName) != -1)
+ || ( pWiz->shouldCreatePrimaryKey()
+ && pWiz->getPrimaryKeyName() == sNewName) );
+
+ if ( bDoubleName )
+ {
+ OUString strMessage = DBA_RES(STR_TABLEDESIGN_DUPLICATE_NAME);
+ strMessage = strMessage.replaceFirst("$column$", sNewName);
+ pWiz->showError(strMessage);
+ pCurFieldDescr->SetName(sName);
+ DisplayData(pCurFieldDescr);
+ m_pParentTabPage->setDuplicateName(true);
+ return;
+ }
+
+ OUString sOldName = pCurFieldDescr->GetName();
+ pCurFieldDescr->SetName(sNewName);
+ m_pParentTabPage->setDuplicateName(false);
+
+ // now we change the name
+
+ ::comphelper::UStringMixEqual aCase(bCase);
+ for (auto & elem : pWiz->m_mNameMapping)
+ {
+ if ( aCase(elem.second,sName) )
+ {
+ elem.second = sNewName;
+ break;
+ }
+ }
+
+ pListBox->remove(nPos);
+ pListBox->insert_text(nPos, pCurFieldDescr->GetName());
+ pListBox->set_id(nPos, weld::toId(pCurFieldDescr));
+
+ pWiz->replaceColumn(nPos,pCurFieldDescr,sOldName);
+ }
+ break;
+ }
+ saveCurrentFieldDescData();
+}
+
+css::lang::Locale OWizTypeSelectControl::GetLocale() const
+{
+ return m_pParentTabPage->m_pParent->GetLocale();
+}
+
+Reference< XNumberFormatter > OWizTypeSelectControl::GetFormatter() const
+{
+ return m_pParentTabPage->m_pParent->GetFormatter();
+}
+
+TOTypeInfoSP OWizTypeSelectControl::getTypeInfo(sal_Int32 _nPos)
+{
+ return m_pParentTabPage->m_pParent->getDestTypeInfo(_nPos);
+}
+
+const OTypeInfoMap* OWizTypeSelectControl::getTypeInfo() const
+{
+ return &m_pParentTabPage->m_pParent->getDestTypeInfo();
+}
+
+css::uno::Reference< css::sdbc::XDatabaseMetaData> OWizTypeSelectControl::getMetaData()
+{
+ return m_pParentTabPage->m_pParent->m_xDestConnection->getMetaData();
+}
+
+css::uno::Reference< css::sdbc::XConnection> OWizTypeSelectControl::getConnection()
+{
+ return m_pParentTabPage->m_pParent->m_xDestConnection;
+}
+
+bool OWizTypeSelectControl::isAutoIncrementValueEnabled() const
+{
+ return m_pParentTabPage->m_bAutoIncrementEnabled;
+}
+
+OUString OWizTypeSelectControl::getAutoIncrementValue() const
+{
+ return m_pParentTabPage->m_sAutoIncrementValue;
+}
+
+OWizTypeSelect::OWizTypeSelect(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream* pStream)
+ : OWizardPage(pPage, pWizard, "dbaccess/ui/typeselectpage.ui", "TypeSelect")
+ , m_xColumnNames(new OWizTypeSelectList(m_xBuilder->weld_tree_view("columnnames")))
+ , m_xColumns(m_xBuilder->weld_label("columns"))
+ , m_xControlContainer(m_xBuilder->weld_container("control_container"))
+ , m_xTypeControl(new OWizTypeSelectControl(m_xControlContainer.get(), this))
+ , m_xAutoType(m_xBuilder->weld_label("autotype"))
+ , m_xAutoFt(m_xBuilder->weld_label("autolabel"))
+ , m_xAutoEt(m_xBuilder->weld_spin_button("auto"))
+ , m_xAutoPb(m_xBuilder->weld_button("autobutton"))
+ , m_pParserStream(pStream)
+ , m_nDisplayRow(0)
+ , m_bAutoIncrementEnabled(false)
+ , m_bDuplicateName(false)
+{
+ m_xColumnNames->connect_changed(LINK(this,OWizTypeSelect,ColumnSelectHdl));
+
+ m_xTypeControl->Init();
+
+ m_xAutoEt->set_text("10");
+ m_xAutoEt->set_digits(0);
+ m_xAutoPb->connect_clicked(LINK(this,OWizTypeSelect,ButtonClickHdl));
+ m_xColumnNames->set_selection_mode(SelectionMode::Multiple);
+
+ try
+ {
+ m_xColumnNames->SetPKey( m_pParent->supportsPrimaryKey() );
+ ::dbaui::fillAutoIncrementValue( m_pParent->m_xDestConnection, m_bAutoIncrementEnabled, m_sAutoIncrementValue );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OWizTypeSelect::~OWizTypeSelect()
+{
+}
+
+OUString OWizTypeSelect::GetTitle() const
+{
+ return DBA_RES(STR_WIZ_TYPE_SELECT_TITLE);
+}
+
+IMPL_LINK_NOARG(OWizTypeSelect, ColumnSelectHdl, weld::TreeView&, void)
+{
+ OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xColumnNames->get_selected_id());
+ if (pField)
+ m_xTypeControl->DisplayData(pField);
+
+ m_xTypeControl->Enable(m_xColumnNames->count_selected_rows() == 1);
+}
+
+void OWizTypeSelect::Reset()
+{
+ // restore original state
+ m_xColumnNames->clear();
+ sal_Int32 nCount(0), nBreakPos;
+ m_pParent->CheckColumns(nBreakPos);
+
+ const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector();
+ for (auto const& column : rDestColumns)
+ {
+ OUString sId(weld::toId(column->second));
+ m_xColumnNames->append(sId, column->first);
+ if (column->second->IsPrimaryKey())
+ m_xColumnNames->set_image(nCount, BMP_PRIMARY_KEY);
+ ++nCount;
+ }
+ m_bFirstTime = false;
+}
+
+void OWizTypeSelect::Activate( )
+{
+ bool bOldFirstTime = m_bFirstTime;
+ Reset();
+ m_bFirstTime = bOldFirstTime;
+
+ m_xColumnNames->select(m_nDisplayRow);
+ m_nDisplayRow = 0;
+ ColumnSelectHdl(*m_xColumnNames->GetWidget());
+}
+
+bool OWizTypeSelect::LeavePage()
+{
+ bool bDuplicateName = false;
+ OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xColumnNames->get_selected_id());
+ if ( pField )
+ {
+ m_xTypeControl->SaveData(pField);
+ bDuplicateName = m_bDuplicateName;
+ }
+ return !bDuplicateName;
+}
+
+void OWizTypeSelect::EnableAuto(bool bEnable)
+{
+ m_xAutoFt->set_visible(bEnable);
+ m_xAutoEt->set_visible(bEnable);
+ m_xAutoPb->set_visible(bEnable);
+ m_xAutoType->set_visible(bEnable);
+}
+
+IMPL_LINK_NOARG(OWizTypeSelect, ButtonClickHdl, weld::Button&, void)
+{
+ sal_Int32 nBreakPos;
+ m_pParent->CheckColumns(nBreakPos);
+
+ // fill column list
+ sal_uInt32 nRows = m_xAutoEt->get_text().toInt32();
+ if(m_pParserStream)
+ {
+ sal_uInt64 const nTell = m_pParserStream->Tell(); // might change seek position of stream
+
+ createReaderAndCallParser(nRows);
+ m_pParserStream->Seek(nTell);
+ }
+
+ Activate();
+}
+
+OWizTypeSelectList::OWizTypeSelectList(std::unique_ptr<weld::TreeView> xControl)
+ : m_xControl(std::move(xControl))
+ , m_bPKey(false)
+{
+ m_xControl->connect_popup_menu(LINK(this, OWizTypeSelectList, CommandHdl));
+}
+
+bool OWizTypeSelectList::IsPrimaryKeyAllowed() const
+{
+ auto aRows = m_xControl->get_selected_rows();
+ std::sort(aRows.begin(), aRows.end());
+
+ const sal_Int32 nCount = aRows.size();
+
+ for( sal_Int32 j = 0; m_bPKey && j < nCount; ++j )
+ {
+ OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xControl->get_id(aRows[j]));
+ if(!pField || pField->getTypeInfo()->nSearchType == ColumnSearch::NONE)
+ return false;
+ }
+ return true;
+}
+
+void OWizTypeSelectList::setPrimaryKey(OFieldDescription* _pFieldDescr, sal_uInt16 _nPos, bool _bSet)
+{
+ _pFieldDescr->SetPrimaryKey(_bSet);
+ if( _bSet )
+ {
+ m_xControl->set_image(_nPos, BMP_PRIMARY_KEY);
+ }
+ else if( _pFieldDescr->getTypeInfo()->bNullable )
+ {
+ _pFieldDescr->SetControlDefault(Any());
+ m_xControl->set_image(_nPos, OUString());
+ }
+}
+
+IMPL_LINK(OWizTypeSelectList, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+ if (!IsPrimaryKeyAllowed())
+ return false;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xControl.get(), "dbaccess/ui/keymenu.ui"));
+ auto xContextMenu = xBuilder->weld_menu("menu");
+ // Should primary key checkbox be checked?
+ const sal_Int32 nCount = m_xControl->n_children();
+ bool bCheckOk = false;
+ for(sal_Int32 j = 0 ; j < nCount ; ++j)
+ {
+ OFieldDescription* pFieldDescr = weld::fromId<OFieldDescription*>(m_xControl->get_id(j));
+ // if at least one of the fields is selected but not in the primary key,
+ // or is in the primary key but not selected, then don't check the
+ // primary key checkbox.
+ if( pFieldDescr && pFieldDescr->IsPrimaryKey() != m_xControl->is_selected(j) )
+ {
+ bCheckOk = false;
+ break;
+ }
+ if (!bCheckOk && m_xControl->is_selected(j))
+ bCheckOk = true;
+ }
+
+ if (bCheckOk)
+ xContextMenu->set_active("primarykey", true);
+
+ OString sCommand(xContextMenu->popup_at_rect(m_xControl.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
+ if (sCommand != "primarykey")
+ return true;
+
+ for (sal_Int32 j = 0 ; j < nCount; ++j)
+ {
+ OFieldDescription* pFieldDescr = weld::fromId<OFieldDescription*>(m_xControl->get_id(j));
+ if (pFieldDescr)
+ {
+ if(!bCheckOk && m_xControl->is_selected(j))
+ {
+ setPrimaryKey(pFieldDescr,j,true);
+ }
+ else
+ {
+ setPrimaryKey(pFieldDescr,j);
+ }
+ }
+ }
+ m_aChangeHdl.Call(*m_xControl);
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/asyncmodaldialog.cxx b/dbaccess/source/ui/misc/asyncmodaldialog.cxx
new file mode 100644
index 000000000..3c59a58f8
--- /dev/null
+++ b/dbaccess/source/ui/misc/asyncmodaldialog.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <asyncmodaldialog.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::ui::dialogs::XExecutableDialog;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::Exception;
+
+ namespace {
+
+ // AsyncDialogExecutor
+ class DialogExecutor_Impl
+ {
+ Reference< XExecutableDialog > m_xDialog;
+
+ public:
+ explicit DialogExecutor_Impl( const Reference< XExecutableDialog >& _rxDialog )
+ :m_xDialog( _rxDialog )
+ {
+ }
+
+ void execute()
+ {
+ Application::PostUserEvent( LINK( this, DialogExecutor_Impl, onExecute ) );
+ }
+
+ protected:
+ ~DialogExecutor_Impl()
+ {
+ }
+
+ private:
+ DECL_LINK( onExecute, void*, void );
+ };
+
+ }
+
+ IMPL_LINK_NOARG( DialogExecutor_Impl, onExecute, void*, void )
+ {
+ try
+ {
+ m_xDialog->execute();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ delete this;
+ }
+
+ // AsyncDialogExecutor
+ void AsyncDialogExecutor::executeModalDialogAsync( const Reference< XExecutableDialog >& _rxDialog )
+ {
+ if ( !_rxDialog.is() )
+ throw IllegalArgumentException();
+
+ DialogExecutor_Impl* pExecutor = new DialogExecutor_Impl( _rxDialog );
+ pExecutor->execute();
+ // will delete itself
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/charsets.cxx b/dbaccess/source/ui/misc/charsets.cxx
new file mode 100644
index 000000000..546d21cb0
--- /dev/null
+++ b/dbaccess/source/ui/misc/charsets.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <charsets.hxx>
+#include <core_resource.hxx>
+#include <osl/diagnose.h>
+#include <strings.hrc>
+#include <rtl/tencinfo.h>
+#include <svx/txenctab.hxx>
+
+namespace dbaui
+{
+ using namespace ::dbtools;
+
+ // OCharsetDisplay
+ OCharsetDisplay::OCharsetDisplay()
+ : m_aSystemDisplayName(DBA_RES( STR_RSC_CHARSETS ))
+ {
+ }
+
+ bool OCharsetDisplay::approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const
+ {
+ if ( !OCharsetMap::approveEncoding( _eEncoding, _rInfo ) )
+ return false;
+
+ if ( RTL_TEXTENCODING_DONTKNOW == _eEncoding )
+ return true;
+
+ return !SvxTextEncodingTable::GetTextString(_eEncoding).isEmpty();
+ }
+
+ OCharsetDisplay::const_iterator OCharsetDisplay::begin() const
+ {
+ return const_iterator( this, OCharsetMap::begin() );
+ }
+
+ OCharsetDisplay::const_iterator OCharsetDisplay::end() const
+ {
+ return const_iterator( this, OCharsetMap::end() );
+ }
+
+ OCharsetDisplay::const_iterator OCharsetDisplay::findEncoding(const rtl_TextEncoding _eEncoding) const
+ {
+ OCharsetMap::const_iterator aBaseIter = OCharsetMap::find(_eEncoding);
+ return const_iterator( this, aBaseIter );
+ }
+
+ OCharsetDisplay::const_iterator OCharsetDisplay::findIanaName(const OUString& _rIanaName) const
+ {
+ OCharsetMap::const_iterator aBaseIter = OCharsetMap::findIanaName(_rIanaName);
+ return const_iterator( this, aBaseIter );
+ }
+
+ OCharsetDisplay::const_iterator OCharsetDisplay::findDisplayName(const OUString& _rDisplayName) const
+ {
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+ if ( _rDisplayName != m_aSystemDisplayName )
+ {
+ eEncoding = SvxTextEncodingTable::GetTextEncoding(_rDisplayName);
+ OSL_ENSURE( RTL_TEXTENCODING_DONTKNOW != eEncoding,
+ "OCharsetDisplay::find: non-empty display name, but DONTKNOW!" );
+ }
+ return const_iterator( this, OCharsetMap::find( eEncoding ) );
+ }
+
+ // CharsetDisplayDerefHelper
+ CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const CharsetDisplayDerefHelper& _rSource)
+ :CharsetDisplayDerefHelper_Base(_rSource)
+ ,m_sDisplayName(_rSource.m_sDisplayName)
+ {
+ }
+
+ CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const ::dbtools::CharsetIteratorDerefHelper& _rBase, const OUString& _rDisplayName)
+ :CharsetDisplayDerefHelper_Base(_rBase)
+ ,m_sDisplayName(_rDisplayName)
+ {
+ OSL_ENSURE( !m_sDisplayName.isEmpty(), "CharsetDisplayDerefHelper::CharsetDisplayDerefHelper: invalid display name!" );
+ }
+
+ // OCharsetDisplay::ExtendedCharsetIterator
+ OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, const base_iterator& _rPosition )
+ :m_pContainer(_pContainer)
+ ,m_aPosition(_rPosition)
+ {
+ OSL_ENSURE(m_pContainer, "OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator : invalid container!");
+ }
+
+ CharsetDisplayDerefHelper OCharsetDisplay::ExtendedCharsetIterator::operator*() const
+ {
+ OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator* : invalid position!");
+
+ rtl_TextEncoding eEncoding = (*m_aPosition).getEncoding();
+ return CharsetDisplayDerefHelper(
+ *m_aPosition,
+ RTL_TEXTENCODING_DONTKNOW == eEncoding ? m_pContainer->m_aSystemDisplayName : SvxTextEncodingTable::GetTextString(eEncoding)
+ );
+ }
+
+ const OCharsetDisplay::ExtendedCharsetIterator& OCharsetDisplay::ExtendedCharsetIterator::operator++()
+ {
+ OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator++ : invalid position!");
+ if ( m_aPosition != m_pContainer->OCharsetDisplay_Base::end() )
+ ++m_aPosition;
+ return *this;
+ }
+
+ bool operator==(const OCharsetDisplay::ExtendedCharsetIterator& lhs, const OCharsetDisplay::ExtendedCharsetIterator& rhs)
+ {
+ return (lhs.m_pContainer == rhs.m_pContainer) && (lhs.m_aPosition == rhs.m_aPosition);
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/controllerframe.cxx b/dbaccess/source/ui/misc/controllerframe.cxx
new file mode 100644
index 000000000..3634a56eb
--- /dev/null
+++ b/dbaccess/source/ui/misc/controllerframe.cxx
@@ -0,0 +1,390 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbaccess/controllerframe.hxx>
+#include <dbaccess/IController.hxx>
+
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <sfx2/objsh.hxx>
+#include <tools/diagnose_ex.h>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::frame::FrameAction;
+ using ::com::sun::star::frame::FrameAction_FRAME_ACTIVATED;
+ using ::com::sun::star::frame::FrameAction_FRAME_UI_ACTIVATED;
+ using ::com::sun::star::frame::FrameAction_FRAME_DEACTIVATING;
+ using ::com::sun::star::frame::FrameAction_FRAME_UI_DEACTIVATING;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::frame::XController2;
+ using ::com::sun::star::awt::XTopWindow;
+ using ::com::sun::star::awt::XTopWindowListener;
+ using ::com::sun::star::awt::XWindow2;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::document::XDocumentEventBroadcaster;
+ using ::com::sun::star::awt::XWindow;
+
+ // FrameWindowActivationListener
+ typedef ::cppu::WeakImplHelper< XTopWindowListener
+ > FrameWindowActivationListener_Base;
+
+ namespace {
+
+ class FrameWindowActivationListener : public FrameWindowActivationListener_Base
+ {
+ public:
+ explicit FrameWindowActivationListener( ControllerFrame_Data& _rData );
+
+ void dispose();
+
+ protected:
+ virtual ~FrameWindowActivationListener() override;
+
+ // XTopWindowListener
+ virtual void SAL_CALL windowOpened( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowClosing( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowClosed( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowMinimized( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowNormalized( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowActivated( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowDeactivated( const css::lang::EventObject& e ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ private:
+ void impl_checkDisposed_throw() const;
+ void impl_registerOnFrameContainerWindow_nothrow( bool _bRegister );
+
+ private:
+ ControllerFrame_Data* m_pData;
+ };
+
+ }
+
+ // ControllerFrame_Data
+ struct ControllerFrame_Data
+ {
+ explicit ControllerFrame_Data( IController& _rController )
+ :m_rController( _rController )
+ ,m_bActive( false )
+ ,m_bIsTopLevelDocumentWindow( false )
+ {
+ }
+
+ IController& m_rController;
+ Reference< XFrame > m_xFrame;
+ Reference< XDocumentEventBroadcaster > m_xDocEventBroadcaster;
+ ::rtl::Reference< FrameWindowActivationListener > m_pListener;
+ bool m_bActive;
+ bool m_bIsTopLevelDocumentWindow;
+ };
+
+ // helper
+ static void lcl_setFrame_nothrow( ControllerFrame_Data& _rData, const Reference< XFrame >& _rxFrame )
+ {
+ // release old listener
+ if (_rData.m_pListener)
+ {
+ _rData.m_pListener->dispose();
+ _rData.m_pListener = nullptr;
+ }
+
+ // remember new frame
+ _rData.m_xFrame = _rxFrame;
+
+ // create new listener
+ if ( _rData.m_xFrame.is() )
+ _rData.m_pListener = new FrameWindowActivationListener( _rData );
+
+ // at this point in time, we can assume the controller also has a model set, if it supports models
+ try
+ {
+ Reference< XController > xController( _rData.m_rController.getXController(), UNO_SET_THROW );
+ Reference< XModel > xModel( xController->getModel() );
+ if ( xModel.is() )
+ _rData.m_xDocEventBroadcaster.set( xModel, UNO_QUERY );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ static bool lcl_isActive_nothrow( const Reference< XFrame >& _rxFrame )
+ {
+ bool bIsActive = false;
+ try
+ {
+ if ( _rxFrame.is() )
+ {
+ Reference< XWindow2 > xWindow( _rxFrame->getContainerWindow(), UNO_QUERY_THROW );
+ bIsActive = xWindow->isActive();
+ }
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bIsActive;
+ }
+
+ /** updates various global and local states with a new active component
+
+ In particular, the following are updated
+ * the global working document (aka Basic's ThisComponent in the application
+ Basic), with our controller's model, or the controller itself if there is no such
+ model.
+ */
+ static void lcl_updateActiveComponents_nothrow( const ControllerFrame_Data& _rData )
+ {
+ try
+ {
+ Reference< XController > xCompController( _rData.m_rController.getXController() );
+ OSL_ENSURE( xCompController.is(), "lcl_updateActiveComponents_nothrow: can't do anything without a controller!" );
+ if ( !xCompController.is() )
+ return;
+
+ if ( _rData.m_bActive && _rData.m_bIsTopLevelDocumentWindow )
+ {
+ // set the "current component" at the SfxObjectShell
+ Reference< XModel > xModel( xCompController->getModel() );
+ Reference< XInterface > xCurrentComponent;
+ if ( xModel.is() )
+ xCurrentComponent = xModel;
+ else
+ xCurrentComponent = xCompController;
+ SfxObjectShell::SetCurrentComponent( xCurrentComponent );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ /** broadcasts the OnFocus resp. OnUnfocus event
+ */
+ static void lcl_notifyFocusChange_nothrow( ControllerFrame_Data& _rData, bool _bActive )
+ {
+ try
+ {
+ if ( _rData.m_xDocEventBroadcaster.is() )
+ {
+ OUString sEventName = _bActive ? OUString("OnFocus") : OUString("OnUnfocus");
+ Reference< XController2 > xController( _rData.m_rController.getXController(), UNO_QUERY_THROW );
+ _rData.m_xDocEventBroadcaster->notifyDocumentEvent( sEventName, xController, Any() );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ static void lcl_updateActive_nothrow( ControllerFrame_Data& _rData, bool _bActive )
+ {
+ if ( _rData.m_bActive == _bActive )
+ return;
+ _rData.m_bActive = _bActive;
+
+ lcl_updateActiveComponents_nothrow( _rData );
+ lcl_notifyFocusChange_nothrow( _rData, _bActive );
+ }
+
+ FrameWindowActivationListener::FrameWindowActivationListener( ControllerFrame_Data& _rData )
+ :m_pData( &_rData )
+ {
+ impl_registerOnFrameContainerWindow_nothrow( true );
+ }
+
+ FrameWindowActivationListener::~FrameWindowActivationListener()
+ {
+ }
+
+ void FrameWindowActivationListener::dispose()
+ {
+ impl_registerOnFrameContainerWindow_nothrow( false );
+ m_pData = nullptr;
+ }
+
+ void FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow( bool _bRegister )
+ {
+ OSL_ENSURE( m_pData && m_pData->m_xFrame.is(), "FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow: no frame!" );
+ if ( !m_pData || !m_pData->m_xFrame.is() )
+ return;
+
+ try
+ {
+ void ( SAL_CALL XTopWindow::*pListenerAction )( const Reference< XTopWindowListener >& ) =
+ _bRegister ? &XTopWindow::addTopWindowListener : &XTopWindow::removeTopWindowListener;
+
+ const Reference< XWindow > xContainerWindow( m_pData->m_xFrame->getContainerWindow(), UNO_SET_THROW );
+ if ( _bRegister )
+ {
+ const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
+ ENSURE_OR_THROW( pContainerWindow, "no Window implementation for the frame's container window!" );
+
+ m_pData->m_bIsTopLevelDocumentWindow = bool( pContainerWindow->GetExtendedStyle() & WindowExtendedStyle::Document );
+ }
+
+ const Reference< XTopWindow > xFrameContainer( xContainerWindow, UNO_QUERY );
+ if ( xFrameContainer.is() )
+ (xFrameContainer.get()->*pListenerAction)( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void FrameWindowActivationListener::impl_checkDisposed_throw() const
+ {
+ if ( !m_pData )
+ throw DisposedException( OUString(), *const_cast< FrameWindowActivationListener* >( this ) );
+ }
+
+ void SAL_CALL FrameWindowActivationListener::windowOpened( const EventObject& /*_rEvent*/ )
+ {
+ // not interested in
+ }
+
+ void SAL_CALL FrameWindowActivationListener::windowClosing( const EventObject& /*_rEvent*/ )
+ {
+ // not interested in
+ }
+
+ void SAL_CALL FrameWindowActivationListener::windowClosed( const EventObject& /*_rEvent*/ )
+ {
+ // not interested in
+ }
+
+ void SAL_CALL FrameWindowActivationListener::windowMinimized( const EventObject& /*_rEvent*/ )
+ {
+ // not interested in
+ }
+
+ void SAL_CALL FrameWindowActivationListener::windowNormalized( const EventObject& /*_rEvent*/ )
+ {
+ // not interested in
+ }
+
+ void SAL_CALL FrameWindowActivationListener::windowActivated( const EventObject& /*_rEvent*/ )
+ {
+ impl_checkDisposed_throw();
+ lcl_updateActive_nothrow( *m_pData, true );
+ }
+
+ void SAL_CALL FrameWindowActivationListener::windowDeactivated( const EventObject& /*_rEvent*/ )
+ {
+ impl_checkDisposed_throw();
+ lcl_updateActive_nothrow( *m_pData, false );
+ }
+
+ void SAL_CALL FrameWindowActivationListener::disposing( const EventObject& /*_rEvent*/ )
+ {
+ dispose();
+ }
+
+ // ControllerFrame
+ ControllerFrame::ControllerFrame( IController& _rController )
+ :m_pData( new ControllerFrame_Data( _rController ) )
+ {
+ }
+
+ ControllerFrame::~ControllerFrame()
+ {
+ }
+
+ const Reference< XFrame >& ControllerFrame::attachFrame( const Reference< XFrame >& _rxFrame )
+ {
+ // set new frame, including listener handling
+ lcl_setFrame_nothrow( *m_pData, _rxFrame );
+
+ // determine whether we're active
+ m_pData->m_bActive = lcl_isActive_nothrow( m_pData->m_xFrame );
+
+ // update active component
+ if ( m_pData->m_bActive )
+ {
+ lcl_updateActiveComponents_nothrow( *m_pData );
+ lcl_notifyFocusChange_nothrow( *m_pData, true );
+ }
+
+ return m_pData->m_xFrame;
+ }
+
+ const Reference< XFrame >& ControllerFrame::getFrame() const
+ {
+ return m_pData->m_xFrame;
+ }
+
+ bool ControllerFrame::isActive() const
+ {
+ return m_pData->m_bActive;
+ }
+
+ void ControllerFrame::frameAction( FrameAction _eAction )
+ {
+ bool bActive = m_pData->m_bActive;
+
+ switch ( _eAction )
+ {
+ case FrameAction_FRAME_ACTIVATED:
+ case FrameAction_FRAME_UI_ACTIVATED:
+ bActive = true;
+ break;
+
+ case FrameAction_FRAME_DEACTIVATING:
+ case FrameAction_FRAME_UI_DEACTIVATING:
+ bActive = false;
+ break;
+
+ default:
+ break;
+ }
+
+ lcl_updateActive_nothrow( *m_pData, bActive );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/databaseobjectview.cxx b/dbaccess/source/ui/misc/databaseobjectview.cxx
new file mode 100644
index 000000000..cb4478295
--- /dev/null
+++ b/dbaccess/source/ui/misc/databaseobjectview.cxx
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <databaseobjectview.hxx>
+#include <strings.hxx>
+#include <asyncmodaldialog.hxx>
+
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/frame/TaskCreator.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/application/XTableUIProvider.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <osl/diagnose.h>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/window.hxx>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdb::application;
+ using namespace ::com::sun::star::ui::dialogs;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::awt;
+
+ // DatabaseObjectView
+ DatabaseObjectView::DatabaseObjectView( const Reference< XComponentContext >& _rxORB,
+ const Reference< XDatabaseDocumentUI >& _rxApplication,
+ const Reference< XFrame >& _rxParentFrame,
+ const OUString& _rComponentURL )
+ :m_xORB ( _rxORB )
+ ,m_xParentFrame ( _rxParentFrame )
+ ,m_xApplication ( _rxApplication )
+ ,m_sComponentURL ( _rComponentURL )
+ {
+ OSL_ENSURE( m_xORB.is(), "DatabaseObjectView::DatabaseObjectView: invalid service factory!" );
+ OSL_ENSURE( m_xApplication.is(), "DatabaseObjectView::DatabaseObjectView: invalid connection!" );
+ }
+
+ Reference< XConnection > DatabaseObjectView::getConnection() const
+ {
+ Reference< XConnection > xConnection;
+ if ( m_xApplication.is() )
+ xConnection = m_xApplication->getActiveConnection();
+ return xConnection;
+ }
+
+ Reference< XComponent > DatabaseObjectView::createNew( const Reference< XDataSource >& _xDataSource, const ::comphelper::NamedValueCollection& i_rDispatchArgs )
+ {
+ return doCreateView( Any( _xDataSource ), OUString(), i_rDispatchArgs );
+ }
+
+ Reference< XComponent > DatabaseObjectView::openExisting( const Any& _rDataSource, const OUString& _rName,
+ const ::comphelper::NamedValueCollection& i_rDispatchArgs )
+ {
+ return doCreateView( _rDataSource, _rName, i_rDispatchArgs );
+ }
+
+ Reference< XComponent > DatabaseObjectView::doCreateView( const Any& _rDataSource, const OUString& _rObjectName,
+ const ::comphelper::NamedValueCollection& i_rCreationArgs )
+ {
+ ::comphelper::NamedValueCollection aDispatchArgs;
+
+ aDispatchArgs.merge( i_rCreationArgs, false ); // false => do not overwrite
+ fillDispatchArgs( aDispatchArgs, _rDataSource, _rObjectName );
+ aDispatchArgs.merge( i_rCreationArgs, true ); // true => do overwrite
+
+ return doDispatch( aDispatchArgs );
+ }
+
+ Reference< XComponent > DatabaseObjectView::doDispatch( const ::comphelper::NamedValueCollection& i_rDispatchArgs )
+ {
+ Reference< XComponent > xReturn;
+ if ( m_xORB.is() )
+ {
+ try
+ {
+ // if we have no externally provided frame, create one
+ if ( !m_xFrameLoader.is() )
+ {
+ Reference< XSingleServiceFactory > xFact = TaskCreator::create(m_xORB);
+ Sequence< Any > lArgs{ Any(NamedValue("ParentFrame", Any(m_xParentFrame))),
+ Any(NamedValue("TopWindow", Any(true))),
+ Any(NamedValue("SupportPersistentWindowState",
+ Any(true))) };
+
+ m_xFrameLoader.set(xFact->createInstanceWithArguments(lArgs), UNO_QUERY_THROW);
+
+ // everything we load can be considered a "top level document", so set the respective bit at the window.
+ // This, amongst other things, triggers that the component in this task participates in the
+ // "ThisComponent"-game for the global application Basic.
+ const Reference< XFrame > xFrame( m_xFrameLoader, UNO_QUERY_THROW );
+ const Reference< XWindow > xFrameWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
+ VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xFrameWindow );
+ ENSURE_OR_THROW( pContainerWindow, "no implementation access to the frame's container window!" );
+ pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WindowExtendedStyle::Document );
+ }
+
+ Reference< XComponentLoader > xFrameLoader( m_xFrameLoader, UNO_SET_THROW );
+ xReturn = xFrameLoader->loadComponentFromURL(
+ m_sComponentURL,
+ "_self",
+ 0,
+ i_rDispatchArgs.getPropertyValues()
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ return xReturn;
+ }
+
+ void DatabaseObjectView::fillDispatchArgs(
+ ::comphelper::NamedValueCollection& i_rDispatchArgs,
+ const Any& _aDataSource,
+ const OUString& /* _rName */
+ )
+ {
+ OUString sDataSource;
+ Reference<XDataSource> xDataSource;
+ if ( _aDataSource >>= sDataSource )
+ {
+ i_rDispatchArgs.put( PROPERTY_DATASOURCENAME, sDataSource );
+ }
+ else if ( _aDataSource >>= xDataSource )
+ {
+ i_rDispatchArgs.put( PROPERTY_DATASOURCE, xDataSource );
+ }
+
+ i_rDispatchArgs.put( PROPERTY_ACTIVE_CONNECTION, getConnection() );
+ }
+
+ // QueryDesigner
+ QueryDesigner::QueryDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication,
+ const Reference< XFrame >& _rxParentFrame, bool _bCreateView )
+ :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, _bCreateView ? OUString(URL_COMPONENT_VIEWDESIGN) : OUString(URL_COMPONENT_QUERYDESIGN) )
+ ,m_nCommandType( _bCreateView ? CommandType::TABLE : CommandType::QUERY )
+ {
+ }
+
+ void QueryDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource,
+ const OUString& _rObjectName )
+ {
+ DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName );
+
+ const bool bIncludeQueryName = !_rObjectName.isEmpty();
+ const bool bGraphicalDesign = i_rDispatchArgs.getOrDefault( PROPERTY_GRAPHICAL_DESIGN, true );
+ const bool bEditViewAsSQLCommand = ( m_nCommandType == CommandType::TABLE ) && !bGraphicalDesign;
+
+ i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, m_nCommandType );
+
+ if ( bIncludeQueryName )
+ {
+ i_rDispatchArgs.put( PROPERTY_COMMAND, _rObjectName );
+ }
+
+ if ( bEditViewAsSQLCommand )
+ {
+ i_rDispatchArgs.put( PROPERTY_ESCAPE_PROCESSING, false );
+ }
+ }
+
+ // TableDesigner
+ TableDesigner::TableDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame )
+ :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_TABLEDESIGN ) )
+ {
+ }
+
+ void TableDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource,
+ const OUString& _rObjectName )
+ {
+ DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName );
+
+ if ( !_rObjectName.isEmpty() )
+ {
+ i_rDispatchArgs.put( PROPERTY_CURRENTTABLE, _rObjectName );
+ }
+ }
+
+ Reference< XComponent > TableDesigner::doCreateView( const Any& _rDataSource, const OUString& _rObjectName,
+ const ::comphelper::NamedValueCollection& i_rCreationArgs )
+ {
+ bool bIsNewDesign = _rObjectName.isEmpty();
+
+ // let's see whether the connection can provide a dedicated table designer
+ Reference< XInterface > xDesigner;
+ if ( !bIsNewDesign )
+ xDesigner = impl_getConnectionProvidedDesigner_nothrow( _rObjectName );
+
+ if ( !xDesigner.is() )
+ return DatabaseObjectView::doCreateView( _rDataSource, _rObjectName, i_rCreationArgs );
+
+ // try whether the designer is a dialog
+ Reference< XExecutableDialog > xDialog( xDesigner, UNO_QUERY_THROW );
+ try { AsyncDialogExecutor::executeModalDialogAsync( xDialog ); }
+ catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
+ return nullptr;
+ }
+
+ Reference< XInterface > TableDesigner::impl_getConnectionProvidedDesigner_nothrow( const OUString& _rTableName )
+ {
+ Reference< XInterface > xDesigner;
+ try
+ {
+ Reference< XTableUIProvider > xTableUIProv( getConnection(), UNO_QUERY );
+ if ( xTableUIProv.is() )
+ xDesigner = xTableUIProv->getTableEditor( getApplicationUI(), _rTableName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xDesigner;
+ }
+
+ // ResultSetBrowser
+ ResultSetBrowser::ResultSetBrowser( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame,
+ bool _bTable )
+ :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast < OUString >( URL_COMPONENT_DATASOURCEBROWSER ) )
+ ,m_bTable(_bTable)
+ {
+ }
+
+ void ResultSetBrowser::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource,
+ const OUString& _rQualifiedName)
+ {
+ DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rQualifiedName );
+ OSL_ENSURE( !_rQualifiedName.isEmpty(),"A Table name must be set");
+ OUString sCatalog;
+ OUString sSchema;
+ OUString sTable;
+ if ( m_bTable )
+ ::dbtools::qualifiedNameComponents( getConnection()->getMetaData(), _rQualifiedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
+
+ i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, (m_bTable ? CommandType::TABLE : CommandType::QUERY) );
+ i_rDispatchArgs.put( PROPERTY_COMMAND, _rQualifiedName );
+ i_rDispatchArgs.put( PROPERTY_ENABLE_BROWSER, false );
+
+ if ( m_bTable )
+ {
+ i_rDispatchArgs.put( PROPERTY_UPDATE_CATALOGNAME, sCatalog );
+ i_rDispatchArgs.put( PROPERTY_UPDATE_SCHEMANAME, sSchema );
+ i_rDispatchArgs.put( PROPERTY_UPDATE_TABLENAME, sTable );
+ }
+ }
+
+ // RelationDesigner
+ RelationDesigner::RelationDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame )
+ :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_RELATIONDESIGN ) )
+ {
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/datasourceconnector.cxx b/dbaccess/source/ui/misc/datasourceconnector.cxx
new file mode 100644
index 000000000..49053e569
--- /dev/null
+++ b/dbaccess/source/ui/misc/datasourceconnector.cxx
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <datasourceconnector.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <UITools.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/weld.hxx>
+#include <tools/diagnose_ex.h>
+#include <cppuhelper/exc_hlp.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::frame;
+ using namespace ::dbtools;
+
+ // ODatasourceConnector
+ ODatasourceConnector::ODatasourceConnector(const Reference< XComponentContext >& _rxContext, weld::Window* _pMessageParent)
+ :m_pErrorMessageParent(_pMessageParent)
+ ,m_xContext(_rxContext)
+ {
+ }
+
+ ODatasourceConnector::ODatasourceConnector( const Reference< XComponentContext >& _rxContext, weld::Window* _pMessageParent,
+ const OUString& _rContextInformation )
+ :m_pErrorMessageParent(_pMessageParent)
+ ,m_xContext(_rxContext)
+ ,m_sContextInformation( _rContextInformation )
+ {
+ }
+
+ Reference< XConnection > ODatasourceConnector::connect( const OUString& _rDataSourceName,
+ ::dbtools::SQLExceptionInfo* _pErrorInfo ) const
+ {
+ Reference< XConnection > xConnection;
+
+ OSL_ENSURE(isValid(), "ODatasourceConnector::connect: invalid object!");
+ if (!isValid())
+ return xConnection;
+
+ // get the data source
+ Reference< XDataSource > xDatasource =
+ getDataSourceByName( _rDataSourceName, m_pErrorMessageParent, m_xContext, _pErrorInfo );
+
+ if ( xDatasource.is() )
+ xConnection = connect( xDatasource, _pErrorInfo );
+ return xConnection;
+ }
+
+ Reference< XConnection > ODatasourceConnector::connect(const Reference< XDataSource>& _xDataSource,
+ ::dbtools::SQLExceptionInfo* _pErrorInfo ) const
+ {
+ Reference< XConnection > xConnection;
+
+ OSL_ENSURE( isValid() && _xDataSource.is(), "ODatasourceConnector::connect: invalid object or argument!" );
+ if ( !isValid() || !_xDataSource.is() )
+ return xConnection;
+
+ // get user/password
+ OUString sPassword, sUser;
+ bool bPwdRequired = false;
+ Reference<XPropertySet> xProp(_xDataSource,UNO_QUERY);
+ try
+ {
+ xProp->getPropertyValue(PROPERTY_PASSWORD) >>= sPassword;
+ xProp->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED) >>= bPwdRequired;
+ xProp->getPropertyValue(PROPERTY_USER) >>= sUser;
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // try to connect
+ SQLExceptionInfo aInfo;
+ try
+ {
+ if (bPwdRequired && sPassword.isEmpty())
+ { // password required, but empty -> connect using an interaction handler
+ Reference< XCompletedConnection > xConnectionCompletion( _xDataSource, UNO_QUERY_THROW );
+
+ Reference< XModel > xModel( getDataSourceOrModel( _xDataSource ), UNO_QUERY_THROW );
+ ::comphelper::NamedValueCollection aArgs( xModel->getArgs() );
+ Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) );
+
+ if ( !xHandler.is() )
+ {
+ // instantiate the default SDB interaction handler
+ xHandler = InteractionHandler::createWithParent(m_xContext, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr);
+ }
+
+ xConnection = xConnectionCompletion->connectWithCompletion(xHandler);
+ }
+ else
+ {
+ xConnection = _xDataSource->getConnection(sUser, sPassword);
+ }
+ }
+ catch( const SQLException& )
+ {
+ aInfo = ::cppu::getCaughtException();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( !aInfo.isValid() )
+ {
+ // there was no error during connecting, but perhaps a warning?
+ Reference< XWarningsSupplier > xConnectionWarnings( xConnection, UNO_QUERY );
+ if ( xConnectionWarnings.is() )
+ {
+ try
+ {
+ Any aWarnings( xConnectionWarnings->getWarnings() );
+ if ( aWarnings.hasValue() )
+ {
+ OUString sMessage( DBA_RES( STR_WARNINGS_DURING_CONNECT ) );
+ sMessage = sMessage.replaceFirst( "$buttontext$", GetStandardText( StandardButtonType::More ) );
+ sMessage = OutputDevice::GetNonMnemonicString( sMessage );
+
+ SQLWarning aContext;
+ aContext.Message = sMessage;
+ aContext.NextException = aWarnings;
+ aInfo = aContext;
+ }
+ xConnectionWarnings->clearWarnings();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ else
+ {
+ if ( !m_sContextInformation.isEmpty() )
+ {
+ SQLException aError;
+ aError.Message = m_sContextInformation;
+ aError.NextException = aInfo.get();
+
+ aInfo = aError;
+ }
+ }
+
+ // was there an error?
+ if ( aInfo.isValid() )
+ {
+ if ( _pErrorInfo )
+ {
+ *_pErrorInfo = aInfo;
+ }
+ else
+ {
+ showError(aInfo, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr, m_xContext);
+ }
+ }
+ return xConnection;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/dbaundomanager.cxx b/dbaccess/source/ui/misc/dbaundomanager.cxx
new file mode 100644
index 000000000..9ed72bbdf
--- /dev/null
+++ b/dbaccess/source/ui/misc/dbaundomanager.cxx
@@ -0,0 +1,324 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbaccess/dbaundomanager.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+
+#include <svl/undo.hxx>
+#include <vcl/svapp.hxx>
+#include <framework/undomanagerhelper.hxx>
+#include <framework/imutex.hxx>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::document::XUndoManager;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::document::XUndoAction;
+ using ::com::sun::star::document::XUndoManagerListener;
+ using ::com::sun::star::lang::NoSupportException;
+
+ // UndoManager_Impl
+ struct UndoManager_Impl : public ::framework::IUndoManagerImplementation
+ {
+ UndoManager_Impl( UndoManager& i_antiImpl, ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex )
+ :rAntiImpl( i_antiImpl )
+ ,rParent( i_parent )
+ ,rMutex( i_mutex )
+ ,bDisposed( false )
+ ,aUndoHelper( *this )
+ {
+ }
+
+ virtual ~UndoManager_Impl()
+ {
+ }
+
+ UndoManager& rAntiImpl;
+ ::cppu::OWeakObject& rParent;
+ ::osl::Mutex& rMutex;
+ bool bDisposed;
+ SfxUndoManager aUndoManager;
+ ::framework::UndoManagerHelper aUndoHelper;
+
+ // IUndoManagerImplementation
+ virtual SfxUndoManager& getImplUndoManager() override;
+ virtual Reference< XUndoManager > getThis() override;
+ };
+
+ SfxUndoManager& UndoManager_Impl::getImplUndoManager()
+ {
+ return aUndoManager;
+ }
+
+ Reference< XUndoManager > UndoManager_Impl::getThis()
+ {
+ return static_cast< XUndoManager* >( &rAntiImpl );
+ }
+
+ namespace {
+
+ // OslMutexFacade
+ class OslMutexFacade : public ::framework::IMutex
+ {
+ public:
+ explicit OslMutexFacade( ::osl::Mutex& i_mutex )
+ :m_rMutex( i_mutex )
+ {
+ }
+
+ virtual ~OslMutexFacade() {}
+
+ virtual void acquire() override;
+ virtual void release() override;
+
+ private:
+ ::osl::Mutex& m_rMutex;
+ };
+
+ }
+
+ void OslMutexFacade::acquire()
+ {
+ m_rMutex.acquire();
+ }
+
+ void OslMutexFacade::release()
+ {
+ m_rMutex.release();
+ }
+
+ namespace {
+
+ // UndoManagerMethodGuard
+ /** guard for public UNO methods of the UndoManager
+ */
+ class UndoManagerMethodGuard : public ::framework::IMutexGuard
+ {
+ public:
+ explicit UndoManagerMethodGuard( UndoManager_Impl& i_impl )
+ :m_aGuard( i_impl.rMutex )
+ ,m_aMutexFacade( i_impl.rMutex )
+ {
+ // throw if the instance is already disposed
+ if ( i_impl.bDisposed )
+ throw DisposedException( OUString(), i_impl.getThis() );
+ }
+ virtual ~UndoManagerMethodGuard()
+ {
+ }
+
+ // IMutexGuard
+ virtual void clear() override;
+ virtual ::framework::IMutex& getGuardedMutex() override;
+
+ private:
+ osl::ClearableMutexGuard m_aGuard;
+ OslMutexFacade m_aMutexFacade;
+ };
+
+ }
+
+ ::framework::IMutex& UndoManagerMethodGuard::getGuardedMutex()
+ {
+ return m_aMutexFacade;
+ }
+
+ void UndoManagerMethodGuard::clear()
+ {
+ m_aGuard.clear();
+ }
+
+ // UndoManager
+ UndoManager::UndoManager( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex )
+ :m_xImpl( new UndoManager_Impl( *this, i_parent, i_mutex ) )
+ {
+ }
+
+ UndoManager::~UndoManager()
+ {
+ }
+
+ SfxUndoManager& UndoManager::GetSfxUndoManager() const
+ {
+ return m_xImpl->aUndoManager;
+ }
+
+ void SAL_CALL UndoManager::acquire( ) noexcept
+ {
+ m_xImpl->rParent.acquire();
+ }
+
+ void SAL_CALL UndoManager::release( ) noexcept
+ {
+ m_xImpl->rParent.release();
+ }
+
+ void UndoManager::disposing()
+ {
+ {
+ ::osl::MutexGuard aGuard( m_xImpl->rMutex );
+ m_xImpl->bDisposed = true;
+ }
+ m_xImpl->aUndoHelper.disposing();
+ }
+
+ void SAL_CALL UndoManager::enterUndoContext( const OUString& i_title )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.enterUndoContext( i_title, aGuard );
+ }
+
+ void SAL_CALL UndoManager::enterHiddenUndoContext( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.enterHiddenUndoContext( aGuard );
+ }
+
+ void SAL_CALL UndoManager::leaveUndoContext( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.leaveUndoContext( aGuard );
+ }
+
+ void SAL_CALL UndoManager::addUndoAction( const Reference< XUndoAction >& i_action )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.addUndoAction( i_action, aGuard );
+ }
+
+ void SAL_CALL UndoManager::undo( )
+ {
+ SolarMutexGuard aSolarGuard;
+ // (all our UndoActions work directly on VCL code, usually, so ...)
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.undo( aGuard );
+ }
+
+ void SAL_CALL UndoManager::redo( )
+ {
+ SolarMutexGuard aSolarGuard;
+ // (all our UndoActions work directly on VCL code, usually, so ...)
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.redo( aGuard );
+ }
+
+ sal_Bool SAL_CALL UndoManager::isUndoPossible( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->aUndoHelper.isUndoPossible();
+ }
+
+ sal_Bool SAL_CALL UndoManager::isRedoPossible( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->aUndoHelper.isRedoPossible();
+ }
+
+ OUString SAL_CALL UndoManager::getCurrentUndoActionTitle( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->aUndoHelper.getCurrentUndoActionTitle();
+ }
+
+ OUString SAL_CALL UndoManager::getCurrentRedoActionTitle( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->aUndoHelper.getCurrentRedoActionTitle();
+ }
+
+ Sequence< OUString > SAL_CALL UndoManager::getAllUndoActionTitles( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->aUndoHelper.getAllUndoActionTitles();
+ }
+
+ Sequence< OUString > SAL_CALL UndoManager::getAllRedoActionTitles( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->aUndoHelper.getAllRedoActionTitles();
+ }
+
+ void SAL_CALL UndoManager::clear( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.clear( aGuard );
+ }
+
+ void SAL_CALL UndoManager::clearRedo( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.clearRedo( aGuard );
+ }
+
+ void SAL_CALL UndoManager::reset( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.reset( aGuard );
+ }
+
+ void SAL_CALL UndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.addUndoManagerListener( i_listener );
+ }
+
+ void SAL_CALL UndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.removeUndoManagerListener( i_listener );
+ }
+
+ void SAL_CALL UndoManager::lock( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.lock();
+ }
+
+ void SAL_CALL UndoManager::unlock( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ m_xImpl->aUndoHelper.unlock();
+ }
+
+ sal_Bool SAL_CALL UndoManager::isLocked( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->aUndoHelper.isLocked();
+ }
+
+ Reference< XInterface > SAL_CALL UndoManager::getParent( )
+ {
+ UndoManagerMethodGuard aGuard( *m_xImpl );
+ return m_xImpl->rParent;
+ }
+
+ void SAL_CALL UndoManager::setParent( const Reference< XInterface >& )
+ {
+ throw NoSupportException( OUString(), m_xImpl->getThis() );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx
new file mode 100644
index 000000000..467a6e925
--- /dev/null
+++ b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx
@@ -0,0 +1,606 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <browserids.hxx>
+#include <commontypes.hxx>
+#include <core_resource.hxx>
+#include <dbaccess/dataview.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <dbaccess/dbsubcomponentcontroller.hxx>
+
+#include <com/sun/star/frame/XUntitledNumbers.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::sdbc::XDataSource;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::util::XNumberFormatter;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::sdb::XOfficeDatabaseDocument;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::sdbc::XDatabaseMetaData;
+ using ::com::sun::star::sdb::XDocumentDataSource;
+ using ::com::sun::star::document::XEmbeddedScripts;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::frame::XUntitledNumbers;
+
+ namespace {
+
+ class DataSourceHolder
+ {
+ public:
+ DataSourceHolder()
+ {
+ }
+
+ explicit DataSourceHolder(const Reference< XDataSource >& _rxDataSource)
+ : m_xDataSource(_rxDataSource)
+ {
+ Reference< XDocumentDataSource > xDocDS( m_xDataSource, UNO_QUERY );
+ if ( xDocDS.is() )
+ m_xDocument = xDocDS->getDatabaseDocument();
+
+ m_xDataSourceProps.set( m_xDataSource, UNO_QUERY );
+ }
+
+ const Reference< XDataSource >& getDataSource() const { return m_xDataSource; }
+ const Reference< XPropertySet >& getDataSourceProps() const { return m_xDataSourceProps; }
+ const Reference< XOfficeDatabaseDocument >& getDatabaseDocument() const { return m_xDocument; }
+
+ bool is() const { return m_xDataSource.is(); }
+
+ void clear()
+ {
+ m_xDataSource.clear();
+ m_xDocument.clear();
+ }
+
+ private:
+ Reference< XDataSource > m_xDataSource;
+ Reference< XPropertySet > m_xDataSourceProps;
+ Reference< XOfficeDatabaseDocument > m_xDocument;
+ };
+
+ }
+
+ struct DBSubComponentController_Impl
+ {
+ private:
+ ::std::optional< bool > m_aDocScriptSupport;
+
+ public:
+ ::dbtools::SQLExceptionInfo m_aCurrentError;
+
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener>
+ m_aModifyListeners;
+
+ // <properties>
+ SharedConnection m_xConnection;
+ ::dbtools::DatabaseMetaData m_aSdbMetaData;
+ // </properties>
+ OUString m_sDataSourceName; // the data source we're working for
+ DataSourceHolder m_aDataSource;
+ Reference< XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier
+ sal_Int32 m_nDocStartNumber;
+ bool m_bSuspended; // is true when the controller was already suspended
+ bool m_bEditable; // is the control readonly or not
+ bool m_bModified; // is the data modified
+ bool m_bNotAttached;
+
+ explicit DBSubComponentController_Impl(osl::Mutex& i_rMutex)
+ :m_aModifyListeners( i_rMutex )
+ ,m_nDocStartNumber(0)
+ ,m_bSuspended( false )
+ ,m_bEditable(true)
+ ,m_bModified(false)
+ ,m_bNotAttached(true)
+ {
+ }
+
+ bool documentHasScriptSupport() const
+ {
+ OSL_PRECOND( !!m_aDocScriptSupport,
+ "DBSubComponentController_Impl::documentHasScriptSupport: not completely initialized, yet - don't know!?" );
+ return !!m_aDocScriptSupport && *m_aDocScriptSupport;
+ }
+
+ void setDocumentScriptSupport( const bool _bSupport )
+ {
+ OSL_PRECOND( !m_aDocScriptSupport,
+ "DBSubComponentController_Impl::setDocumentScriptSupport: already initialized!" );
+ m_aDocScriptSupport = ::std::optional< bool >( _bSupport );
+ }
+ };
+
+ // DBSubComponentController
+ DBSubComponentController::DBSubComponentController(const Reference< XComponentContext >& _rxORB)
+ :DBSubComponentController_Base( _rxORB )
+ ,m_pImpl( new DBSubComponentController_Impl( getMutex() ) )
+ {
+ }
+
+ DBSubComponentController::~DBSubComponentController()
+ {
+ }
+
+ void DBSubComponentController::impl_initialize()
+ {
+ OGenericUnoController::impl_initialize();
+
+ const ::comphelper::NamedValueCollection& rArguments( getInitParams() );
+
+ Reference< XConnection > xConnection;
+ xConnection = rArguments.getOrDefault( PROPERTY_ACTIVE_CONNECTION, xConnection );
+
+ if ( !xConnection.is() )
+ ::dbtools::isEmbeddedInDatabase( getModel(), xConnection );
+
+ if ( xConnection.is() )
+ initializeConnection( xConnection );
+
+ bool bShowError = true;
+ if ( !isConnected() )
+ {
+ reconnect( false );
+ bShowError = false;
+ }
+ if ( !isConnected() )
+ {
+ if ( bShowError )
+ connectionLostMessage();
+ throw IllegalArgumentException();
+ }
+ }
+
+ Any SAL_CALL DBSubComponentController::queryInterface(const Type& _rType)
+ {
+ if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) )
+ {
+ if ( m_pImpl->documentHasScriptSupport() )
+ return Any( Reference< XScriptInvocationContext >( this ) );
+ return Any();
+ }
+
+ return DBSubComponentController_Base::queryInterface( _rType );
+ }
+
+ Sequence< Type > SAL_CALL DBSubComponentController::getTypes( )
+ {
+ Sequence< Type > aTypes( DBSubComponentController_Base::getTypes() );
+ if ( !m_pImpl->documentHasScriptSupport() )
+ {
+ auto [begin, end] = asNonConstRange(aTypes);
+ auto newEnd = std::remove_if( begin, end,
+ [](const Type& type)
+ { return type == cppu::UnoType<XScriptInvocationContext>::get(); } );
+ aTypes.realloc( std::distance(begin, newEnd) );
+ }
+ return aTypes;
+ }
+
+ void DBSubComponentController::initializeConnection( const Reference< XConnection >& _rxForeignConn )
+ {
+ DBG_ASSERT( !isConnected(), "DBSubComponentController::initializeConnection: not to be called when already connected!" );
+ // usually this gets called from within initialize of derived classes ...
+ if ( isConnected() )
+ disconnect();
+
+ m_pImpl->m_xConnection.reset( _rxForeignConn, SharedConnection::NoTakeOwnership );
+ m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection );
+ startConnectionListening( m_pImpl->m_xConnection );
+
+ // get the data source the connection belongs to
+ try
+ {
+ // determine our data source
+ OSL_PRECOND( !m_pImpl->m_aDataSource.is(), "DBSubComponentController::initializeConnection: already a data source in this phase?" );
+ {
+ Reference< XChild > xConnAsChild( m_pImpl->m_xConnection, UNO_QUERY );
+ Reference< XDataSource > xDS;
+ if ( xConnAsChild.is() )
+ xDS.set( xConnAsChild->getParent(), UNO_QUERY );
+
+ // (take the indirection through XDataSource to ensure we have a correct object...)
+ m_pImpl->m_aDataSource = DataSourceHolder(xDS);
+ }
+ SAL_WARN_IF( !m_pImpl->m_aDataSource.is(), "dbaccess.ui", "DBSubComponentController::initializeConnection: unable to obtain the data source object!" );
+
+ if ( m_pImpl->m_bNotAttached )
+ {
+ Reference< XUntitledNumbers > xUntitledProvider( getDatabaseDocument(), UNO_QUERY );
+ m_pImpl->m_nDocStartNumber = 1;
+ if ( xUntitledProvider.is() )
+ m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) );
+ }
+
+ // determine the availability of script support in our document. Our own XScriptInvocationContext
+ // interface depends on this
+ m_pImpl->setDocumentScriptSupport( Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY ).is() );
+
+ // get a number formatter
+ Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps(), UNO_SET_THROW );
+ xDataSourceProps->getPropertyValue( PROPERTY_NAME ) >>= m_pImpl->m_sDataSourceName;
+ DBG_ASSERT( !m_pImpl->m_sDataSourceName.isEmpty(), "DBSubComponentController::initializeConnection: invalid data source name!" );
+ Reference< XNumberFormatsSupplier> xSupplier = ::dbtools::getNumberFormats(m_pImpl->m_xConnection);
+ if(xSupplier.is())
+ {
+ m_pImpl->m_xFormatter.set(NumberFormatter::create(getORB()), UNO_QUERY_THROW);
+ m_pImpl->m_xFormatter->attachNumberFormatsSupplier(xSupplier);
+ }
+ OSL_ENSURE(m_pImpl->m_xFormatter.is(),"No NumberFormatter!");
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void DBSubComponentController::reconnect( bool _bUI )
+ {
+ OSL_ENSURE(!m_pImpl->m_bSuspended, "Cannot reconnect while suspended!");
+
+ stopConnectionListening( m_pImpl->m_xConnection );
+ m_pImpl->m_aSdbMetaData.reset( nullptr );
+ m_pImpl->m_xConnection.clear();
+
+ // reconnect
+ bool bReConnect = true;
+ if ( _bUI )
+ {
+ std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ DBA_RES(STR_QUERY_CONNECTION_LOST)));
+ bReConnect = (RET_YES == xQuery->run());
+ }
+
+ // now really reconnect ...
+ if ( bReConnect )
+ {
+ m_pImpl->m_xConnection.reset( connect( m_pImpl->m_aDataSource.getDataSource() ), SharedConnection::TakeOwnership );
+ m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection );
+ }
+
+ // invalidate all slots
+ InvalidateAll();
+ }
+
+ void DBSubComponentController::disconnect()
+ {
+ stopConnectionListening(m_pImpl->m_xConnection);
+ m_pImpl->m_aSdbMetaData.reset( nullptr );
+ m_pImpl->m_xConnection.clear();
+
+ InvalidateAll();
+ }
+
+ void DBSubComponentController::losingConnection()
+ {
+ // our connection was disposed so we need a new one
+ reconnect( true );
+ InvalidateAll();
+ }
+
+ void SAL_CALL DBSubComponentController::disposing()
+ {
+ DBSubComponentController_Base::disposing();
+
+ disconnect();
+
+ attachFrame( Reference < XFrame >() );
+
+ m_pImpl->m_aDataSource.clear();
+ }
+
+ void SAL_CALL DBSubComponentController::disposing(const EventObject& _rSource)
+ {
+ if ( _rSource.Source == getConnection() )
+ {
+ if ( !m_pImpl->m_bSuspended // when already suspended then we don't have to reconnect
+ && !getBroadcastHelper().bInDispose
+ && !getBroadcastHelper().bDisposed
+ && isConnected()
+ )
+ {
+ losingConnection();
+ }
+ else
+ {
+ m_pImpl->m_xConnection.reset( m_pImpl->m_xConnection, SharedConnection::NoTakeOwnership );
+ // this prevents the "disposeComponent" call in disconnect
+ disconnect();
+ }
+ }
+ else
+ DBSubComponentController_Base::disposing( _rSource );
+ }
+
+ void DBSubComponentController::appendError( const OUString& _rErrorMessage )
+ {
+ m_pImpl->m_aCurrentError.append( ::dbtools::SQLExceptionInfo::TYPE::SQLException, _rErrorMessage,
+ getStandardSQLState( ::dbtools::StandardSQLState::GENERAL_ERROR ),
+ 1000 );
+ }
+ void DBSubComponentController::clearError()
+ {
+ m_pImpl->m_aCurrentError = ::dbtools::SQLExceptionInfo();
+ }
+
+ bool DBSubComponentController::hasError() const
+ {
+ return m_pImpl->m_aCurrentError.isValid();
+ }
+
+ const ::dbtools::SQLExceptionInfo& DBSubComponentController::getError() const
+ {
+ return m_pImpl->m_aCurrentError;
+ }
+
+ void DBSubComponentController::displayError()
+ {
+ showError( m_pImpl->m_aCurrentError );
+ }
+
+ sal_Bool SAL_CALL DBSubComponentController::suspend(sal_Bool bSuspend)
+ {
+ m_pImpl->m_bSuspended = bSuspend;
+ if ( !bSuspend && !isConnected() )
+ reconnect(true);
+
+ return true;
+ }
+
+ sal_Bool SAL_CALL DBSubComponentController::attachModel( const Reference< XModel > & _rxModel)
+ {
+ if ( !_rxModel.is() )
+ return false;
+ if ( !DBSubComponentController_Base::attachModel( _rxModel ) )
+ return false;
+
+ m_pImpl->m_bNotAttached = false;
+ if ( m_pImpl->m_nDocStartNumber == 1 )
+ releaseNumberForComponent();
+
+ Reference< XUntitledNumbers > xUntitledProvider( _rxModel, UNO_QUERY );
+ m_pImpl->m_nDocStartNumber = 1;
+ if ( xUntitledProvider.is() )
+ m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) );
+
+ return true;
+ }
+
+ void DBSubComponentController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs)
+ {
+ if ( _nId == ID_BROWSER_CLOSE )
+ {
+ closeTask();
+ return;
+ }
+
+ DBSubComponentController_Base::Execute( _nId, _rArgs );
+ InvalidateFeature( _nId );
+ }
+
+ OUString DBSubComponentController::getDataSourceName() const
+ {
+ OUString sName;
+ Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps() );
+ if ( xDataSourceProps.is() )
+ xDataSourceProps->getPropertyValue(PROPERTY_NAME) >>= sName;
+ return sName;
+ }
+ void DBSubComponentController::connectionLostMessage() const
+ {
+ OUString aMessage(DBA_RES(RID_STR_CONNECTION_LOST));
+ Reference< XWindow > xWindow = getTopMostContainerWindow();
+ vcl::Window* pWin = nullptr;
+ if ( xWindow.is() )
+ pWin = VCLUnoHelper::GetWindow(xWindow);
+ if ( !pWin )
+ pWin = getView()->Window::GetParent();
+
+ std::unique_ptr<weld::MessageDialog> xInfo(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr,
+ VclMessageType::Info, VclButtonsType::Ok, aMessage));
+ xInfo->run();
+ }
+ const Reference< XConnection >& DBSubComponentController::getConnection() const
+ {
+ return m_pImpl->m_xConnection;
+ }
+
+ bool DBSubComponentController::isReadOnly() const
+ {
+ return !m_pImpl->m_bEditable;
+ }
+
+ bool DBSubComponentController::isEditable() const
+ {
+ return m_pImpl->m_bEditable;
+ }
+
+ void DBSubComponentController::setEditable(bool _bEditable)
+ {
+ m_pImpl->m_bEditable = _bEditable;
+ }
+
+ const ::dbtools::DatabaseMetaData& DBSubComponentController::getSdbMetaData() const
+ {
+ return m_pImpl->m_aSdbMetaData;
+ }
+
+ bool DBSubComponentController::isConnected() const
+ {
+ return m_pImpl->m_xConnection.is();
+ }
+
+ Reference< XDatabaseMetaData > DBSubComponentController::getMetaData( ) const
+ {
+ Reference< XDatabaseMetaData > xMeta;
+ try
+ {
+ if ( isConnected() )
+ xMeta.set( m_pImpl->m_xConnection->getMetaData(), UNO_SET_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xMeta;
+ }
+
+ const Reference< XPropertySet >& DBSubComponentController::getDataSource() const
+ {
+ return m_pImpl->m_aDataSource.getDataSourceProps();
+ }
+
+ bool DBSubComponentController::haveDataSource() const
+ {
+ return m_pImpl->m_aDataSource.is();
+ }
+
+ Reference< XModel > DBSubComponentController::getDatabaseDocument() const
+ {
+ return Reference< XModel >( m_pImpl->m_aDataSource.getDatabaseDocument(), UNO_QUERY );
+ }
+
+ Reference< XNumberFormatter > const & DBSubComponentController::getNumberFormatter() const
+ {
+ return m_pImpl->m_xFormatter;
+ }
+
+ Reference< XModel > DBSubComponentController::getPrivateModel() const
+ {
+ return getDatabaseDocument();
+ }
+ // XTitle
+ OUString SAL_CALL DBSubComponentController::getTitle()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( m_bExternalTitle )
+ return impl_getTitleHelper_throw()->getTitle ();
+
+ OUStringBuffer sTitle;
+ Reference< XTitle > xTitle(getPrivateModel(),UNO_QUERY);
+ if ( xTitle.is() )
+ {
+ sTitle.append( xTitle->getTitle() );
+ sTitle.append(" : ");
+ }
+ sTitle.append( getPrivateTitle() );
+ return sTitle.makeStringAndClear();
+ }
+
+ sal_Int32 DBSubComponentController::getCurrentStartNumber() const
+ {
+ return m_pImpl->m_nDocStartNumber;
+ }
+
+ Reference< XEmbeddedScripts > SAL_CALL DBSubComponentController::getScriptContainer()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( !m_pImpl->documentHasScriptSupport() )
+ return nullptr;
+
+ return Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY_THROW );
+ }
+
+ void SAL_CALL DBSubComponentController::addModifyListener( const Reference< XModifyListener >& i_Listener )
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ m_pImpl->m_aModifyListeners.addInterface( i_Listener );
+ }
+
+ void SAL_CALL DBSubComponentController::removeModifyListener( const Reference< XModifyListener >& i_Listener )
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ m_pImpl->m_aModifyListeners.removeInterface( i_Listener );
+ }
+
+ sal_Bool SAL_CALL DBSubComponentController::isModified( )
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ return impl_isModified();
+ }
+
+ void SAL_CALL DBSubComponentController::setModified( sal_Bool i_bModified )
+ {
+ ::osl::ClearableMutexGuard aGuard( getMutex() );
+
+ if ( m_pImpl->m_bModified == bool(i_bModified) )
+ return;
+
+ m_pImpl->m_bModified = i_bModified;
+ impl_onModifyChanged();
+
+ EventObject aEvent( *this );
+ aGuard.clear();
+ m_pImpl->m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
+ }
+
+ bool DBSubComponentController::impl_isModified() const
+ {
+ return m_pImpl->m_bModified;
+ }
+
+ void DBSubComponentController::impl_onModifyChanged()
+ {
+ InvalidateFeature( ID_BROWSER_SAVEDOC );
+ if ( isFeatureSupported( ID_BROWSER_SAVEASDOC ) )
+ InvalidateFeature( ID_BROWSER_SAVEASDOC );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx
new file mode 100644
index 000000000..53ef26fa3
--- /dev/null
+++ b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <defaultobjectnamecheck.hxx>
+
+#include <strings.hrc>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/tools/XConnectionTools.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbmetadata.hxx>
+
+#include <rtl/ustrbuf.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <memory>
+#include <string_view>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::container::XHierarchicalNameAccess;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdb::tools::XObjectNames;
+ using ::com::sun::star::sdb::tools::XConnectionTools;
+ using ::com::sun::star::uno::UNO_QUERY;
+
+ using namespace dbtools;
+
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+
+ // helper
+ namespace
+ {
+ void lcl_fillNameExistsError( std::u16string_view _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay )
+ {
+ SQLException aError;
+ OUString sErrorMessage = DBA_RES(STR_NAMED_OBJECT_ALREADY_EXISTS);
+ aError.Message = sErrorMessage.replaceAll("$#$", _rObjectName);
+ _out_rErrorToDisplay = aError;
+ }
+
+ }
+
+ // HierarchicalNameCheck_Impl
+ struct HierarchicalNameCheck_Impl
+ {
+ Reference< XHierarchicalNameAccess > xHierarchicalNames;
+ OUString sRelativeRoot;
+ };
+
+ // HierarchicalNameCheck
+ HierarchicalNameCheck::HierarchicalNameCheck( const Reference< XHierarchicalNameAccess >& _rxNames, const OUString& _rRelativeRoot )
+ :m_pImpl( new HierarchicalNameCheck_Impl )
+ {
+ m_pImpl->xHierarchicalNames = _rxNames;
+ m_pImpl->sRelativeRoot = _rRelativeRoot;
+
+ if ( !m_pImpl->xHierarchicalNames.is() )
+ throw IllegalArgumentException();
+ }
+
+ HierarchicalNameCheck::~HierarchicalNameCheck()
+ {
+ }
+
+ bool HierarchicalNameCheck::isNameValid( const OUString& _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) const
+ {
+ try
+ {
+ OUStringBuffer aCompleteName;
+ if ( !m_pImpl->sRelativeRoot.isEmpty() )
+ {
+ aCompleteName.append( m_pImpl->sRelativeRoot );
+ aCompleteName.append( "/" );
+ }
+ aCompleteName.append( _rObjectName );
+
+ OUString sCompleteName( aCompleteName.makeStringAndClear() );
+ if ( !m_pImpl->xHierarchicalNames->hasByHierarchicalName( sCompleteName ) )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ lcl_fillNameExistsError( _rObjectName, _out_rErrorToDisplay );
+ return false;
+ }
+
+ // DynamicTableOrQueryNameCheck_Impl
+ struct DynamicTableOrQueryNameCheck_Impl
+ {
+ sal_Int32 nCommandType;
+ Reference< XObjectNames > xObjectNames;
+ };
+
+ // DynamicTableOrQueryNameCheck
+ DynamicTableOrQueryNameCheck::DynamicTableOrQueryNameCheck( const Reference< XConnection >& _rxSdbLevelConnection, sal_Int32 _nCommandType )
+ :m_pImpl( new DynamicTableOrQueryNameCheck_Impl )
+ {
+ Reference< XConnectionTools > xConnTools( _rxSdbLevelConnection, UNO_QUERY );
+ if ( xConnTools.is() )
+ m_pImpl->xObjectNames.set( xConnTools->getObjectNames() );
+ if ( !m_pImpl->xObjectNames.is() )
+ throw IllegalArgumentException();
+
+ if ( ( _nCommandType != CommandType::QUERY ) && ( _nCommandType != CommandType::TABLE ) )
+ throw IllegalArgumentException();
+ m_pImpl->nCommandType = _nCommandType;
+ }
+
+ DynamicTableOrQueryNameCheck::~DynamicTableOrQueryNameCheck()
+ {
+ }
+
+ bool DynamicTableOrQueryNameCheck::isNameValid( const OUString& _rObjectName, ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay ) const
+ {
+ try
+ {
+ m_pImpl->xObjectNames->checkNameForCreate( m_pImpl->nCommandType, _rObjectName );
+ return true;
+ }
+ catch( const SQLException& )
+ {
+ _out_rErrorToDisplay = ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() );
+ }
+ return false;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/dsmeta.cxx b/dbaccess/source/ui/misc/dsmeta.cxx
new file mode 100644
index 000000000..286ce63aa
--- /dev/null
+++ b/dbaccess/source/ui/misc/dsmeta.cxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dsmeta.hxx>
+#include <connectivity/DriversConfig.hxx>
+#include <dsntypes.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <map>
+#include <utility>
+
+namespace dbaui
+{
+
+ using namespace dbaccess;
+ using namespace ::com::sun::star;
+
+ namespace {
+
+ struct FeatureSupport
+ {
+ // authentication mode of the data source
+ AuthenticationMode eAuthentication;
+
+ FeatureSupport()
+ :eAuthentication( AuthUserPwd )
+ {
+ }
+
+ explicit FeatureSupport(AuthenticationMode Auth)
+ :eAuthentication( Auth )
+ {
+ }
+ };
+
+ struct FeatureMapping
+ {
+ /// one of the items from dsitems.hxx
+ ItemID nItemID;
+ OUString pAsciiFeatureName;
+ };
+
+ // global tables
+ const FeatureMapping s_aMappings[] = {
+ { DSID_AUTORETRIEVEENABLED, "GeneratedValues" },
+ { DSID_AUTOINCREMENTVALUE, "GeneratedValues" },
+ { DSID_AUTORETRIEVEVALUE, "GeneratedValues" },
+ { DSID_SQL92CHECK, "UseSQL92NamingConstraints" },
+ { DSID_APPEND_TABLE_ALIAS, "AppendTableAliasInSelect" },
+ { DSID_AS_BEFORE_CORRNAME, "UseKeywordAsBeforeAlias" },
+ { DSID_ENABLEOUTERJOIN, "UseBracketedOuterJoinSyntax" },
+ { DSID_IGNOREDRIVER_PRIV, "IgnoreDriverPrivileges" },
+ { DSID_PARAMETERNAMESUBST, "ParameterNameSubstitution" },
+ { DSID_SUPPRESSVERSIONCL, "DisplayVersionColumns" },
+ { DSID_CATALOG, "UseCatalogInSelect" },
+ { DSID_SCHEMA, "UseSchemaInSelect" },
+ { DSID_INDEXAPPENDIX, "UseIndexDirectionKeyword" },
+ { DSID_DOSLINEENDS, "UseDOSLineEnds" },
+ { DSID_BOOLEANCOMPARISON, "BooleanComparisonMode" },
+ { DSID_CHECK_REQUIRED_FIELDS, "FormsCheckRequiredFields" },
+ { DSID_IGNORECURRENCY, "IgnoreCurrency" },
+ { DSID_ESCAPE_DATETIME, "EscapeDateTime" },
+ { DSID_PRIMARY_KEY_SUPPORT, "PrimaryKeySupport" },
+ { DSID_RESPECTRESULTSETTYPE, "RespectDriverResultSetType" },
+ { DSID_MAX_ROW_SCAN, "MaxRowScan" },
+ };
+ }
+
+ static const FeatureSet& lcl_getFeatureSet( const OUString& _rURL )
+ {
+ typedef std::map< OUString, FeatureSet > FeatureSets;
+ static FeatureSets s_aFeatureSets = []()
+ {
+ FeatureSets tmp;
+ ::connectivity::DriversConfig aDriverConfig( ::comphelper::getProcessComponentContext() );
+ const uno::Sequence< OUString > aPatterns = aDriverConfig.getURLs();
+ for ( auto const & pattern : aPatterns )
+ {
+ FeatureSet aCurrentSet;
+ const ::comphelper::NamedValueCollection aCurrentFeatures( aDriverConfig.getFeatures( pattern ).getNamedValues() );
+
+ for ( const FeatureMapping& rFeatureMapping : s_aMappings )
+ {
+ if ( aCurrentFeatures.has( rFeatureMapping.pAsciiFeatureName ) )
+ aCurrentSet.put( rFeatureMapping.nItemID );
+ }
+
+ tmp[ pattern ] = aCurrentSet;
+ }
+ return tmp;
+ }();
+
+ OSL_ENSURE( s_aFeatureSets.find( _rURL ) != s_aFeatureSets.end(), "invalid URL/pattern!" );
+ return s_aFeatureSets[ _rURL ];
+ }
+
+ static AuthenticationMode getAuthenticationMode( const OUString& _sURL )
+ {
+ static std::map< OUString, FeatureSupport > s_aSupport = []()
+ {
+ std::map< OUString, FeatureSupport > tmp;
+ ::connectivity::DriversConfig aDriverConfig(::comphelper::getProcessComponentContext());
+ const uno::Sequence< OUString > aURLs = aDriverConfig.getURLs();
+ const OUString* pIter = aURLs.getConstArray();
+ const OUString* pEnd = pIter + aURLs.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ FeatureSupport aInit( AuthNone );
+ const ::comphelper::NamedValueCollection& aMetaData = aDriverConfig.getMetaData(*pIter);
+ if ( aMetaData.has("Authentication") )
+ {
+ OUString sAuth;
+ aMetaData.get("Authentication") >>= sAuth;
+ if ( sAuth == "UserPassword" )
+ aInit = FeatureSupport(AuthUserPwd);
+ else if ( sAuth == "Password" )
+ aInit = FeatureSupport(AuthPwd);
+ }
+ tmp.insert(std::make_pair(*pIter,aInit));
+ }
+ return tmp;
+ }();
+ OSL_ENSURE(s_aSupport.find(_sURL) != s_aSupport.end(),"Illegal URL!");
+ return s_aSupport[ _sURL ].eAuthentication;
+ }
+
+ // DataSourceMetaData_Impl
+ class DataSourceMetaData_Impl
+ {
+ public:
+ explicit DataSourceMetaData_Impl(const OUString& rURL);
+
+ const OUString& getType() const { return m_sURL; }
+
+ private:
+ const OUString m_sURL;
+ };
+
+ DataSourceMetaData_Impl::DataSourceMetaData_Impl( const OUString& _sURL )
+ :m_sURL( _sURL )
+ {
+ }
+
+ // DataSourceMetaData
+ DataSourceMetaData::DataSourceMetaData( const OUString& _sURL )
+ :m_pImpl( std::make_shared<DataSourceMetaData_Impl>( _sURL ) )
+ {
+ }
+
+ DataSourceMetaData::~DataSourceMetaData()
+ {
+ }
+
+ const FeatureSet& DataSourceMetaData::getFeatureSet() const
+ {
+ return lcl_getFeatureSet( m_pImpl->getType() );
+ }
+
+ AuthenticationMode DataSourceMetaData::getAuthentication( const OUString& _sURL )
+ {
+ return getAuthenticationMode( _sURL );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/imageprovider.cxx b/dbaccess/source/ui/misc/imageprovider.cxx
new file mode 100644
index 000000000..b69ec70e6
--- /dev/null
+++ b/dbaccess/source/ui/misc/imageprovider.cxx
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <imageprovider.hxx>
+#include <bitmaps.hlst>
+
+#include <com/sun/star/graphic/GraphicColorMode.hpp>
+#include <com/sun/star/sdb/application/XTableUIProvider.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::graphic::XGraphic;
+ using ::com::sun::star::sdb::application::XTableUIProvider;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::sdbcx::XViewsSupplier;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+
+ namespace GraphicColorMode = css::graphic::GraphicColorMode;
+ namespace DatabaseObject = css::sdb::application::DatabaseObject;
+
+ // ImageProvider_Data
+ struct ImageProvider_Data
+ {
+ /// the connection we work with
+ Reference< XConnection > xConnection;
+ /// the views of the connection, if the DB supports views
+ Reference< XNameAccess > xViews;
+ /// interface for providing table's UI
+ Reference< XTableUIProvider > xTableUI;
+ };
+
+ namespace
+ {
+ void lcl_getConnectionProvidedTableIcon_nothrow( const ImageProvider_Data& _rData,
+ const OUString& _rName, Reference< XGraphic >& _out_rxGraphic )
+ {
+ try
+ {
+ if ( _rData.xTableUI.is() )
+ _out_rxGraphic = _rData.xTableUI->getTableIcon( _rName, GraphicColorMode::NORMAL );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void lcl_getTableImageResourceID_nothrow( const ImageProvider_Data& _rData, const OUString& _rName,
+ OUString& _out_rResourceID)
+ {
+ _out_rResourceID = OUString();
+ try
+ {
+ bool bIsView = _rData.xViews.is() && _rData.xViews->hasByName( _rName );
+ if ( bIsView )
+ {
+ _out_rResourceID = VIEW_TREE_ICON;
+ }
+ else
+ {
+ _out_rResourceID = TABLE_TREE_ICON;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ // ImageProvider
+ ImageProvider::ImageProvider()
+ :m_pData( std::make_shared<ImageProvider_Data>() )
+ {
+ }
+
+ ImageProvider::ImageProvider( const Reference< XConnection >& _rxConnection )
+ :m_pData( std::make_shared<ImageProvider_Data>() )
+ {
+ m_pData->xConnection = _rxConnection;
+ try
+ {
+ Reference< XViewsSupplier > xSuppViews( m_pData->xConnection, UNO_QUERY );
+ if ( xSuppViews.is() )
+ m_pData->xViews.set( xSuppViews->getViews(), UNO_SET_THROW );
+
+ m_pData->xTableUI.set( _rxConnection, UNO_QUERY );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ OUString ImageProvider::getImageId(const OUString& _rName, const sal_Int32 _nDatabaseObjectType)
+ {
+ if (_nDatabaseObjectType != DatabaseObject::TABLE)
+ {
+ // for types other than tables, the icon does not depend on the concrete object
+ return getDefaultImageResourceID( _nDatabaseObjectType );
+ }
+ else
+ {
+ // no -> determine by type
+ OUString sImageResourceID;
+ lcl_getTableImageResourceID_nothrow( *m_pData, _rName, sImageResourceID );
+ return sImageResourceID;
+ }
+ }
+
+ Reference<XGraphic> ImageProvider::getXGraphic(const OUString& _rName, const sal_Int32 _nDatabaseObjectType)
+ {
+ Reference<XGraphic> xGraphic;
+ if (_nDatabaseObjectType == DatabaseObject::TABLE)
+ {
+ // check whether the connection can give us an icon
+ lcl_getConnectionProvidedTableIcon_nothrow( *m_pData, _rName, xGraphic );
+ }
+ return xGraphic;
+ }
+
+ OUString ImageProvider::getDefaultImageResourceID( sal_Int32 _nDatabaseObjectType)
+ {
+ OUString sImageResourceID;
+ switch ( _nDatabaseObjectType )
+ {
+ case DatabaseObject::QUERY:
+ sImageResourceID = QUERY_TREE_ICON;
+ break;
+ case DatabaseObject::FORM:
+ sImageResourceID = FORM_TREE_ICON;
+ break;
+ case DatabaseObject::REPORT:
+ sImageResourceID = REPORT_TREE_ICON;
+ break;
+ case DatabaseObject::TABLE:
+ sImageResourceID = TABLE_TREE_ICON;
+ break;
+ default:
+ OSL_FAIL( "ImageProvider::getDefaultImage: invalid database object type!" );
+ break;
+ }
+ return sImageResourceID;
+ }
+
+ OUString ImageProvider::getFolderImageId( sal_Int32 _nDatabaseObjectType )
+ {
+ OUString sImageResourceID;
+ switch ( _nDatabaseObjectType )
+ {
+ case DatabaseObject::QUERY:
+ sImageResourceID = QUERYFOLDER_TREE_ICON;
+ break;
+ case DatabaseObject::FORM:
+ sImageResourceID = FORMFOLDER_TREE_ICON;
+ break;
+ case DatabaseObject::REPORT:
+ sImageResourceID = REPORTFOLDER_TREE_ICON;
+ break;
+ case DatabaseObject::TABLE:
+ sImageResourceID = TABLEFOLDER_TREE_ICON;
+ break;
+ default:
+ OSL_FAIL( "ImageProvider::getDefaultImage: invalid database object type!" );
+ break;
+ }
+
+ return sImageResourceID;
+ }
+
+ OUString ImageProvider::getDatabaseImage()
+ {
+ return DATABASE_TREE_ICON;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/indexcollection.cxx b/dbaccess/source/ui/misc/indexcollection.cxx
new file mode 100644
index 000000000..1b9377362
--- /dev/null
+++ b/dbaccess/source/ui/misc/indexcollection.cxx
@@ -0,0 +1,328 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <indexcollection.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <comphelper/extract.hxx>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::sdbc;
+
+ // OIndexCollection
+ OIndexCollection::OIndexCollection()
+ {
+ }
+
+ OIndexCollection::OIndexCollection(const OIndexCollection& _rSource)
+ {
+ *this = _rSource;
+ }
+
+ OIndexCollection& OIndexCollection::operator=(const OIndexCollection& _rSource)
+ {
+ detach();
+ m_xIndexes = _rSource.m_xIndexes;
+ m_aIndexes = _rSource.m_aIndexes;
+ return *this;
+ }
+
+ void OIndexCollection::attach(const Reference< XNameAccess >& _rxIndexes)
+ {
+ implConstructFrom(_rxIndexes);
+ }
+
+ void OIndexCollection::detach()
+ {
+ m_xIndexes.clear();
+ m_aIndexes.clear();
+ }
+
+ Indexes::const_iterator OIndexCollection::find(const OUString& _rName) const
+ {
+ // loop'n'compare
+ return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(),
+ [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; });
+ }
+
+ Indexes::iterator OIndexCollection::find(const OUString& _rName)
+ {
+ // loop'n'compare
+ return std::find_if(m_aIndexes.begin(), m_aIndexes.end(),
+ [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; });
+ }
+
+ Indexes::const_iterator OIndexCollection::findOriginal(const OUString& _rName) const
+ {
+ // loop'n'compare
+ return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(),
+ [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; });
+ }
+
+ Indexes::iterator OIndexCollection::findOriginal(const OUString& _rName)
+ {
+ // loop'n'compare
+ return std::find_if(m_aIndexes.begin(), m_aIndexes.end(),
+ [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; });
+ }
+
+ void OIndexCollection::commitNewIndex(const Indexes::iterator& _rPos)
+ {
+ OSL_ENSURE(_rPos->isNew(), "OIndexCollection::commitNewIndex: index must be new!");
+
+ try
+ {
+ Reference< XDataDescriptorFactory > xIndexFactory(m_xIndexes, UNO_QUERY);
+ Reference< XAppend > xAppendIndex(xIndexFactory, UNO_QUERY);
+ if (!xAppendIndex.is())
+ {
+ OSL_FAIL("OIndexCollection::commitNewIndex: missing an interface of the index container!");
+ return;
+ }
+
+ Reference< XPropertySet > xIndexDescriptor = xIndexFactory->createDataDescriptor();
+ Reference< XColumnsSupplier > xColsSupp(xIndexDescriptor, UNO_QUERY);
+ Reference< XNameAccess > xCols;
+ if (xColsSupp.is())
+ xCols = xColsSupp->getColumns();
+
+ Reference< XDataDescriptorFactory > xColumnFactory(xCols, UNO_QUERY);
+ Reference< XAppend > xAppendCols(xColumnFactory, UNO_QUERY);
+ if (!xAppendCols.is())
+ {
+ OSL_FAIL("OIndexCollection::commitNewIndex: invalid index descriptor returned!");
+ return;
+ }
+
+ // set the properties
+ static constexpr OUStringLiteral s_sNamePropertyName = u"Name";
+ // the index' own props
+ xIndexDescriptor->setPropertyValue("IsUnique", css::uno::Any(_rPos->bUnique));
+ xIndexDescriptor->setPropertyValue(s_sNamePropertyName, Any(_rPos->sName));
+
+ // the fields
+ for (auto const& field : _rPos->aFields)
+ {
+ OSL_ENSURE(!xCols->hasByName(field.sFieldName), "OIndexCollection::commitNewIndex: double column name (need to prevent this outside)!");
+
+ Reference< XPropertySet > xColDescriptor = xColumnFactory->createDataDescriptor();
+ OSL_ENSURE(xColDescriptor.is(), "OIndexCollection::commitNewIndex: invalid column descriptor!");
+ if (xColDescriptor.is())
+ {
+ xColDescriptor->setPropertyValue("IsAscending", css::uno::Any(field.bSortAscending));
+ xColDescriptor->setPropertyValue(s_sNamePropertyName, Any(field.sFieldName));
+ xAppendCols->appendByDescriptor(xColDescriptor);
+ }
+ }
+
+ xAppendIndex->appendByDescriptor(xIndexDescriptor);
+
+ _rPos->flagAsCommitted(GrantIndexAccess());
+ _rPos->clearModified();
+ }
+ catch(SQLException&)
+ { // allowed to pass
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ bool OIndexCollection::dropNoRemove(const Indexes::iterator& _rPos)
+ {
+ try
+ {
+ OSL_ENSURE(m_xIndexes->hasByName(_rPos->getOriginalName()), "OIndexCollection::drop: invalid name!");
+
+ Reference< XDrop > xDropIndex(m_xIndexes, UNO_QUERY);
+ if (!xDropIndex.is())
+ {
+ OSL_FAIL("OIndexCollection::drop: no XDrop interface!");
+ return false;
+ }
+
+ xDropIndex->dropByName(_rPos->getOriginalName());
+ }
+ catch(SQLException&)
+ { // allowed to pass
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ return false;
+ }
+
+ // adjust the OIndex structure
+ Indexes::iterator aDropped = findOriginal(_rPos->getOriginalName());
+ OSL_ENSURE(aDropped != m_aIndexes.end(), "OIndexCollection::drop: invalid original name, but successful commit?!");
+ aDropped->flagAsNew(GrantIndexAccess());
+
+ return true;
+ }
+
+ bool OIndexCollection::drop(const Indexes::iterator& _rPos)
+ {
+ OSL_ENSURE((_rPos >= m_aIndexes.begin()) && (_rPos < m_aIndexes.end()),
+ "OIndexCollection::drop: invalid position (fasten your seatbelt... this will crash)!");
+
+ if (!_rPos->isNew())
+ if (!dropNoRemove(_rPos))
+ return false;
+
+ // adjust the index array
+ m_aIndexes.erase(_rPos);
+ return true;
+ }
+
+ void OIndexCollection::implFillIndexInfo(OIndex& _rIndex)
+ {
+ // get the UNO descriptor for the index
+ Reference< XPropertySet > xIndex;
+ m_xIndexes->getByName(_rIndex.getOriginalName()) >>= xIndex;
+ if (!xIndex.is())
+ {
+ OSL_FAIL("OIndexCollection::implFillIndexInfo: got an invalid index object!");
+ }
+ else
+ implFillIndexInfo(_rIndex, xIndex);
+ }
+
+ void OIndexCollection::implFillIndexInfo(OIndex& _rIndex, const Reference< XPropertySet >& _rxDescriptor)
+ {
+ _rIndex.bPrimaryKey = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsPrimaryKeyIndex"));
+ _rIndex.bUnique = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsUnique"));
+ _rxDescriptor->getPropertyValue("Catalog") >>= _rIndex.sDescription;
+
+ // the columns
+ Reference< XColumnsSupplier > xSuppCols(_rxDescriptor, UNO_QUERY);
+ Reference< XNameAccess > xCols;
+ if (xSuppCols.is())
+ xCols = xSuppCols->getColumns();
+ OSL_ENSURE(xCols.is(), "OIndexCollection::implFillIndexInfo: the index does not have columns!");
+ if (!xCols.is())
+ return;
+
+ Sequence< OUString > aFieldNames = xCols->getElementNames();
+ _rIndex.aFields.resize(aFieldNames.getLength());
+
+ const OUString* pFieldNames = aFieldNames.getConstArray();
+ const OUString* pFieldNamesEnd = pFieldNames + aFieldNames.getLength();
+ IndexFields::iterator aCopyTo = _rIndex.aFields.begin();
+
+ Reference< XPropertySet > xIndexColumn;
+ for (;pFieldNames < pFieldNamesEnd; ++pFieldNames, ++aCopyTo)
+ {
+ // extract the column
+ xIndexColumn.clear();
+ xCols->getByName(*pFieldNames) >>= xIndexColumn;
+ if (!xIndexColumn.is())
+ {
+ OSL_FAIL("OIndexCollection::implFillIndexInfo: invalid index column!");
+ --aCopyTo;
+ continue;
+ }
+
+ // get the relevant properties
+ aCopyTo->sFieldName = *pFieldNames;
+ aCopyTo->bSortAscending = ::cppu::any2bool(xIndexColumn->getPropertyValue("IsAscending"));
+ }
+
+ _rIndex.aFields.resize(aCopyTo - _rIndex.aFields.begin());
+ // (just in case some fields were invalid ...)
+ }
+
+ void OIndexCollection::resetIndex(const Indexes::iterator& _rPos)
+ {
+ OSL_ENSURE(_rPos >= m_aIndexes.begin() && _rPos < m_aIndexes.end(),
+ "OIndexCollection::resetIndex: invalid position!");
+
+ try
+ {
+ _rPos->sName = _rPos->getOriginalName();
+ implFillIndexInfo(*_rPos);
+
+ _rPos->clearModified();
+ _rPos->flagAsCommitted(GrantIndexAccess());
+ }
+ catch(SQLException&)
+ { // allowed to pass
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ Indexes::iterator OIndexCollection::insert(const OUString& _rName)
+ {
+ OSL_ENSURE(end() == find(_rName), "OIndexCollection::insert: invalid new name!");
+ OIndex aNewIndex((OUString())); // the empty string indicates the index is a new one
+ aNewIndex.sName = _rName;
+ m_aIndexes.push_back(aNewIndex);
+ return m_aIndexes.end() - 1; // the last element is the new one ...
+ }
+
+ void OIndexCollection::implConstructFrom(const Reference< XNameAccess >& _rxIndexes)
+ {
+ detach();
+
+ m_xIndexes = _rxIndexes;
+ if (!m_xIndexes.is())
+ return;
+
+ // loop through all the indexes
+ Sequence< OUString > aNames = m_xIndexes->getElementNames();
+ const OUString* pNames = aNames.getConstArray();
+ const OUString* pEnd = pNames + aNames.getLength();
+ for (; pNames < pEnd; ++pNames)
+ {
+ // extract the index object
+ Reference< XPropertySet > xIndex;
+ m_xIndexes->getByName(*pNames) >>= xIndex;
+ if (!xIndex.is())
+ {
+ OSL_FAIL("OIndexCollection::implConstructFrom: got an invalid index object ... ignoring!");
+ continue;
+ }
+
+ // fill the OIndex structure
+ OIndex aCurrentIndex(*pNames);
+ implFillIndexInfo(aCurrentIndex);
+ m_aIndexes.push_back(aCurrentIndex);
+ }
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/linkeddocuments.cxx b/dbaccess/source/ui/misc/linkeddocuments.cxx
new file mode 100644
index 000000000..192331ced
--- /dev/null
+++ b/dbaccess/source/ui/misc/linkeddocuments.cxx
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <core_resource.hxx>
+#include <linkeddocuments.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include <unotools/confignode.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/task/XJobExecutor.hpp>
+#include <comphelper/types.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <svl/filenotation.hxx>
+#include <browserids.hxx>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <comphelper/mimeconfighelper.hxx>
+#include <vcl/weld.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/io/WrongFormatException.hpp>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::ucb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb::application;
+ using namespace ::com::sun::star::task;
+ using namespace ::svt;
+
+ namespace
+ {
+ Sequence< sal_Int8 > lcl_GetSequenceClassID( sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3,
+ sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11,
+ sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15 )
+ {
+ Sequence< sal_Int8 > aResult{ /* [ 0] */ static_cast<sal_Int8>(n1 >> 24),
+ /* [ 1] */ static_cast<sal_Int8>(( n1 << 8 ) >> 24),
+ /* [ 2] */ static_cast<sal_Int8>(( n1 << 16 ) >> 24),
+ /* [ 3] */ static_cast<sal_Int8>(( n1 << 24 ) >> 24),
+ /* [ 4] */ static_cast<sal_Int8>(n2 >> 8),
+ /* [ 5] */ static_cast<sal_Int8>(( n2 << 8 ) >> 8),
+ /* [ 6] */ static_cast<sal_Int8>(n3 >> 8),
+ /* [ 7] */ static_cast<sal_Int8>(( n3 << 8 ) >> 8),
+ /* [ 8] */ static_cast<sal_Int8>(b8),
+ /* [ 9] */ static_cast<sal_Int8>(b9),
+ /* [10] */ static_cast<sal_Int8>(b10),
+ /* [11] */ static_cast<sal_Int8>(b11),
+ /* [12] */ static_cast<sal_Int8>(b12),
+ /* [13] */ static_cast<sal_Int8>(b13),
+ /* [14] */ static_cast<sal_Int8>(b14),
+ /* [15] */ static_cast<sal_Int8>(b15) };
+ return aResult;
+ }
+ }
+
+ // OLinkedDocumentsAccess
+ OLinkedDocumentsAccess::OLinkedDocumentsAccess( weld::Window* pDialogParent, const Reference< XDatabaseDocumentUI >& i_rDocumentUI,
+ const Reference< XComponentContext >& _rxContext, const Reference< XNameAccess >& _rxContainer,
+ const Reference< XConnection>& _xConnection, const OUString& _sDataSourceName )
+ :m_xContext(_rxContext)
+ ,m_xDocumentContainer(_rxContainer)
+ ,m_xConnection(_xConnection)
+ ,m_xDocumentUI( i_rDocumentUI )
+ ,m_pDialogParent(pDialogParent)
+ ,m_sDataSourceName(_sDataSourceName)
+ {
+ OSL_ENSURE(m_xContext.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid service factory!");
+ assert(m_pDialogParent && "OLinkedDocumentsAccess::OLinkedDocumentsAccess: really need a dialog parent!");
+ }
+ OLinkedDocumentsAccess::~OLinkedDocumentsAccess()
+ {
+ }
+ Reference< XComponent> OLinkedDocumentsAccess::impl_open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition,
+ ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs )
+ {
+ Reference< XComponent> xRet;
+ OSL_ENSURE(m_xDocumentContainer.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid document container!");
+ Reference< XComponentLoader > xComponentLoader(m_xDocumentContainer,UNO_QUERY);
+ if ( !xComponentLoader.is() )
+ return xRet;
+
+ weld::WaitObject aWaitCursor(m_pDialogParent);
+
+ ::comphelper::NamedValueCollection aArguments;
+ OUString sOpenMode;
+ switch ( _eOpenMode )
+ {
+ case E_OPEN_NORMAL:
+ sOpenMode = "open";
+ break;
+
+ case E_OPEN_FOR_MAIL:
+ aArguments.put( "Hidden", true );
+ [[fallthrough]];
+
+ case E_OPEN_DESIGN:
+ sOpenMode = "openDesign";
+ break;
+
+ default:
+ OSL_FAIL( "OLinkedDocumentsAccess::implOpen: invalid open mode!" );
+ break;
+ }
+ aArguments.put( "OpenMode", sOpenMode );
+
+ aArguments.put( PROPERTY_ACTIVE_CONNECTION, m_xConnection );
+
+ Reference<XHierarchicalNameContainer> xHier(m_xDocumentContainer,UNO_QUERY);
+ if ( xHier.is() && xHier->hasByHierarchicalName(_rLinkName) )
+ {
+ _xDefinition.set(xHier->getByHierarchicalName(_rLinkName),UNO_QUERY);
+ }
+
+ aArguments.merge( _rAdditionalArgs, true );
+
+ xRet = xComponentLoader->loadComponentFromURL( _rLinkName, OUString(), 0, aArguments.getPropertyValues() );
+
+ return xRet;
+ }
+ void OLinkedDocumentsAccess::impl_newWithPilot( const char* _pWizardService,
+ const sal_Int32 _nCommandType, const OUString& _rObjectName )
+ {
+ try
+ {
+ ::comphelper::NamedValueCollection aArgs;
+ aArgs.put( "DataSourceName", m_sDataSourceName );
+
+ if ( m_xConnection.is() )
+ aArgs.put( "ActiveConnection", m_xConnection );
+
+ if ( !_rObjectName.isEmpty() && ( _nCommandType != -1 ) )
+ {
+ aArgs.put( "CommandType", _nCommandType );
+ aArgs.put( "Command", _rObjectName );
+ }
+
+ aArgs.put( "DocumentUI", m_xDocumentUI );
+
+ Reference< XJobExecutor > xWizard;
+ {
+ weld::WaitObject aWaitCursor(m_pDialogParent);
+ xWizard.set( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ OUString::createFromAscii( _pWizardService ),
+ aArgs.getWrappedPropertyValues(),
+ m_xContext
+ ), UNO_QUERY_THROW );
+ }
+
+ xWizard->trigger( "start" );
+ ::comphelper::disposeComponent( xWizard );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ void OLinkedDocumentsAccess::newFormWithPilot( const sal_Int32 _nCommandType,const OUString& _rObjectName )
+ {
+ impl_newWithPilot( "com.sun.star.wizards.form.CallFormWizard", _nCommandType, _rObjectName );
+ }
+
+ void OLinkedDocumentsAccess::newReportWithPilot( const sal_Int32 _nCommandType, const OUString& _rObjectName )
+ {
+ impl_newWithPilot( "com.sun.star.wizards.report.CallReportWizard", _nCommandType, _rObjectName );
+ }
+ void OLinkedDocumentsAccess::newTableWithPilot()
+ {
+ impl_newWithPilot( "com.sun.star.wizards.table.CallTableWizard", -1, OUString() );
+ }
+ void OLinkedDocumentsAccess::newQueryWithPilot()
+ {
+ impl_newWithPilot( "com.sun.star.wizards.query.CallQueryWizard", -1, OUString() );
+ }
+ Reference< XComponent > OLinkedDocumentsAccess::newDocument( sal_Int32 i_nActionID,
+ const ::comphelper::NamedValueCollection& i_rCreationArgs, Reference< XComponent >& o_rDefinition )
+ {
+ OSL_ENSURE(m_xDocumentContainer.is(), "OLinkedDocumentsAccess::newDocument: invalid document container!");
+ // determine the class ID to use for the new document
+ Sequence<sal_Int8> aClassId;
+ if ( !i_rCreationArgs.has( "ClassID" )
+ && !i_rCreationArgs.has( "MediaType" )
+ && !i_rCreationArgs.has( "DocumentServiceName" )
+ )
+ {
+ switch ( i_nActionID )
+ {
+ case ID_FORM_NEW_TEXT:
+ aClassId = lcl_GetSequenceClassID(SO3_SW_CLASSID);
+ OSL_ENSURE(aClassId == comphelper::MimeConfigurationHelper::GetSequenceClassID(SO3_SW_CLASSID),"Not equal");
+ break;
+
+ case ID_FORM_NEW_CALC:
+ aClassId = lcl_GetSequenceClassID(SO3_SC_CLASSID);
+ break;
+
+ case ID_FORM_NEW_IMPRESS:
+ aClassId = lcl_GetSequenceClassID(SO3_SIMPRESS_CLASSID);
+ break;
+
+ case ID_REPORT_NEW_TEXT:
+ aClassId = comphelper::MimeConfigurationHelper::GetSequenceClassID(SO3_RPT_CLASSID_90);
+ break;
+
+ default:
+ OSL_FAIL( "OLinkedDocumentsAccess::newDocument: please use newFormWithPilot!" );
+ return Reference< XComponent >();
+
+ }
+ }
+
+ // load the document as template
+ Reference< XComponent > xNewDocument;
+ try
+ { // get the desktop object
+
+ Reference<XMultiServiceFactory> xORB(m_xDocumentContainer,UNO_QUERY);
+ if ( xORB.is() )
+ {
+ ::comphelper::NamedValueCollection aCreationArgs( i_rCreationArgs );
+ if ( aClassId.hasElements() )
+ aCreationArgs.put( "ClassID", aClassId );
+ aCreationArgs.put( PROPERTY_ACTIVE_CONNECTION, m_xConnection );
+
+ // separate values which are real creation args from args relevant for opening the doc
+ ::comphelper::NamedValueCollection aCommandArgs;
+ if ( aCreationArgs.has( "Hidden" ) )
+ {
+ aCommandArgs.put( "Hidden", aCreationArgs.get( "Hidden" ) );
+ aCreationArgs.remove( "Hidden" );
+ }
+
+ Reference< XCommandProcessor > xContent( xORB->createInstanceWithArguments(
+ SERVICE_SDB_DOCUMENTDEFINITION,
+ aCreationArgs.getWrappedPropertyValues()
+ ),
+ UNO_QUERY_THROW
+ );
+ o_rDefinition.set( xContent, UNO_QUERY );
+
+ // put the OpenMode into the OpenArgs
+ OpenCommandArgument aOpenModeArg;
+ aOpenModeArg.Mode = OpenMode::DOCUMENT;
+ aCommandArgs.put( "OpenMode", aOpenModeArg );
+
+ Command aCommand;
+ aCommand.Name = "openDesign";
+ aCommand.Argument <<= aCommandArgs.getPropertyValues();
+ weld::WaitObject aWaitCursor(m_pDialogParent);
+ xNewDocument.set( xContent->execute( aCommand, xContent->createCommandIdentifier(), nullptr ), UNO_QUERY );
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return xNewDocument;
+ }
+
+ Reference< XComponent > OLinkedDocumentsAccess::open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition,
+ ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs )
+ {
+ dbtools::SQLExceptionInfo aInfo;
+ Reference< XComponent > xRet;
+ try
+ {
+ xRet = impl_open( _rLinkName, _xDefinition, _eOpenMode, _rAdditionalArgs );
+ if ( !xRet.is() )
+ {
+ OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC);
+ sMessage = sMessage.replaceFirst("$file$",_rLinkName);
+
+ css::sdbc::SQLException aSQLException;
+ aSQLException.Message = sMessage;
+ aInfo = dbtools::SQLExceptionInfo(aSQLException);
+ }
+ }
+ catch(const css::io::WrongFormatException &e)
+ {
+ css::sdbc::SQLException aSQLException;
+ aSQLException.Message = e.Message;
+ aSQLException.Context = e.Context;
+ aInfo = dbtools::SQLExceptionInfo(aSQLException);
+
+ // more like a hack, insert an empty message
+ OUString sText( DBA_RES( RID_STR_EXTENSION_NOT_PRESENT ) );
+ sText = sText.replaceFirst("$file$",_rLinkName);
+ aInfo.prepend(sText);
+
+ OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC);
+ sMessage = sMessage.replaceFirst("$file$",_rLinkName);
+ aInfo.prepend(sMessage);
+ }
+ catch(const Exception& e)
+ {
+ Any aAny = ::cppu::getCaughtException();
+ css::sdbc::SQLException a;
+ if ( !(aAny >>= a) || (a.ErrorCode != dbtools::ParameterInteractionCancelled) )
+ {
+ css::sdbc::SQLException aSQLException;
+ aSQLException.Message = e.Message;
+ aSQLException.Context = e.Context;
+ aInfo = dbtools::SQLExceptionInfo(aSQLException);
+
+ // more like a hack, insert an empty message
+ aInfo.prepend(" \n");
+
+ OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC);
+ sMessage = sMessage.replaceFirst("$file$",_rLinkName);
+ aInfo.prepend(sMessage);
+ }
+ }
+ if (aInfo.isValid())
+ {
+ showError(aInfo, m_pDialogParent->GetXWindow(), m_xContext);
+ }
+ return xRet;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/propertystorage.cxx b/dbaccess/source/ui/misc/propertystorage.cxx
new file mode 100644
index 000000000..c3c504994
--- /dev/null
+++ b/dbaccess/source/ui/misc/propertystorage.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <propertystorage.hxx>
+
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+
+#include <osl/diagnose.h>
+
+#include <cassert>
+#include <memory>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Any;
+
+ // helper
+ namespace
+ {
+ template < class ITEMTYPE, class UNOTYPE >
+ class ItemAdapter
+ {
+ public:
+ static bool trySet( SfxItemSet& _rSet, sal_uInt16 _nItemId, const Any& _rValue )
+ {
+ const SfxPoolItem& rItem( _rSet.Get( _nItemId ) );
+ const ITEMTYPE* pTypedItem = dynamic_cast< const ITEMTYPE* >( &rItem );
+ if ( !pTypedItem )
+ return false;
+
+ UNOTYPE aValue( pTypedItem->GetValue() );
+ OSL_VERIFY( _rValue >>= aValue );
+ // TODO: one could throw an IllegalArgumentException here - finally, this method
+ // is (to be) used from within an XPropertySet::setPropertyValue implementation,
+ // where this would be the appropriate reaction on wrong value types
+ ITEMTYPE* pCloneItem = dynamic_cast< ITEMTYPE* >( pTypedItem->Clone() );
+ if(!pCloneItem)
+ {
+ return false;
+ }
+ std::unique_ptr< ITEMTYPE > pClone( pCloneItem);
+ assert(pClone.get());
+ pClone->SetValue( aValue );
+ _rSet.Put( std::move(pClone) );
+ return true;
+ }
+
+ static bool tryGet( const SfxPoolItem& _rItem, Any& _out_rValue )
+ {
+ const ITEMTYPE* pTypedItem = dynamic_cast< const ITEMTYPE* >( &_rItem );
+ if ( !pTypedItem )
+ return false;
+
+ _out_rValue <<= UNOTYPE( pTypedItem->GetValue() );
+ return true;
+ }
+ };
+ }
+
+ // SetItemPropertyStorage
+ void SetItemPropertyStorage::getPropertyValue( Any& _out_rValue ) const
+ {
+ const SfxPoolItem& rItem( m_rItemSet.Get( m_nItemID ) );
+
+ // try some known item types
+ if ( ItemAdapter< SfxBoolItem, bool >::tryGet( rItem, _out_rValue )
+ || ItemAdapter< SfxStringItem, OUString >::tryGet( rItem, _out_rValue )
+ )
+ return;
+
+ OSL_FAIL( "SetItemPropertyStorage::getPropertyValue: unsupported item type!" );
+ }
+
+ void SetItemPropertyStorage::setPropertyValue( const Any& _rValue )
+ {
+ // try some known item types
+ if ( ItemAdapter< SfxBoolItem, bool >::trySet( m_rItemSet, m_nItemID, _rValue )
+ || ItemAdapter< SfxStringItem, OUString >::trySet( m_rItemSet, m_nItemID, _rValue )
+ )
+ return;
+
+ OSL_FAIL( "SetItemPropertyStorage::setPropertyValue: unsupported item type!" );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/singledoccontroller.cxx b/dbaccess/source/ui/misc/singledoccontroller.cxx
new file mode 100644
index 000000000..28b0c9e77
--- /dev/null
+++ b/dbaccess/source/ui/misc/singledoccontroller.cxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbaccess/dbaundomanager.hxx>
+#include <dbaccess/dataview.hxx>
+#include <core_resource.hxx>
+#include <singledoccontroller.hxx>
+#include <browserids.hxx>
+#include <strings.hrc>
+
+#include <svl/undo.hxx>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::document::XUndoManager;
+ using ::com::sun::star::beans::PropertyValue;
+
+ // OSingleDocumentController_Data
+ struct OSingleDocumentController_Data
+ {
+ // no Reference! see UndoManager::acquire
+ std::unique_ptr<UndoManager> m_pUndoManager;
+
+ OSingleDocumentController_Data( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex )
+ : m_pUndoManager(new UndoManager(i_parent, i_mutex))
+ {
+ }
+ };
+
+ // OSingleDocumentController
+ OSingleDocumentController::OSingleDocumentController( const Reference< XComponentContext >& _rxORB )
+ :OSingleDocumentController_Base( _rxORB )
+ ,m_pData( new OSingleDocumentController_Data( *this, getMutex() ) )
+ {
+ }
+
+ OSingleDocumentController::~OSingleDocumentController()
+ {
+ }
+
+ void SAL_CALL OSingleDocumentController::disposing()
+ {
+ OSingleDocumentController_Base::disposing();
+ ClearUndoManager();
+ m_pData->m_pUndoManager->disposing();
+ }
+
+ void OSingleDocumentController::ClearUndoManager()
+ {
+ GetUndoManager().Clear();
+ }
+
+ SfxUndoManager& OSingleDocumentController::GetUndoManager() const
+ {
+ return m_pData->m_pUndoManager->GetSfxUndoManager();
+ }
+
+ void OSingleDocumentController::addUndoActionAndInvalidate(std::unique_ptr<SfxUndoAction> _pAction)
+ {
+ // add undo action
+ GetUndoManager().AddUndoAction( std::move(_pAction) );
+
+ // when we add an undo action the controller was modified
+ setModified( true );
+
+ // now inform me that or states changed
+ InvalidateFeature( ID_BROWSER_UNDO );
+ InvalidateFeature( ID_BROWSER_REDO );
+ }
+
+ Reference< XUndoManager > SAL_CALL OSingleDocumentController::getUndoManager( )
+ {
+ // see UndoManager::acquire
+ return m_pData->m_pUndoManager.get();
+ }
+
+ FeatureState OSingleDocumentController::GetState(sal_uInt16 _nId) const
+ {
+ FeatureState aReturn;
+ switch ( _nId )
+ {
+ case ID_BROWSER_UNDO:
+ aReturn.bEnabled = isEditable() && GetUndoManager().GetUndoActionCount() != 0;
+ if ( aReturn.bEnabled )
+ {
+ OUString sUndo = DBA_RES(STR_UNDO_COLON) + " " +
+ GetUndoManager().GetUndoActionComment();
+ aReturn.sTitle = sUndo;
+ }
+ break;
+
+ case ID_BROWSER_REDO:
+ aReturn.bEnabled = isEditable() && GetUndoManager().GetRedoActionCount() != 0;
+ if ( aReturn.bEnabled )
+ {
+ OUString sRedo = DBA_RES(STR_REDO_COLON) + " " +
+ GetUndoManager().GetRedoActionComment();
+ aReturn.sTitle = sRedo;
+ }
+ break;
+
+ case SID_GETUNDOSTRINGS:
+ {
+ size_t nCount(GetUndoManager().GetUndoActionCount());
+ Sequence<OUString> aSeq(nCount);
+ auto aSeqRange = asNonConstRange(aSeq);
+ for (size_t n = 0; n < nCount; ++n)
+ aSeqRange[n] = GetUndoManager().GetUndoActionComment(n);
+ aReturn.aValue <<= aSeq;
+ aReturn.bEnabled = true;
+ break;
+ }
+
+ case SID_GETREDOSTRINGS:
+ {
+ size_t nCount(GetUndoManager().GetRedoActionCount());
+ Sequence<OUString> aSeq(nCount);
+ auto aSeqRange = asNonConstRange(aSeq);
+ for (size_t n = 0; n < nCount; ++n)
+ aSeqRange[n] = GetUndoManager().GetRedoActionComment(n);
+ aReturn.aValue <<= aSeq;
+ aReturn.bEnabled = true;
+ break;
+ }
+
+ default:
+ aReturn = OSingleDocumentController_Base::GetState(_nId);
+ }
+ return aReturn;
+ }
+ void OSingleDocumentController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs )
+ {
+ switch ( _nId )
+ {
+ case ID_BROWSER_UNDO:
+ case ID_BROWSER_REDO:
+ {
+ sal_Int16 nCount(1);
+ if (_rArgs.hasElements() && _rArgs[0].Name != "KeyModifier")
+ _rArgs[0].Value >>= nCount;
+
+ while (nCount--)
+ {
+ if (_nId == ID_BROWSER_UNDO)
+ GetUndoManager().Undo();
+ else
+ GetUndoManager().Redo();
+ }
+
+ InvalidateFeature( ID_BROWSER_UNDO );
+ InvalidateFeature( ID_BROWSER_REDO );
+ break;
+ }
+
+ default:
+ OSingleDocumentController_Base::Execute( _nId, _rArgs );
+ break;
+ }
+ InvalidateFeature(_nId);
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/misc/stringlistitem.cxx b/dbaccess/source/ui/misc/stringlistitem.cxx
new file mode 100644
index 000000000..97e75fe6d
--- /dev/null
+++ b/dbaccess/source/ui/misc/stringlistitem.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stringlistitem.hxx>
+
+namespace dbaui
+{
+using namespace ::com::sun::star::uno;
+
+// OStringListItem
+OStringListItem::OStringListItem(sal_Int16 _nWhich, const Sequence<OUString>& _rList)
+ : SfxPoolItem(_nWhich)
+ , m_aList(_rList)
+{
+}
+
+OStringListItem::OStringListItem(const OStringListItem& _rSource)
+ : SfxPoolItem(_rSource)
+ , m_aList(_rSource.m_aList)
+{
+}
+
+bool OStringListItem::operator==(const SfxPoolItem& _rItem) const
+{
+ if (!SfxPoolItem::operator==(_rItem))
+ return false;
+ const OStringListItem* pCompare = static_cast<const OStringListItem*>(&_rItem);
+ if (pCompare->m_aList.getLength() != m_aList.getLength())
+ return false;
+
+ // compare all strings individually
+ for (sal_Int32 i = 0; i < m_aList.getLength(); ++i)
+ if (m_aList[i] != pCompare->m_aList[i])
+ return false;
+
+ return true;
+}
+
+OStringListItem* OStringListItem::Clone(SfxItemPool* /* _pPool */) const
+{
+ return new OStringListItem(*this);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/ConnectionLine.cxx b/dbaccess/source/ui/querydesign/ConnectionLine.cxx
new file mode 100644
index 000000000..77a67004e
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/ConnectionLine.cxx
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ConnectionLine.hxx>
+#include <ConnectionLineData.hxx>
+#include <TableWindow.hxx>
+#include <TableWindowListBox.hxx>
+#include <TableConnection.hxx>
+#include <vcl/svapp.hxx>
+#include <math.h>
+#include <osl/diagnose.h>
+#include <vcl/lineinfo.hxx>
+#include <vcl/settings.hxx>
+
+using namespace dbaui;
+const tools::Long DESCRIPT_LINE_WIDTH = 15;
+const tools::Long HIT_SENSITIVE_RADIUS = 5;
+
+namespace
+{
+ /** calcRect creates a new rectangle with the given points
+ @param _rBase the base point
+ @param _aVector the vector which will be added
+ */
+ tools::Rectangle calcRect(const Point& _rBase,const Point& _aVector)
+ {
+ return tools::Rectangle( _rBase - _aVector, _rBase + _aVector );
+ }
+ /** GetTextPos calculate the rectangle for the connection to be drawn
+ @param _pWin the table window where to draw it
+ @param _aConnPos the connection point
+ @param _aDescrLinePos the description line pos
+ */
+ tools::Rectangle GetTextPos(const OTableWindow* _pWin, const Point& _aConnPos,const Point& _aDescrLinePos)
+ {
+ VclPtr<OTableWindowListBox> pListBox = _pWin ? _pWin->GetListBox() : nullptr;
+ OSL_ENSURE(_pWin && pListBox, "OConnectionLine::GetSourceTextPos : invalid call !");
+
+ tools::Rectangle aReturn;
+ if ( pListBox )
+ {
+ const tools::Long nRowHeight = pListBox->get_widget().get_height_rows(1);
+ aReturn.SetTop( _aConnPos.Y() - nRowHeight );
+ aReturn.SetBottom( aReturn.Top() + nRowHeight );
+ if (_aDescrLinePos.X() < _aConnPos.X())
+ {
+ aReturn.SetLeft( _aDescrLinePos.X() );
+ aReturn.SetRight( aReturn.Left() + _aConnPos.X() - _aDescrLinePos.X() );
+ }
+ else
+ {
+ aReturn.SetLeft( _aConnPos.X() );
+ aReturn.SetRight( aReturn.Left() + _aDescrLinePos.X() - _aConnPos.X() );
+ }
+ }
+
+ return aReturn;
+ }
+ /** calcPointsYValue calculate the points Y value in relation to the listbox entry
+ @param _pWin the corresponding window
+ @param _nEntry the source or dest entry
+ @param _rNewConPos (in/out) the connection pos
+ @param _rNewDescrPos (in/out) the description pos
+ */
+ void calcPointsYValue(const OTableWindow* _pWin, int _nEntry, Point& _rNewConPos, Point& _rNewDescrPos)
+ {
+ const OTableWindowListBox* pListBox = _pWin->GetListBox();
+ _rNewConPos.setY( _pWin->GetPosPixel().Y() );
+
+ std::unique_ptr<weld::TreeIter> xEntry;
+ const weld::TreeView& rTreeView = pListBox->get_widget();
+
+ if (_nEntry != -1)
+ {
+ _rNewConPos.AdjustY(pListBox->GetPosPixel().Y() );
+ xEntry = rTreeView.make_iterator();
+ if (!rTreeView.get_iter_first(*xEntry) || !rTreeView.iter_nth_sibling(*xEntry, _nEntry))
+ xEntry.reset();
+ }
+
+ if (xEntry)
+ {
+ auto nEntryPos = rTreeView.get_row_area(*xEntry).Center().Y();
+
+ if( nEntryPos >= 0 )
+ {
+ _rNewConPos.AdjustY(nEntryPos);
+ }
+ else
+ {
+ const auto nRowHeight = rTreeView.get_height_rows(1);
+ _rNewConPos.AdjustY( -static_cast<tools::Long>( 0.5 * nRowHeight ) );
+ }
+
+ tools::Long nListBoxBottom = _pWin->GetPosPixel().Y()
+ + pListBox->GetPosPixel().Y()
+ + pListBox->GetSizePixel().Height();
+ if( _rNewConPos.Y() > nListBoxBottom )
+ _rNewConPos.setY( nListBoxBottom + 2 );
+ }
+ else
+ _rNewConPos.AdjustY(static_cast<sal_Int32>(pListBox->GetPosPixel().Y()*0.5) );
+
+ _rNewDescrPos.setY( _rNewConPos.Y() );
+ }
+}
+
+OConnectionLine::OConnectionLine( OTableConnection* _pConn, OConnectionLineDataRef const & _pLineData )
+ : m_pTabConn( _pConn )
+ , m_pData( _pLineData )
+{
+}
+
+OConnectionLine::OConnectionLine( const OConnectionLine& _rLine )
+ : m_pTabConn(nullptr)
+{
+ m_pData = new OConnectionLineData( *_rLine.GetData() );
+ *this = _rLine;
+}
+
+OConnectionLine::~OConnectionLine()
+{
+}
+
+OConnectionLine& OConnectionLine::operator=( const OConnectionLine& rLine )
+{
+ if( &rLine != this )
+ {
+ // as the data does not belong to me, I don't delete the old one
+ m_pData->CopyFrom(*rLine.GetData());
+ // CopyFrom is virtual, therefore it is not a problem, if m_pData is of a type derived from OTableConnectionData
+
+ m_pTabConn = rLine.m_pTabConn;
+ m_aSourceConnPos = rLine.m_aSourceConnPos;
+ m_aDestConnPos = rLine.m_aDestConnPos;
+ m_aSourceDescrLinePos = rLine.m_aSourceDescrLinePos;
+ m_aDestDescrLinePos = rLine.m_aDestDescrLinePos;
+ }
+
+ return *this;
+}
+
+tools::Rectangle OConnectionLine::GetBoundingRect() const
+{
+ // determine surrounding rectangle
+ tools::Rectangle aBoundingRect( Point(0,0), Point(0,0) );
+ if( !IsValid() )
+ return aBoundingRect;
+
+ Point aTopLeft;
+ Point aBottomRight;
+
+ if( m_aSourceDescrLinePos.Y() <= m_aDestDescrLinePos.Y() )
+ {
+ aTopLeft.setY( m_aSourceDescrLinePos.Y() );
+ aBottomRight.setY( m_aDestDescrLinePos.Y() );
+ }
+ else
+ {
+ aTopLeft.setY( m_aDestDescrLinePos.Y() );
+ aBottomRight.setY( m_aSourceDescrLinePos.Y() );
+ }
+
+ if( m_aSourceDescrLinePos.X() <= m_aDestDescrLinePos.X() )
+ {
+ aTopLeft.setX( m_aSourceDescrLinePos.X() );
+ aBottomRight.setX( m_aDestDescrLinePos.X() );
+ }
+ else
+ {
+ aTopLeft.setX( m_aDestDescrLinePos.X() );
+ aBottomRight.setX( m_aSourceDescrLinePos.X() );
+ }
+
+ const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin();
+ const OTableWindow* pDestWin = m_pTabConn->GetDestWin();
+ // line proceeds in z-Form
+ if( pSourceWin == pDestWin || std::abs(m_aSourceConnPos.X() - m_aDestConnPos.X()) > std::abs(m_aSourceDescrLinePos.X() - m_aDestDescrLinePos.X()) )
+ {
+ aTopLeft.AdjustX( -DESCRIPT_LINE_WIDTH );
+ aBottomRight.AdjustX(DESCRIPT_LINE_WIDTH );
+ }
+
+ aBoundingRect = tools::Rectangle( aTopLeft-Point(2,17), aBottomRight+Point(2,2) );
+
+ return aBoundingRect;
+}
+
+static void calcPointX1(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos)
+{
+ _rNewConPos.setX( _pWin->GetPosPixel().X() + _pWin->GetSizePixel().Width() );
+ _rNewDescrPos.setX( _rNewConPos.X() );
+ _rNewConPos.AdjustX(DESCRIPT_LINE_WIDTH );
+}
+
+static void calcPointX2(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos)
+{
+ _rNewConPos.setX( _pWin->GetPosPixel().X() );
+ _rNewDescrPos.setX( _rNewConPos.X() );
+ _rNewConPos.AdjustX( -DESCRIPT_LINE_WIDTH );
+}
+
+bool OConnectionLine::RecalcLine()
+{
+ // Windows and entries must be set
+ const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin();
+ const OTableWindow* pDestWin = m_pTabConn->GetDestWin();
+
+ if( !pSourceWin || !pDestWin )
+ return false;
+
+ int nSourceEntry = pSourceWin->GetListBox()->GetEntryFromText( GetData()->GetSourceFieldName() );
+ int nDestEntry = pDestWin->GetListBox()->GetEntryFromText( GetData()->GetDestFieldName() );
+
+ // determine X-coordinates
+ Point aSourceCenter( 0, 0 );
+ Point aDestCenter( 0, 0 );
+
+ aSourceCenter.setX( pSourceWin->GetPosPixel().X() + static_cast<tools::Long>( 0.5*pSourceWin->GetSizePixel().Width() ) );
+ aDestCenter.setX( pDestWin->GetPosPixel().X() + static_cast<tools::Long>( 0.5*pDestWin->GetSizePixel().Width() ) );
+
+ const OTableWindow* pFirstWin = pDestWin;
+ const OTableWindow* pSecondWin = pSourceWin;
+ Point* pFirstConPos = &m_aDestConnPos;
+ Point* pFirstDescrPos = &m_aDestDescrLinePos;
+ Point* pSecondConPos = &m_aSourceConnPos;
+ Point* pSecondDescrPos = &m_aSourceDescrLinePos;
+ if( aDestCenter.X() > aSourceCenter.X() )
+ {
+ pFirstWin = pSourceWin;
+ pSecondWin = pDestWin;
+ pFirstConPos = &m_aSourceConnPos;
+ pFirstDescrPos = &m_aSourceDescrLinePos;
+ pSecondConPos = &m_aDestConnPos;
+ pSecondDescrPos = &m_aDestDescrLinePos;
+ }
+
+ if (pFirstWin == pSecondWin && nSourceEntry != nDestEntry)
+ calcPointX2(pFirstWin,*pFirstConPos,*pFirstDescrPos);
+ else
+ calcPointX1(pFirstWin,*pFirstConPos,*pFirstDescrPos);
+ calcPointX2(pSecondWin,*pSecondConPos,*pSecondDescrPos);
+
+ // determine aSourceConnPosY
+ calcPointsYValue(pSourceWin, nSourceEntry, m_aSourceConnPos,m_aSourceDescrLinePos);
+
+ // determine aDestConnPosY
+ calcPointsYValue(pDestWin, nDestEntry, m_aDestConnPos,m_aDestDescrLinePos);
+
+ return true;
+}
+
+void OConnectionLine::Draw( OutputDevice* pOutDev )
+{
+ const sal_uInt16 nRectSize = 3;
+
+ // calculate new dimension
+ if( !RecalcLine() )
+ return;
+
+ // draw lines
+ if (m_pTabConn->IsSelected())
+ pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetHighlightColor());
+ else
+ pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor());
+
+ LineInfo aLineInfo;
+ if ( m_pTabConn->IsSelected() )
+ aLineInfo.SetWidth(3);
+ tools::Polygon aPoly;
+ aPoly.Insert(0,m_aSourceDescrLinePos);
+ aPoly.Insert(1,m_aSourceConnPos);
+ aPoly.Insert(2,m_aDestConnPos);
+ aPoly.Insert(3,m_aDestDescrLinePos);
+ pOutDev->DrawPolyLine(aPoly,aLineInfo);
+
+ // draw the connection rectangles
+ pOutDev->SetFillColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
+
+ Point aVector(nRectSize,nRectSize);
+ pOutDev->DrawRect( calcRect(m_aSourceDescrLinePos,aVector) );
+ pOutDev->DrawRect( calcRect( m_aDestDescrLinePos,aVector) );
+}
+
+bool OConnectionLine::IsValid() const
+{
+ return m_pData.is();
+}
+
+static double dist_Euklid(const Point &p1, const Point& p2,const Point& pM, Point& q)
+{
+ Point v(p2 - p1);
+ Point w(pM - p1);
+ double a = std::hypot(v.X(), v.Y());
+ double l = (v.X() * w.Y() - v.Y() * w.X()) / a;
+ double a2 = w.X()*v.X()+w.Y()*v.Y();
+ a = a2 / (a * a);
+ q.setX( tools::Long(p1.X() + a * v.X()) );
+ q.setY( tools::Long(p1.Y() + a * v.Y()) );
+ return l;
+}
+
+bool OConnectionLine::CheckHit( const Point& rMousePos ) const
+{
+ /*
+ course of action with HitTest:
+ the distance is calculated according to Euklid.
+ */
+ Point q;
+ double l = fabs(dist_Euklid(m_aSourceConnPos,m_aDestConnPos,rMousePos,q));
+ if( l < HIT_SENSITIVE_RADIUS)
+ {
+ if(std::min(m_aSourceConnPos.X(),m_aDestConnPos.X()) <= q.X() && std::min(m_aSourceConnPos.Y(),m_aDestConnPos.Y()) <= q.Y()
+ && q.X() <= std::max(m_aDestConnPos.X(),m_aSourceConnPos.X()) && q.Y() <= std::max(m_aDestConnPos.Y(),m_aSourceConnPos.Y()))
+ return true;
+ }
+
+ return false;
+}
+
+tools::Rectangle OConnectionLine::GetSourceTextPos() const
+{
+ return GetTextPos(m_pTabConn->GetSourceWin(),m_aSourceConnPos,m_aSourceDescrLinePos);
+}
+
+tools::Rectangle OConnectionLine::GetDestTextPos() const
+{
+ return GetTextPos(m_pTabConn->GetDestWin(),m_aDestConnPos,m_aDestDescrLinePos);
+}
+
+Point OConnectionLine::getMidPoint() const
+{
+ Point aDest = m_aDestConnPos - m_aSourceConnPos;
+ aDest.setX( aDest.X() / 2 );
+ aDest.setY( aDest.Y() / 2 );
+
+ return m_aSourceConnPos + aDest;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx b/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx
new file mode 100644
index 000000000..f11ca853c
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ConnectionLineAccess.hxx>
+#include <ConnectionLine.hxx>
+#include <JoinTableView.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <TableConnection.hxx>
+#include <TableWindow.hxx>
+#include <comphelper/sequence.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::accessibility;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star;
+
+ OConnectionLineAccess::OConnectionLineAccess(OTableConnection* _pLine)
+ : VCLXAccessibleComponent(_pLine->GetComponentInterface().is() ? _pLine->GetWindowPeer() : nullptr)
+ ,m_pLine(_pLine)
+ {
+ }
+ void SAL_CALL OConnectionLineAccess::disposing()
+ {
+ m_pLine = nullptr;
+ VCLXAccessibleComponent::disposing();
+ }
+ Any SAL_CALL OConnectionLineAccess::queryInterface( const Type& aType )
+ {
+ Any aRet(VCLXAccessibleComponent::queryInterface( aType ));
+ return aRet.hasValue() ? aRet : OConnectionLineAccess_BASE::queryInterface( aType );
+ }
+ Sequence< Type > SAL_CALL OConnectionLineAccess::getTypes( )
+ {
+ return ::comphelper::concatSequences(VCLXAccessibleComponent::getTypes(),OConnectionLineAccess_BASE::getTypes());
+ }
+ OUString SAL_CALL OConnectionLineAccess::getImplementationName()
+ {
+ return "org.openoffice.comp.dbu.ConnectionLineAccessibility";
+ }
+ // XAccessibleContext
+ sal_Int32 SAL_CALL OConnectionLineAccess::getAccessibleChildCount( )
+ {
+ return 0;
+ }
+ Reference< XAccessible > SAL_CALL OConnectionLineAccess::getAccessibleChild( sal_Int32 /*i*/ )
+ {
+ return Reference< XAccessible >();
+ }
+ sal_Int32 SAL_CALL OConnectionLineAccess::getAccessibleIndexInParent( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ sal_Int32 nIndex = -1;
+ if( m_pLine )
+ {
+ // search the position of our table window in the table window map
+ // TODO JNA Shouldn't nIndex begin at 0?
+ nIndex = m_pLine->GetParent()->GetTabWinMap().size();
+ const auto& rVec = m_pLine->GetParent()->getTableConnections();
+ bool bFound = false;
+ for (auto const& elem : rVec)
+ {
+ if (elem.get() == m_pLine)
+ {
+ bFound = true;
+ break;
+ }
+ ++nIndex;
+ }
+ nIndex = bFound ? nIndex : -1;
+ }
+ return nIndex;
+ }
+ sal_Int16 SAL_CALL OConnectionLineAccess::getAccessibleRole( )
+ {
+ return AccessibleRole::UNKNOWN; // ? or may be an AccessibleRole::WINDOW
+ }
+ OUString SAL_CALL OConnectionLineAccess::getAccessibleDescription( )
+ {
+ return "Relation";
+ }
+ Reference< XAccessibleRelationSet > SAL_CALL OConnectionLineAccess::getAccessibleRelationSet( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return this;
+ }
+ // XAccessibleComponent
+ Reference< XAccessible > SAL_CALL OConnectionLineAccess::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ )
+ {
+ return Reference< XAccessible >();
+ }
+ awt::Rectangle SAL_CALL OConnectionLineAccess::getBounds( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ tools::Rectangle aRect(m_pLine ? m_pLine->GetBoundingRect() : tools::Rectangle());
+ return awt::Rectangle(aRect.Left(),aRect.Top(),aRect.getWidth(),aRect.getHeight());
+ }
+ awt::Point SAL_CALL OConnectionLineAccess::getLocation( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Point aPoint(m_pLine ? m_pLine->GetBoundingRect().TopLeft() : Point());
+ return awt::Point(aPoint.X(),aPoint.Y());
+ }
+ awt::Point SAL_CALL OConnectionLineAccess::getLocationOnScreen( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Point aPoint(m_pLine ? m_pLine->GetParent()->ScreenToOutputPixel(m_pLine->GetBoundingRect().TopLeft()) : Point());
+ return awt::Point(aPoint.X(),aPoint.Y());
+ }
+ awt::Size SAL_CALL OConnectionLineAccess::getSize( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Size aSize(m_pLine ? m_pLine->GetBoundingRect().GetSize() : Size());
+ return awt::Size(aSize.Width(),aSize.Height());
+ }
+ // XAccessibleRelationSet
+ sal_Int32 SAL_CALL OConnectionLineAccess::getRelationCount( )
+ {
+ return 1;
+ }
+ AccessibleRelation SAL_CALL OConnectionLineAccess::getRelation( sal_Int32 nIndex )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( nIndex < 0 || nIndex >= getRelationCount() )
+ throw IndexOutOfBoundsException();
+
+ Sequence< Reference<XInterface> > aSeq;
+ if( m_pLine )
+ {
+ aSeq = { m_pLine->GetSourceWin()->GetAccessible(),
+ m_pLine->GetDestWin()->GetAccessible() };
+ }
+
+ return AccessibleRelation(AccessibleRelationType::CONTROLLED_BY,aSeq);
+ }
+ sal_Bool SAL_CALL OConnectionLineAccess::containsRelation( sal_Int16 aRelationType )
+ {
+ return AccessibleRelationType::CONTROLLED_BY == aRelationType;
+ }
+ AccessibleRelation SAL_CALL OConnectionLineAccess::getRelationByType( sal_Int16 aRelationType )
+ {
+ if( AccessibleRelationType::CONTROLLED_BY == aRelationType )
+ return getRelation(0);
+ return AccessibleRelation();
+ }
+ Reference< XAccessible > OTableConnection::CreateAccessible()
+ {
+ return new OConnectionLineAccess(this);
+ }
+ OTableConnection::~OTableConnection()
+ {
+ disposeOnce();
+ }
+ void OTableConnection::dispose()
+ {
+ // clear vector
+ clearLineData();
+ m_pParent.clear();
+ vcl::Window::dispose();
+ }
+ Reference< XAccessibleContext > SAL_CALL OConnectionLineAccess::getAccessibleContext( )
+ {
+ return this;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/ConnectionLineData.cxx b/dbaccess/source/ui/querydesign/ConnectionLineData.cxx
new file mode 100644
index 000000000..db7177294
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/ConnectionLineData.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ConnectionLineData.hxx>
+
+using namespace dbaui;
+OConnectionLineData::OConnectionLineData()
+{
+}
+
+OConnectionLineData::OConnectionLineData( const OUString& rSourceFieldName, const OUString& rDestFieldName )
+ :m_aSourceFieldName( rSourceFieldName )
+ ,m_aDestFieldName( rDestFieldName )
+{
+}
+
+OConnectionLineData::OConnectionLineData( const OConnectionLineData& rConnLineData )
+ : ::salhelper::SimpleReferenceObject()
+{
+ *this = rConnLineData;
+}
+
+OConnectionLineData::~OConnectionLineData()
+{
+}
+
+void OConnectionLineData::CopyFrom(const OConnectionLineData& rSource)
+{
+ *this = rSource;
+ // Here I rely on the (non-virtual) operator=, which only copies my members
+}
+
+OConnectionLineData& OConnectionLineData::operator=( const OConnectionLineData& rConnLineData )
+{
+ if (&rConnLineData == this)
+ return *this;
+
+ m_aSourceFieldName = rConnLineData.GetSourceFieldName();
+ m_aDestFieldName = rConnLineData.GetDestFieldName();
+
+ return *this;
+}
+
+void OConnectionLineData::Reset()
+{
+ m_aDestFieldName.clear();
+ m_aSourceFieldName.clear();
+}
+
+namespace dbaui
+{
+bool operator==(const OConnectionLineData& lhs, const OConnectionLineData& rhs)
+{
+ return (lhs.m_aSourceFieldName == rhs.m_aSourceFieldName)
+ && (lhs.m_aDestFieldName == rhs.m_aDestFieldName);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/JAccess.cxx b/dbaccess/source/ui/querydesign/JAccess.cxx
new file mode 100644
index 000000000..8068f0fa7
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/JAccess.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <JAccess.hxx>
+#include <JoinTableView.hxx>
+#include <TableWindow.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <TableConnection.hxx>
+#include <o3tl/safeint.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::accessibility;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+
+ OJoinDesignViewAccess::OJoinDesignViewAccess(OJoinTableView* _pTableView)
+ :VCLXAccessibleComponent(_pTableView->GetComponentInterface().is() ? _pTableView->GetWindowPeer() : nullptr)
+ ,m_pTableView(_pTableView)
+ {
+ }
+ OUString SAL_CALL OJoinDesignViewAccess::getImplementationName()
+ {
+ return "org.openoffice.comp.dbu.JoinViewAccessibility";
+ }
+ void OJoinDesignViewAccess::clearTableView()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_pTableView = nullptr;
+ }
+ // XAccessibleContext
+ sal_Int32 SAL_CALL OJoinDesignViewAccess::getAccessibleChildCount( )
+ {
+ // TODO may be this will change to only visible windows
+ // this is the same assumption mt implements
+ ::osl::MutexGuard aGuard( m_aMutex );
+ sal_Int32 nChildCount = 0;
+ if ( m_pTableView )
+ nChildCount = m_pTableView->GetTabWinCount() + m_pTableView->getTableConnections().size();
+ return nChildCount;
+ }
+ Reference< XAccessible > SAL_CALL OJoinDesignViewAccess::getAccessibleChild( sal_Int32 i )
+ {
+ Reference< XAccessible > aRet;
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if(i < 0 || i >= getAccessibleChildCount() || !m_pTableView)
+ throw IndexOutOfBoundsException();
+ // check if we should return a table window or a connection
+ sal_Int32 nTableWindowCount = m_pTableView->GetTabWinCount();
+ if( i < nTableWindowCount )
+ {
+ OJoinTableView::OTableWindowMap::const_iterator aIter = std::next(m_pTableView->GetTabWinMap().begin(), i);
+ aRet = aIter->second->GetAccessible();
+ }
+ else if( o3tl::make_unsigned(i - nTableWindowCount) < m_pTableView->getTableConnections().size() )
+ aRet = m_pTableView->getTableConnections()[i - nTableWindowCount]->GetAccessible();
+ return aRet;
+ }
+ sal_Int16 SAL_CALL OJoinDesignViewAccess::getAccessibleRole( )
+ {
+ return AccessibleRole::VIEW_PORT;
+ }
+ Reference< XAccessibleContext > SAL_CALL OJoinDesignViewAccess::getAccessibleContext( )
+ {
+ return this;
+ }
+ // XInterface
+ IMPLEMENT_FORWARD_XINTERFACE2( OJoinDesignViewAccess, VCLXAccessibleComponent, OJoinDesignViewAccess_BASE )
+ // XTypeProvider
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( OJoinDesignViewAccess, VCLXAccessibleComponent, OJoinDesignViewAccess_BASE )
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/JoinController.cxx b/dbaccess/source/ui/querydesign/JoinController.cxx
new file mode 100644
index 000000000..0857e0448
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/JoinController.cxx
@@ -0,0 +1,406 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <browserids.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <JoinController.hxx>
+#include <TableWindowData.hxx>
+#include <TableWindow.hxx>
+#include <TableConnectionData.hxx>
+#include <adtabdlg.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::dbtools;
+using namespace ::comphelper;
+
+namespace dbaui
+{
+
+// AddTableDialogContext
+class AddTableDialogContext : public IAddTableDialogContext
+{
+ OJoinController& m_rController;
+
+public:
+ explicit AddTableDialogContext( OJoinController& _rController )
+ :m_rController( _rController )
+ {
+ }
+
+ virtual ~AddTableDialogContext() {}
+
+ // IAddTableDialogContext
+ virtual css::uno::Reference< css::sdbc::XConnection >
+ getConnection() const override;
+ virtual bool allowViews() const override;
+ virtual bool allowQueries() const override;
+ virtual bool allowAddition() const override;
+ virtual void addTableWindow( const OUString& _rQualifiedTableName, const OUString& _rAliasName ) override;
+ virtual void onWindowClosing() override;
+
+private:
+ OJoinTableView* getTableView() const;
+};
+
+Reference< XConnection > AddTableDialogContext::getConnection() const
+{
+ return m_rController.getConnection();
+}
+
+bool AddTableDialogContext::allowViews() const
+{
+ return m_rController.allowViews();
+}
+
+bool AddTableDialogContext::allowQueries() const
+{
+ return m_rController.allowQueries();
+}
+
+bool AddTableDialogContext::allowAddition() const
+{
+ return m_rController.getJoinView()->getTableView()->IsAddAllowed();
+}
+
+void AddTableDialogContext::addTableWindow( const OUString& _rQualifiedTableName, const OUString& _rAliasName )
+{
+ getTableView()->AddTabWin( _rQualifiedTableName, _rAliasName, true );
+}
+
+void AddTableDialogContext::onWindowClosing()
+{
+ if (!m_rController.getView())
+ return;
+ m_rController.InvalidateFeature( ID_BROWSER_ADDTABLE );
+ m_rController.getView()->GrabFocus();
+}
+
+OJoinTableView* AddTableDialogContext::getTableView() const
+{
+ if ( m_rController.getJoinView() )
+ return m_rController.getJoinView()->getTableView();
+ return nullptr;
+}
+
+// OJoinController
+
+OJoinController::OJoinController(const Reference< XComponentContext >& _rM)
+ : OJoinController_BASE(_rM)
+{
+}
+
+OJoinController::~OJoinController()
+{
+}
+
+OJoinDesignView* OJoinController::getJoinView()
+{
+ return static_cast< OJoinDesignView* >( getView() );
+}
+
+void OJoinController::disposing()
+{
+ if (m_xAddTableDialog)
+ {
+ m_xAddTableDialog->response(RET_CLOSE);
+ m_xAddTableDialog.reset();
+ }
+
+ OJoinController_BASE::disposing();
+
+ clearView();
+
+ m_vTableConnectionData.clear();
+ m_vTableData.clear();
+}
+
+void OJoinController::reconnect( bool _bUI )
+{
+ OJoinController_BASE::reconnect( _bUI );
+ if ( isConnected() && m_xAddTableDialog )
+ m_xAddTableDialog->Update();
+}
+
+void OJoinController::impl_onModifyChanged()
+{
+ OJoinController_BASE::impl_onModifyChanged();
+ InvalidateFeature( SID_RELATION_ADD_RELATION );
+}
+
+void OJoinController::SaveTabWinPosSize(OTableWindow const * pTabWin, tools::Long nOffsetX, tools::Long nOffsetY)
+{
+ // the data for the window
+ const TTableWindowData::value_type& pData = pTabWin->GetData();
+ OSL_ENSURE(pData != nullptr, "SaveTabWinPosSize : TabWin has no data !");
+
+ // set Position & Size of data anew (with current window parameters)
+ Point aPos = pTabWin->GetPosPixel();
+ aPos.AdjustX(nOffsetX );
+ aPos.AdjustY(nOffsetY );
+ pData->SetPosition(aPos);
+ pData->SetSize(pTabWin->GetSizePixel());
+
+}
+
+FeatureState OJoinController::GetState(sal_uInt16 _nId) const
+{
+ FeatureState aReturn;
+ // (disabled automatically)
+ aReturn.bEnabled = true;
+
+ switch (_nId)
+ {
+ case ID_BROWSER_EDITDOC:
+ aReturn.bChecked = isEditable();
+ break;
+ case ID_BROWSER_ADDTABLE:
+ aReturn.bEnabled = ( getView() != nullptr )
+ && const_cast< OJoinController* >( this )->getJoinView()->getTableView()->IsAddAllowed();
+ aReturn.bChecked = aReturn.bEnabled && m_xAddTableDialog;
+ if ( aReturn.bEnabled )
+ aReturn.sTitle = OAddTableDlg::getDialogTitleForContext( impl_getDialogContext() );
+ break;
+
+ default:
+ aReturn = OJoinController_BASE::GetState(_nId);
+ }
+ return aReturn;
+}
+
+AddTableDialogContext& OJoinController::impl_getDialogContext() const
+{
+ if (!m_pDialogContext)
+ {
+ OJoinController* pNonConstThis = const_cast< OJoinController* >( this );
+ pNonConstThis->m_pDialogContext.reset( new AddTableDialogContext( *pNonConstThis ) );
+ }
+ assert(m_pDialogContext && "always exists at this point");
+ return *m_pDialogContext;
+}
+
+void OJoinController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
+{
+ switch(_nId)
+ {
+ case ID_BROWSER_EDITDOC:
+ if(isEditable())
+ { // the state should be changed to not editable
+ switch (saveModified())
+ {
+ case RET_CANCEL:
+ // don't change anything here so return
+ return;
+ case RET_NO:
+ reset();
+ setModified(false); // and we are not modified yet
+ break;
+ default:
+ break;
+ }
+ }
+ setEditable(!isEditable());
+ getJoinView()->setReadOnly(!isEditable());
+ InvalidateAll();
+ return;
+ case ID_BROWSER_ADDTABLE:
+ if (m_xAddTableDialog)
+ {
+ m_xAddTableDialog->response(RET_CLOSE);
+ getView()->GrabFocus();
+ }
+ else
+ {
+ runDialogAsync();
+ }
+ break;
+ default:
+ OJoinController_BASE::Execute(_nId,aArgs);
+ }
+ InvalidateFeature(_nId);
+}
+
+void OJoinController::runDialogAsync()
+{
+ assert(!m_xAddTableDialog);
+ m_xAddTableDialog = std::make_shared<OAddTableDlg>(getFrameWeld(), impl_getDialogContext());
+ {
+ weld::WaitObject aWaitCursor(getFrameWeld());
+ m_xAddTableDialog->Update();
+ }
+ weld::DialogController::runAsync(m_xAddTableDialog, [this](sal_Int32 /*nResult*/){
+ m_xAddTableDialog->OnClose();
+ m_xAddTableDialog.reset();
+ });
+}
+
+void OJoinController::SaveTabWinsPosSize( OJoinTableView::OTableWindowMap* pTabWinList, tools::Long nOffsetX, tools::Long nOffsetY )
+{
+ // Deletion and recreation of the old implementation with the current model is not correct anymore:
+ // The TabWins have a pointer to their data, but they are managed by me. When I delete the old ones, the TabWins suddenly have a pointer to objects, which no longer exist.
+ // If the TabWins had a SetData, I could save that effort... but they don't, further I also would still have to set information anew, which actually didn't change.
+ // So I don't delete the TabWinDatas, but only update them.
+ OSL_ENSURE(m_vTableData.size() == pTabWinList->size(),
+ "OJoinController::SaveTabWinsPosSize : inconsistent state : should have as many TabWinDatas as TabWins !");
+
+ for (auto const& tabWin : *pTabWinList)
+ SaveTabWinPosSize(tabWin.second, nOffsetX, nOffsetY);
+}
+
+void OJoinController::removeConnectionData(const TTableConnectionData::value_type& _pData)
+{
+ m_vTableConnectionData.erase( std::remove(m_vTableConnectionData.begin(),m_vTableConnectionData.end(),_pData),m_vTableConnectionData.end());
+}
+
+void OJoinController::describeSupportedFeatures()
+{
+ OJoinController_BASE::describeSupportedFeatures();
+ implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:AddTable", ID_BROWSER_ADDTABLE,CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:GetUndoStrings", SID_GETUNDOSTRINGS );
+ implDescribeSupportedFeature( ".uno:GetRedoStrings", SID_GETREDOSTRINGS );
+}
+
+sal_Bool SAL_CALL OJoinController::suspend(sal_Bool _bSuspend)
+{
+ if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed )
+ return true;
+
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( getView() && getView()->IsInModalMode() )
+ return false;
+ bool bCheck = true;
+ if ( _bSuspend )
+ {
+ bCheck = saveModified() != RET_CANCEL;
+ if ( bCheck )
+ OSingleDocumentController::suspend(_bSuspend);
+ }
+ return bCheck;
+}
+
+void OJoinController::loadTableWindows( const ::comphelper::NamedValueCollection& i_rViewSettings )
+{
+ m_vTableData.clear();
+
+ m_aMinimumTableViewSize = Point();
+
+ Sequence< PropertyValue > aWindowData;
+ aWindowData = i_rViewSettings.getOrDefault( "Tables", aWindowData );
+
+ const PropertyValue* pTablesIter = aWindowData.getConstArray();
+ const PropertyValue* pTablesEnd = pTablesIter + aWindowData.getLength();
+ for ( ; pTablesIter != pTablesEnd; ++pTablesIter )
+ {
+ ::comphelper::NamedValueCollection aSingleTableData( pTablesIter->Value );
+ loadTableWindow( aSingleTableData );
+ }
+ if ( m_aMinimumTableViewSize != Point() )
+ {
+ getJoinView()->getScrollHelper()->resetRange( m_aMinimumTableViewSize );
+ }
+}
+
+void OJoinController::loadTableWindow( const ::comphelper::NamedValueCollection& i_rTableWindowSettings )
+{
+ sal_Int32 nX = -1, nY = -1, nHeight = -1, nWidth = -1;
+
+ OUString sComposedName,sTableName,sWindowName;
+ bool bShowAll = false;
+
+ sComposedName = i_rTableWindowSettings.getOrDefault( "ComposedName", sComposedName );
+ sTableName = i_rTableWindowSettings.getOrDefault( "TableName", sTableName );
+ sWindowName = i_rTableWindowSettings.getOrDefault( "WindowName", sWindowName );
+ nY = i_rTableWindowSettings.getOrDefault( "WindowTop", nY );
+ nX = i_rTableWindowSettings.getOrDefault( "WindowLeft", nX );
+ nWidth = i_rTableWindowSettings.getOrDefault( "WindowWidth", nWidth );
+ nHeight = i_rTableWindowSettings.getOrDefault( "WindowHeight", nHeight );
+ bShowAll = i_rTableWindowSettings.getOrDefault( "ShowAll", bShowAll );
+
+ TTableWindowData::value_type pData = createTableWindowData(sComposedName,sTableName,sWindowName);
+ if ( pData )
+ {
+ pData->SetPosition(Point(nX,nY));
+ pData->SetSize( Size( nWidth, nHeight ) );
+ pData->ShowAll(bShowAll);
+ m_vTableData.push_back(pData);
+ if ( m_aMinimumTableViewSize.X() < (nX+nWidth) )
+ m_aMinimumTableViewSize.setX( nX+nWidth );
+ if ( m_aMinimumTableViewSize.Y() < (nY+nHeight) )
+ m_aMinimumTableViewSize.setY( nY+nHeight );
+ }
+}
+
+void OJoinController::saveTableWindows( ::comphelper::NamedValueCollection& o_rViewSettings ) const
+{
+ if ( m_vTableData.empty() )
+ return;
+
+ ::comphelper::NamedValueCollection aAllTablesData;
+
+ sal_Int32 i = 1;
+ for (auto const& elem : m_vTableData)
+ {
+ ::comphelper::NamedValueCollection aWindowData;
+ aWindowData.put( "ComposedName", elem->GetComposedName() );
+ aWindowData.put( "TableName", elem->GetTableName() );
+ aWindowData.put( "WindowName", elem->GetWinName() );
+ aWindowData.put( "WindowTop", static_cast<sal_Int32>(elem->GetPosition().Y()) );
+ aWindowData.put( "WindowLeft", static_cast<sal_Int32>(elem->GetPosition().X()) );
+ aWindowData.put( "WindowWidth", static_cast<sal_Int32>(elem->GetSize().Width()) );
+ aWindowData.put( "WindowHeight", static_cast<sal_Int32>(elem->GetSize().Height()) );
+ aWindowData.put( "ShowAll", elem->IsShowAll() );
+
+ const OUString sTableName( "Table" + OUString::number( i++ ) );
+ aAllTablesData.put( sTableName, aWindowData.getPropertyValues() );
+ }
+
+ o_rViewSettings.put( "Tables", aAllTablesData.getPropertyValues() );
+}
+
+TTableWindowData::value_type OJoinController::createTableWindowData(const OUString& _sComposedName,const OUString& _sTableName,const OUString& _sWindowName)
+{
+ OJoinDesignView* pView = getJoinView();
+ if( pView )
+ return pView->getTableView()->createTableWindowData(_sComposedName,_sTableName,_sWindowName);
+ OSL_FAIL("We should never ever reach this point!");
+
+ return TTableWindowData::value_type();
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/JoinDesignView.cxx b/dbaccess/source/ui/querydesign/JoinDesignView.cxx
new file mode 100644
index 000000000..c0d3ea81c
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/JoinDesignView.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <JoinDesignView.hxx>
+#include <JoinTableView.hxx>
+#include <JoinController.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+
+namespace dbaui
+{
+
+// OJoinDesignView
+OJoinDesignView::OJoinDesignView(vcl::Window* _pParent, OJoinController& _rController,const Reference< XComponentContext >& _rxContext)
+ :ODataView( _pParent, _rController, _rxContext )
+ ,m_pTableView(nullptr)
+ ,m_rController( _rController )
+{
+ m_pScrollWindow = VclPtr<OScrollWindowHelper>::Create(this);
+}
+
+OJoinDesignView::~OJoinDesignView()
+{
+ disposeOnce();
+}
+
+void OJoinDesignView::dispose()
+{
+ m_pTableView.disposeAndClear();
+ m_pScrollWindow.disposeAndClear();
+ ODataView::dispose();
+}
+
+void OJoinDesignView::Construct()
+{
+ m_pScrollWindow->setTableView(m_pTableView);
+ m_pScrollWindow->Show();
+ m_pTableView->Show();
+
+ SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetFaceColor()) );
+
+ ODataView::Construct();
+}
+
+void OJoinDesignView::initialize()
+{
+}
+
+void OJoinDesignView::resizeDocumentView(tools::Rectangle& _rPlayground)
+{
+ m_pScrollWindow->SetPosSizePixel( _rPlayground.TopLeft(), _rPlayground.GetSize() );
+
+ // just for completeness: there is no space left, we occupied it all ...
+ _rPlayground.SetPos( _rPlayground.BottomRight() );
+ _rPlayground.SetSize( Size( 0, 0 ) );
+}
+
+void OJoinDesignView::setReadOnly(bool /*_bReadOnly*/)
+{
+}
+
+void OJoinDesignView::SaveTabWinUIConfig(OTableWindow const * pWin)
+{
+ OJoinController::SaveTabWinPosSize(pWin, m_pScrollWindow->GetHScrollBar().GetThumbPos(), m_pScrollWindow->GetVScrollBar().GetThumbPos());
+}
+
+void OJoinDesignView::KeyInput( const KeyEvent& rEvt )
+{
+ if ( m_pTableView && m_pTableView->IsVisible() )
+ m_pTableView->KeyInput( rEvt );
+ else
+ ODataView::KeyInput(rEvt);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/JoinExchange.cxx b/dbaccess/source/ui/querydesign/JoinExchange.cxx
new file mode 100644
index 000000000..0dc88e2cc
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/JoinExchange.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <JoinExchange.hxx>
+#include <sot/formats.hxx>
+#include <comphelper/servicehelper.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::datatransfer;
+
+ void OJoinExchObj::setDescriptors(const OJoinExchangeData& jxdSource,bool _bFirstEntry)
+ {
+ m_bFirstEntry = _bFirstEntry;
+ m_jxdSourceDescription = jxdSource;
+ }
+
+ OJoinExchObj::OJoinExchObj()
+ : m_bFirstEntry(false)
+ {
+ }
+
+ OJoinExchObj::~OJoinExchObj()
+ {
+ }
+
+ bool OJoinExchObj::isFormatAvailable( const DataFlavorExVector& _rFormats ,SotClipboardFormatId _nSlotID)
+ {
+ for (auto const& format : _rFormats)
+ {
+ if ( _nSlotID == format.mnSotId )
+ return true;
+ }
+ return false;
+ }
+
+ OJoinExchangeData OJoinExchObj::GetSourceDescription(const Reference< XTransferable >& _rxObject)
+ {
+ OJoinExchangeData aReturn;
+ auto pImplementation = comphelper::getFromUnoTunnel<OJoinExchObj>(_rxObject);
+ if (pImplementation)
+ aReturn = pImplementation->m_jxdSourceDescription;
+ return aReturn;
+ }
+
+ const Sequence< sal_Int8 > & OJoinExchObj::getUnoTunnelId()
+ {
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+ }
+
+ sal_Int64 SAL_CALL OJoinExchObj::getSomething( const Sequence< sal_Int8 >& _rIdentifier )
+ {
+ return comphelper::getSomethingImpl(_rIdentifier, this);
+ }
+
+ void OJoinExchObj::AddSupportedFormats()
+ {
+ AddFormat( SotClipboardFormatId::SBA_JOIN );
+ if ( m_bFirstEntry )
+ AddFormat( SotClipboardFormatId::SBA_TABID );
+ }
+
+ bool OJoinExchObj::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor);
+ if ( SotClipboardFormatId::SBA_JOIN == nFormat )
+ // this is a HACK
+ // we don't really copy our data, the instances using us have to call GetSourceDescription...
+ // if, one day, we have a _lot_ of time, this hack should be removed...
+ return true;
+
+ return false;
+ }
+
+ Any SAL_CALL OJoinExchObj::queryInterface( const Type& _rType )
+ {
+ Any aReturn = TransferDataContainer::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = OJoinExchObj_Base::queryInterface(_rType);
+ return aReturn;
+ }
+
+ void SAL_CALL OJoinExchObj::acquire( ) noexcept
+ {
+ TransferDataContainer::acquire( );
+ }
+
+ void SAL_CALL OJoinExchObj::release( ) noexcept
+ {
+ TransferDataContainer::release( );
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/JoinTableView.cxx b/dbaccess/source/ui/querydesign/JoinTableView.cxx
new file mode 100644
index 000000000..055628133
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/JoinTableView.cxx
@@ -0,0 +1,1568 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <JoinTableView.hxx>
+#include <osl/diagnose.h>
+#include <JoinController.hxx>
+#include <JoinDesignView.hxx>
+#include <TableWindow.hxx>
+#include <TableWindowListBox.hxx>
+#include <TableConnection.hxx>
+#include <TableConnectionData.hxx>
+#include <ConnectionLine.hxx>
+#include <ConnectionLineData.hxx>
+#include <browserids.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include "QueryMoveTabWinUndoAct.hxx"
+#include "QuerySizeTabWinUndoAct.hxx"
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/weldutils.hxx>
+#include <TableWindowData.hxx>
+#include <JAccess.hxx>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <connectivity/dbtools.hxx>
+#include <tools/diagnose_ex.h>
+#include <algorithm>
+#include <functional>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+#define LINE_SIZE 50
+// Constants for the window layout
+#define TABWIN_SPACING_X 17
+#define TABWIN_SPACING_Y 17
+
+#define TABWIN_WIDTH_STD 120
+#define TABWIN_HEIGHT_STD 120
+
+OScrollWindowHelper::OScrollWindowHelper( vcl::Window* pParent) : Window( pParent)
+ ,m_aHScrollBar( VclPtr<ScrollBar>::Create(this, WB_HSCROLL|WB_REPEAT|WB_DRAG) )
+ ,m_aVScrollBar( VclPtr<ScrollBar>::Create(this, WB_VSCROLL|WB_REPEAT|WB_DRAG) )
+ ,m_pCornerWindow(VclPtr<ScrollBarBox>::Create(this, WB_3DLOOK))
+ ,m_pTableView(nullptr)
+{
+
+ // ScrollBars
+
+ GetHScrollBar().SetRange( Range(0, 1000) );
+ GetVScrollBar().SetRange( Range(0, 1000) );
+
+ GetHScrollBar().SetLineSize( LINE_SIZE );
+ GetVScrollBar().SetLineSize( LINE_SIZE );
+
+ GetHScrollBar().Show();
+ GetVScrollBar().Show();
+ m_pCornerWindow->Show();
+
+ // normally we should be SCROLL_PANE
+ SetAccessibleRole(AccessibleRole::SCROLL_PANE);
+}
+
+OScrollWindowHelper::~OScrollWindowHelper()
+{
+ disposeOnce();
+}
+
+void OScrollWindowHelper::dispose()
+{
+ m_aHScrollBar.disposeAndClear();
+ m_aVScrollBar.disposeAndClear();
+ m_pCornerWindow.disposeAndClear();
+ m_pTableView.clear();
+ vcl::Window::dispose();
+}
+
+void OScrollWindowHelper::setTableView(OJoinTableView* _pTableView)
+{
+ m_pTableView = _pTableView;
+ // ScrollBars
+ GetHScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, ScrollHdl) );
+ GetVScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, ScrollHdl) );
+}
+
+void OScrollWindowHelper::resetRange(const Point& _aSize)
+{
+ Point aPos = PixelToLogic(_aSize);
+ GetHScrollBar().SetRange( Range(0, aPos.X() + TABWIN_SPACING_X) );
+ GetVScrollBar().SetRange( Range(0, aPos.Y() + TABWIN_SPACING_Y) );
+}
+
+void OScrollWindowHelper::Resize()
+{
+ Window::Resize();
+
+ Size aTotalOutputSize = GetOutputSizePixel();
+ tools::Long nHScrollHeight = GetHScrollBar().GetSizePixel().Height();
+ tools::Long nVScrollWidth = GetVScrollBar().GetSizePixel().Width();
+
+ GetHScrollBar().SetPosSizePixel(
+ Point( 0, aTotalOutputSize.Height()-nHScrollHeight ),
+ Size( aTotalOutputSize.Width()-nVScrollWidth, nHScrollHeight )
+ );
+
+ GetVScrollBar().SetPosSizePixel(
+ Point( aTotalOutputSize.Width()-nVScrollWidth, 0 ),
+ Size( nVScrollWidth, aTotalOutputSize.Height()-nHScrollHeight )
+ );
+
+ m_pCornerWindow->SetPosSizePixel(
+ Point( aTotalOutputSize.Width() - nVScrollWidth, aTotalOutputSize.Height() - nHScrollHeight),
+ Size( nVScrollWidth, nHScrollHeight )
+ );
+
+ GetHScrollBar().SetPageSize( aTotalOutputSize.Width() );
+ GetHScrollBar().SetVisibleSize( aTotalOutputSize.Width() );
+
+ GetVScrollBar().SetPageSize( aTotalOutputSize.Height() );
+ GetVScrollBar().SetVisibleSize( aTotalOutputSize.Height() );
+
+ // adjust the ranges of the scrollbars if necessary
+ tools::Long lRange = GetHScrollBar().GetRange().Max() - GetHScrollBar().GetRange().Min();
+ if (m_pTableView->GetScrollOffset().X() + aTotalOutputSize.Width() > lRange)
+ GetHScrollBar().SetRangeMax(m_pTableView->GetScrollOffset().X() + aTotalOutputSize.Width() + GetHScrollBar().GetRange().Min());
+
+ lRange = GetVScrollBar().GetRange().Max() - GetVScrollBar().GetRange().Min();
+ if (m_pTableView->GetScrollOffset().Y() + aTotalOutputSize.Height() > lRange)
+ GetVScrollBar().SetRangeMax(m_pTableView->GetScrollOffset().Y() + aTotalOutputSize.Height() + GetVScrollBar().GetRange().Min());
+
+ m_pTableView->SetPosSizePixel(Point( 0, 0 ),Size( aTotalOutputSize.Width()-nVScrollWidth, aTotalOutputSize.Height()-nHScrollHeight ));
+}
+
+
+OJoinTableView::OJoinTableView( vcl::Window* pParent, OJoinDesignView* pView )
+ :Window( pParent,WB_BORDER )
+ ,DropTargetHelper(this)
+ ,m_aDragScrollIdle("dbaccess OJoinTableView m_aDragScrollIdle")
+ ,m_aDragOffset( Point(0,0) )
+ ,m_aScrollOffset( Point(0,0) )
+ ,m_pDragWin( nullptr )
+ ,m_pSizingWin( nullptr )
+ ,m_pSelectedConn( nullptr )
+ ,m_pLastFocusTabWin(nullptr)
+ ,m_pView( pView )
+{
+ SetSizePixel( Size(1000, 1000) );
+
+ InitColors();
+
+ m_aDragScrollIdle.SetInvokeHandler(LINK(this, OJoinTableView, OnDragScrollTimer));
+}
+
+OJoinTableView::~OJoinTableView()
+{
+ disposeOnce();
+}
+
+void OJoinTableView::dispose()
+{
+ if( m_pAccessible )
+ {
+ m_pAccessible->clearTableView();
+ m_pAccessible = nullptr;
+ }
+ // delete lists
+ clearLayoutInformation();
+ m_pDragWin.clear();
+ m_pSizingWin.clear();
+ m_pSelectedConn.clear();
+ m_pLastFocusTabWin.clear();
+ m_pView.clear();
+ m_vTableConnection.clear();
+ vcl::Window::dispose();
+}
+
+IMPL_LINK( OJoinTableView, ScrollHdl, ScrollBar*, pScrollBar, void )
+{
+ // move all windows
+ ScrollPane( pScrollBar->GetDelta(), (pScrollBar == &GetHScrollBar()), false );
+}
+
+void OJoinTableView::Resize()
+{
+ Window::Resize();
+ m_aOutputSize = GetSizePixel();
+
+ // tab win positions may not be up-to-date
+ if (m_aTableMap.empty())
+ // no tab wins ...
+ return;
+
+ // we have at least one table so resize it
+ m_aScrollOffset.setX( GetHScrollBar().GetThumbPos() );
+ m_aScrollOffset.setY( GetVScrollBar().GetThumbPos() );
+
+ VclPtr<OTableWindow> pCheck = m_aTableMap.begin()->second;
+ Point aRealPos = pCheck->GetPosPixel();
+ Point aAssumedPos = pCheck->GetData()->GetPosition() - GetScrollOffset();
+
+ if (aRealPos == aAssumedPos)
+ // all ok
+ return;
+
+ for (auto const& elem : m_aTableMap)
+ {
+ OTableWindow* pCurrent = elem.second;
+ Point aPos(pCurrent->GetData()->GetPosition() - GetScrollOffset());
+ pCurrent->SetPosPixel(aPos);
+ }
+}
+
+sal_uLong OJoinTableView::GetTabWinCount() const
+{
+ return m_aTableMap.size();
+}
+
+bool OJoinTableView::RemoveConnection(VclPtr<OTableConnection>& rConn, bool _bDelete)
+{
+ VclPtr<OTableConnection> xConn(rConn);
+
+ DeselectConn(xConn);
+
+ // to force a redraw
+ xConn->InvalidateConnection();
+
+ m_pView->getController().removeConnectionData(xConn->GetData());
+
+ m_vTableConnection.erase(std::find(m_vTableConnection.begin(), m_vTableConnection.end(), xConn));
+
+ modified();
+ if ( m_pAccessible )
+ m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
+ Any(xConn->GetAccessible()),
+ Any());
+ if (_bDelete)
+ xConn->disposeOnce();
+
+ return true;
+}
+
+OTableWindow* OJoinTableView::GetTabWindow( const OUString& rName )
+{
+ OTableWindowMap::const_iterator aIter = m_aTableMap.find(rName);
+
+ return aIter == m_aTableMap.end() ? nullptr : aIter->second;
+}
+
+TTableWindowData::value_type OJoinTableView::createTableWindowData(const OUString& _rComposedName
+ ,const OUString& _sTableName
+ ,const OUString& _rWinName)
+{
+ TTableWindowData::value_type pData( CreateImpl(_rComposedName, _sTableName,_rWinName) );
+ OJoinDesignView* pParent = getDesignView();
+ try
+ {
+ if ( !pData->init(pParent->getController().getConnection(),allowQueries()) )
+ {
+ if ( pData->isValid() )
+ onNoColumns_throw();
+ else
+ pData.reset();
+ }
+ }
+ catch ( const SQLException& )
+ {
+ ::dbtools::showError( ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ),
+ VCLUnoHelper::GetInterface(pParent), pParent->getController().getORB() );
+ }
+ catch( const WrappedTargetException& e )
+ {
+ SQLException aSql;
+ if ( e.TargetException >>= aSql )
+ ::dbtools::showError( ::dbtools::SQLExceptionInfo( aSql ), VCLUnoHelper::GetInterface(pParent), pParent->getController().getORB() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return pData;
+}
+
+std::shared_ptr<OTableWindowData> OJoinTableView::CreateImpl(const OUString& _rComposedName
+ ,const OUString& _sTableName
+ ,const OUString& _rWinName)
+{
+ return std::make_shared<OTableWindowData>( nullptr,_rComposedName,_sTableName, _rWinName );
+}
+
+void OJoinTableView::AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool /*bNewTable*/)
+{
+ OSL_ENSURE(!_rComposedName.isEmpty(),"There must be a table name supplied!");
+
+ TTableWindowData::value_type pNewTabWinData(createTableWindowData( _rComposedName, rWinName,rWinName ));
+
+ // insert new window in window list
+ VclPtr<OTableWindow> pNewTabWin = createWindow( pNewTabWinData );
+ if ( pNewTabWin->Init() )
+ {
+ m_pView->getController().getTableWindowData().push_back( pNewTabWinData);
+ // when we already have a table with this name insert the full qualified one instead
+ if(m_aTableMap.find(rWinName) != m_aTableMap.end())
+ m_aTableMap[_rComposedName] = pNewTabWin;
+ else
+ m_aTableMap[rWinName] = pNewTabWin;
+
+ SetDefaultTabWinPosSize( pNewTabWin );
+ pNewTabWin->Show();
+
+ modified();
+ if ( m_pAccessible )
+ m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
+ Any(),
+ Any(pNewTabWin->GetAccessible()));
+ }
+ else
+ {
+ pNewTabWin->clearListBox();
+ pNewTabWin.disposeAndClear();
+ }
+}
+
+void OJoinTableView::RemoveTabWin( OTableWindow* pTabWin )
+{
+ // first delete all connections of this window to others
+ bool bRemove = true;
+ TTableWindowData::value_type pData = pTabWin->GetData();
+ sal_Int32 nCount = m_vTableConnection.size();
+ auto aIter = m_vTableConnection.rbegin();
+ while(aIter != m_vTableConnection.rend() && bRemove)
+ {
+ VclPtr<OTableConnection>& rTabConn = *aIter;
+ if (
+ (pData == rTabConn->GetData()->getReferencingTable()) ||
+ (pData == rTabConn->GetData()->getReferencedTable())
+ )
+ {
+ bRemove = RemoveConnection(rTabConn, true);
+ aIter = m_vTableConnection.rbegin();
+ }
+ else
+ ++aIter;
+ }
+
+ // then delete the window itself
+ if ( bRemove )
+ {
+ if ( m_pAccessible )
+ m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
+ Any(pTabWin->GetAccessible()),Any()
+ );
+
+ pTabWin->Hide();
+ OJoinController& rController = m_pView->getController();
+ TTableWindowData::iterator aFind = std::find(rController.getTableWindowData().begin(), rController.getTableWindowData().end(), pData);
+ if(aFind != rController.getTableWindowData().end())
+ {
+ rController.getTableWindowData().erase(aFind);
+ rController.setModified(true);
+ }
+
+ if ( !m_aTableMap.erase( pTabWin->GetWinName() ) )
+ m_aTableMap.erase( pTabWin->GetComposedName() );
+
+ if (pTabWin == m_pLastFocusTabWin)
+ m_pLastFocusTabWin = nullptr;
+
+ pTabWin->clearListBox();
+ pTabWin->disposeOnce();
+ }
+
+ if ( static_cast<sal_Int32>(m_vTableConnection.size()) < (nCount-1) ) // if some connections could be removed
+ modified();
+}
+
+namespace
+{
+ bool isScrollAllowed( OJoinTableView* _pView,tools::Long nDelta, bool bHoriz)
+ {
+ // adjust ScrollBar-Positions
+ ScrollBar& rBar = bHoriz ? _pView->GetHScrollBar() : _pView->GetVScrollBar() ;
+
+ tools::Long nOldThumbPos = rBar.GetThumbPos();
+ tools::Long nNewThumbPos = nOldThumbPos + nDelta;
+ if( nNewThumbPos < 0 )
+ nNewThumbPos = 0;
+ else if( nNewThumbPos > rBar.GetRangeMax() )
+ nNewThumbPos = rBar.GetRangeMax();
+
+ if ( bHoriz )
+ {
+ if( nNewThumbPos == _pView->GetScrollOffset().X() )
+ return false;
+ }
+ else if ( nNewThumbPos == _pView->GetScrollOffset().Y() )
+ return false;
+
+ return true;
+ }
+ bool getMovementImpl(OJoinTableView* _pView,const Point& _rPoint,const Size& _rSize,tools::Long& _nScrollX,tools::Long& _nScrollY)
+ {
+ _nScrollY = _nScrollX = 0;
+ // data about the tab win
+ Point aUpperLeft = _rPoint;
+ // normalize with respect to visibility
+ aUpperLeft -= _pView->GetScrollOffset();
+ Point aLowerRight(aUpperLeft.X() + _rSize.Width(), aUpperLeft.Y() + _rSize.Height());
+
+ // data about ourself
+ Size aSize = _pView->getRealOutputSize(); //GetOutputSizePixel();
+
+ bool bVisible = true;
+ bool bFitsHor = (aUpperLeft.X() >= 0) && (aLowerRight.X() <= aSize.Width());
+ bool bFitsVert= (aUpperLeft.Y() >= 0) && (aLowerRight.Y() <= aSize.Height());
+ if (!bFitsHor || !bFitsVert)
+ {
+ if (!bFitsHor)
+ {
+ // ensure the visibility of the right border
+ if ( aLowerRight.X() > aSize.Width() )
+ _nScrollX = aLowerRight.X() - aSize.Width() + TABWIN_SPACING_X;
+
+ // ensure the visibility of the left border (higher priority)
+ if ( aUpperLeft.X() < 0 )
+ _nScrollX = aUpperLeft.X() - TABWIN_SPACING_X;
+ }
+
+ if (!bFitsVert)
+ {
+ // lower border
+ if ( aLowerRight.Y() > aSize.Height() )
+ _nScrollY = aLowerRight.Y() - aSize.Height() + TABWIN_SPACING_Y;
+ // upper border
+ if ( aUpperLeft.Y() < 0 )
+ _nScrollY = aUpperLeft.Y() - TABWIN_SPACING_Y;
+ }
+
+ if ( _nScrollX ) // aSize.Width() > _rSize.Width() &&
+ bVisible = isScrollAllowed(_pView,_nScrollX, true);
+
+ if ( _nScrollY ) // aSize.Height() > _rSize.Height() &&
+ bVisible = bVisible && isScrollAllowed(_pView,_nScrollY, false);
+
+ if ( bVisible )
+ {
+ sal_Int32 nHRangeMax = _pView->GetHScrollBar().GetRangeMax();
+ sal_Int32 nVRangeMax = _pView->GetVScrollBar().GetRangeMax();
+
+ if ( aSize.Width() + _pView->GetHScrollBar().GetThumbPos() + _nScrollX > nHRangeMax )
+ bVisible = false;
+ if ( bVisible && aSize.Height() + _pView->GetVScrollBar().GetThumbPos() + _nScrollY > nVRangeMax )
+ bVisible = false;
+ }
+ }
+
+ return bVisible;
+ }
+} // end of ano namespace
+
+bool OJoinTableView::isMovementAllowed(const Point& _rPoint,const Size& _rSize)
+{
+ tools::Long nX,nY;
+ return getMovementImpl(this,_rPoint,_rSize,nX,nY);
+}
+
+void OJoinTableView::EnsureVisible(const OTableWindow* _pWin)
+{
+ // data about the tab win
+ TTableWindowData::value_type pData = _pWin->GetData();
+ EnsureVisible( pData->GetPosition() , pData->GetSize());
+ Invalidate(InvalidateFlags::NoChildren);
+}
+
+void OJoinTableView::EnsureVisible(const Point& _rPoint,const Size& _rSize)
+{
+ tools::Long nScrollX,nScrollY;
+
+ if ( getMovementImpl(this,_rPoint,_rSize,nScrollX,nScrollY) )
+ {
+ bool bVisible = true;
+ if (nScrollX)
+ bVisible = ScrollPane(nScrollX, true, true);
+
+ if (nScrollY && bVisible)
+ ScrollPane(nScrollY, false, true);
+ }
+}
+
+void OJoinTableView::SetDefaultTabWinPosSize( OTableWindow* pTabWin )
+{
+ // determine position:
+ // the window is divided into lines with height TABWIN_SPACING_Y+TABWIN_HEIGHT_STD.
+ // Then for each line is checked, if there is space for another window.
+ // If there is no space, the next line is checked.
+ Size aOutSize = GetSizePixel();
+ Point aNewPos( 0,0 );
+ sal_uInt16 nRow = 0;
+ bool bEnd = false;
+ while( !bEnd )
+ {
+ // Set new position to start of line
+ aNewPos.setX( TABWIN_SPACING_X );
+ aNewPos.setY( (nRow+1) * TABWIN_SPACING_Y );
+
+ // determine rectangle for the corresponding line
+ tools::Rectangle aRowRect( Point(0,0), aOutSize );
+ aRowRect.SetTop( nRow * ( TABWIN_SPACING_Y + TABWIN_HEIGHT_STD ) );
+ aRowRect.SetBottom( (nRow+1) * ( TABWIN_SPACING_Y + TABWIN_HEIGHT_STD ) );
+
+ // check occupied areas of this line
+ for (auto const& elem : m_aTableMap)
+ {
+ OTableWindow* pOtherTabWin = elem.second;
+ tools::Rectangle aOtherTabWinRect( pOtherTabWin->GetPosPixel(), pOtherTabWin->GetSizePixel() );
+
+ if(
+ ( (aOtherTabWinRect.Top()>aRowRect.Top()) && (aOtherTabWinRect.Top()<aRowRect.Bottom()) ) ||
+ ( (aOtherTabWinRect.Bottom()>aRowRect.Top()) && (aOtherTabWinRect.Bottom()<aRowRect.Bottom()) )
+ )
+ {
+ // TabWin is in the line
+ if( aOtherTabWinRect.Right()>aNewPos.X() )
+ aNewPos.setX( aOtherTabWinRect.Right() + TABWIN_SPACING_X );
+ }
+ }
+
+ // Is there space left in this line?
+ if( (aNewPos.X()+TABWIN_WIDTH_STD)<aRowRect.Right() )
+ {
+ aNewPos.setY( aRowRect.Top() + TABWIN_SPACING_Y );
+ bEnd = true;
+ }
+ else
+ {
+ if( (aRowRect.Bottom()+aRowRect.GetHeight()) > aOutSize.Height() )
+ {
+ // insert it in the first row
+ sal_Int32 nCount = m_aTableMap.size() % (nRow+1);
+ ++nCount;
+ aNewPos.setY( nCount * TABWIN_SPACING_Y + (nCount-1)*CalcZoom(TABWIN_HEIGHT_STD) );
+ bEnd = true;
+ }
+ else
+ nRow++;
+
+ }
+ }
+
+ // determine size
+ Size aNewSize( CalcZoom(TABWIN_WIDTH_STD), CalcZoom(TABWIN_HEIGHT_STD) );
+
+ // check if the new position in inside the scrollbars ranges
+ Point aBottom(aNewPos);
+ aBottom.AdjustX(aNewSize.Width() );
+ aBottom.AdjustY(aNewSize.Height() );
+
+ if(!GetHScrollBar().GetRange().Contains(aBottom.X()))
+ GetHScrollBar().SetRange( Range(0, aBottom.X()) );
+ if(!GetVScrollBar().GetRange().Contains(aBottom.Y()))
+ GetVScrollBar().SetRange( Range(0, aBottom.Y()) );
+
+ pTabWin->SetPosSizePixel( aNewPos, aNewSize );
+}
+
+void OJoinTableView::DataChanged(const DataChangedEvent& rDCEvt)
+{
+ if (rDCEvt.GetType() == DataChangedEventType::SETTINGS)
+ {
+ // consider the worst case: the colors changed, so adjust me
+ InitColors();
+ Invalidate(InvalidateFlags::NoChildren);
+ // due to the Invalidate, the connections are redrawn, so that they are also pictured in the new colors
+ }
+}
+
+void OJoinTableView::InitColors()
+{
+ // the colors for the illustration should be the system colors
+ StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings();
+ SetBackground(Wallpaper(aSystemStyle.GetDialogColor()));
+}
+
+void OJoinTableView::BeginChildMove( OTableWindow* pTabWin, const Point& rMousePos )
+{
+
+ if (m_pView->getController().isReadOnly())
+ return;
+
+ m_pDragWin = pTabWin;
+ SetPointer(PointerStyle::Move);
+ Point aMousePos = ScreenToOutputPixel( rMousePos );
+ m_aDragOffset = aMousePos - pTabWin->GetPosPixel();
+ m_pDragWin->SetZOrder(nullptr, ZOrderFlags::First);
+ StartTracking();
+}
+
+void OJoinTableView::NotifyTitleClicked( OTableWindow* pTabWin, const Point& rMousePos )
+{
+ DeselectConn(GetSelectedConn());
+ BeginChildMove(pTabWin, rMousePos);
+}
+
+void OJoinTableView::BeginChildSizing( OTableWindow* pTabWin, PointerStyle nPointer )
+{
+
+ if (m_pView->getController().isReadOnly())
+ return;
+
+ SetPointer( nPointer );
+ m_pSizingWin = pTabWin;
+ StartTracking();
+}
+
+bool OJoinTableView::ScrollPane( tools::Long nDelta, bool bHoriz, bool bPaintScrollBars )
+{
+ bool bRet = true;
+
+ // adjust ScrollBar-Positions
+ if( bPaintScrollBars )
+ {
+ if( bHoriz )
+ {
+ tools::Long nOldThumbPos = GetHScrollBar().GetThumbPos();
+ tools::Long nNewThumbPos = nOldThumbPos + nDelta;
+ if( nNewThumbPos < 0 )
+ {
+ nNewThumbPos = 0;
+ bRet = false;
+ }
+ if( nNewThumbPos > GetHScrollBar().GetRange().Max() )
+ {
+ nNewThumbPos = GetHScrollBar().GetRange().Max();
+ bRet = false;
+ }
+ GetHScrollBar().SetThumbPos( nNewThumbPos );
+ nDelta = GetHScrollBar().GetThumbPos() - nOldThumbPos;
+ }
+ else
+ {
+ tools::Long nOldThumbPos = GetVScrollBar().GetThumbPos();
+ tools::Long nNewThumbPos = nOldThumbPos+nDelta;
+ if( nNewThumbPos < 0 )
+ {
+ nNewThumbPos = 0;
+ bRet = false;
+ }
+ if( nNewThumbPos > GetVScrollBar().GetRange().Max() )
+ {
+ nNewThumbPos = GetVScrollBar().GetRange().Max();
+ bRet = false;
+ }
+ GetVScrollBar().SetThumbPos( nNewThumbPos );
+ nDelta = GetVScrollBar().GetThumbPos() - nOldThumbPos;
+ }
+ }
+
+ // If ScrollOffset hitting borders, no redrawing.
+ if( (GetHScrollBar().GetThumbPos()==m_aScrollOffset.X()) &&
+ (GetVScrollBar().GetThumbPos()==m_aScrollOffset.Y()) )
+ return false;
+
+ // set ScrollOffset anew
+ if (bHoriz)
+ m_aScrollOffset.setX( GetHScrollBar().GetThumbPos() );
+ else
+ m_aScrollOffset.setY( GetVScrollBar().GetThumbPos() );
+
+ // move all windows
+ OTableWindow* pTabWin;
+ Point aPos;
+
+ for (auto const& elem : m_aTableMap)
+ {
+ pTabWin = elem.second;
+ aPos = pTabWin->GetPosPixel();
+
+ if( bHoriz )
+ aPos.AdjustX( -nDelta );
+ else aPos.AdjustY( -nDelta );
+
+ pTabWin->SetPosPixel( aPos );
+ }
+
+ Invalidate(); // InvalidateFlags::NoChildren
+
+ return bRet;
+}
+
+void OJoinTableView::Tracking( const TrackingEvent& rTEvt )
+{
+ HideTracking();
+
+ if (rTEvt.IsTrackingEnded())
+ {
+ if( m_pDragWin )
+ {
+ if (m_aDragScrollIdle.IsActive())
+ m_aDragScrollIdle.Stop();
+
+ // adjust position of child after moving
+ // windows are not allowed to leave display range
+ Point aDragWinPos = rTEvt.GetMouseEvent().GetPosPixel() - m_aDragOffset;
+ Size aDragWinSize = m_pDragWin->GetSizePixel();
+ if( aDragWinPos.X() < 0 )
+ aDragWinPos.setX( 0 );
+ if( aDragWinPos.Y() < 0 )
+ aDragWinPos.setY( 0 );
+ if( (aDragWinPos.X() + aDragWinSize.Width()) > m_aOutputSize.Width() )
+ aDragWinPos.setX( m_aOutputSize.Width() - aDragWinSize.Width() - 1 );
+ if( (aDragWinPos.Y() + aDragWinSize.Height()) > m_aOutputSize.Height() )
+ aDragWinPos.setY( m_aOutputSize.Height() - aDragWinSize.Height() - 1 );
+ if( aDragWinPos.X() < 0 )
+ aDragWinPos.setX( 0 );
+ if( aDragWinPos.Y() < 0 )
+ aDragWinPos.setY( 0 );
+ // TODO : don't position window anew, if it is leaving range, but just expand the range
+
+ // position window
+ EndTracking();
+ m_pDragWin->SetZOrder(nullptr, ZOrderFlags::First);
+ // check, if I really moved
+ // (this prevents setting the modified-Flag, when there actually was no change0
+ TTableWindowData::value_type pData = m_pDragWin->GetData();
+ if ( ! (pData && pData->HasPosition() && (pData->GetPosition() == aDragWinPos)))
+ {
+ // old logic coordinates
+ Point ptOldPos = m_pDragWin->GetPosPixel() + Point(GetHScrollBar().GetThumbPos(), GetVScrollBar().GetThumbPos());
+ // new positioning
+ m_pDragWin->SetPosPixel(aDragWinPos);
+ TabWinMoved(m_pDragWin, ptOldPos);
+
+ m_pDragWin->GrabFocus();
+ }
+ m_pDragWin = nullptr;
+ SetPointer(PointerStyle::Arrow);
+ }
+ // else we handle the resizing
+ else if( m_pSizingWin )
+ {
+ SetPointer( PointerStyle::Arrow );
+ EndTracking();
+
+ // old physical coordinates
+
+ Size szOld = m_pSizingWin->GetSizePixel();
+ Point ptOld = m_pSizingWin->GetPosPixel();
+ Size aNewSize(CalcZoom(m_aSizingRect.GetSize().Width()),CalcZoom(m_aSizingRect.GetSize().Height()));
+ m_pSizingWin->SetPosSizePixel( m_aSizingRect.TopLeft(), aNewSize );
+ TabWinSized(m_pSizingWin, ptOld, szOld);
+
+ m_pSizingWin->Invalidate( m_aSizingRect );
+ m_pSizingWin = nullptr;
+ }
+ }
+ else if (rTEvt.IsTrackingCanceled())
+ {
+ if (m_aDragScrollIdle.IsActive())
+ m_aDragScrollIdle.Stop();
+ EndTracking();
+ }
+ else
+ {
+ if( m_pDragWin )
+ {
+ m_ptPrevDraggingPos = rTEvt.GetMouseEvent().GetPosPixel();
+ // scroll at window borders
+ ScrollWhileDragging();
+ }
+
+ if( m_pSizingWin )
+ {
+ Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
+ m_aSizingRect = m_pSizingWin->getSizingRect(aMousePos,m_aOutputSize);
+ PaintImmediately();
+ ShowTracking( m_aSizingRect, ShowTrackFlags::Small | ShowTrackFlags::TrackWindow );
+ }
+ }
+}
+
+void OJoinTableView::ConnDoubleClicked(VclPtr<OTableConnection>& /*rConnection*/)
+{
+}
+
+void OJoinTableView::MouseButtonDown( const MouseEvent& rEvt )
+{
+ GrabFocus();
+ Window::MouseButtonDown(rEvt);
+}
+
+void OJoinTableView::MouseButtonUp( const MouseEvent& rEvt )
+{
+ Window::MouseButtonUp(rEvt);
+ // Has a connection been selected?
+ if( m_vTableConnection.empty() )
+ return;
+
+ DeselectConn(GetSelectedConn());
+
+ for (auto & elem : m_vTableConnection)
+ {
+ if( elem->CheckHit(rEvt.GetPosPixel()) )
+ {
+ SelectConn(elem);
+
+ // Double-click
+ if( rEvt.GetClicks() == 2 )
+ ConnDoubleClicked(elem);
+
+ break;
+ }
+ }
+}
+
+void OJoinTableView::KeyInput( const KeyEvent& rEvt )
+{
+ sal_uInt16 nCode = rEvt.GetKeyCode().GetCode();
+ bool bShift = rEvt.GetKeyCode().IsShift();
+ bool bCtrl = rEvt.GetKeyCode().IsMod1();
+
+ if( !bCtrl && !bShift && (nCode==KEY_DELETE) )
+ {
+ if (GetSelectedConn())
+ RemoveConnection(GetSelectedConn(), true);
+ }
+ else
+ Window::KeyInput( rEvt );
+}
+
+void OJoinTableView::DeselectConn(OTableConnection* pConn)
+{
+ if (!pConn || !pConn->IsSelected())
+ return;
+
+ // deselect the corresponding entries in the ListBox of the table window
+ OTableWindow* pWin = pConn->GetSourceWin();
+ if (pWin && pWin->GetListBox())
+ pWin->GetListBox()->get_widget().unselect_all();
+
+ pWin = pConn->GetDestWin();
+ if (pWin && pWin->GetListBox())
+ pWin->GetListBox()->get_widget().unselect_all();
+
+ pConn->Deselect();
+ m_pSelectedConn = nullptr;
+}
+
+void OJoinTableView::SelectConn(OTableConnection* pConn)
+{
+ DeselectConn(GetSelectedConn());
+
+ pConn->Select();
+ m_pSelectedConn = pConn;
+ GrabFocus(); // has to be called here because a table window may still be focused
+
+ // select the concerned entries in the windows
+ OTableWindow* pConnSource = pConn->GetSourceWin();
+ OTableWindow* pConnDest = pConn->GetDestWin();
+ if (!(pConnSource && pConnDest))
+ return;
+
+ OTableWindowListBox* pSourceBox = pConnSource->GetListBox().get();
+ OTableWindowListBox* pDestBox = pConnDest->GetListBox().get();
+ if (!(pSourceBox && pDestBox))
+ return;
+
+ pSourceBox->get_widget().unselect_all();
+ pDestBox->get_widget().unselect_all();
+
+ bool bScrolled = false;
+
+ const std::vector<std::unique_ptr<OConnectionLine>>& rLines = pConn->GetConnLineList();
+ auto aIter = rLines.rbegin();
+ for(;aIter != rLines.rend();++aIter)
+ {
+ if ((*aIter)->IsValid())
+ {
+ int nSourceEntry = pSourceBox->GetEntryFromText((*aIter)->GetData()->GetSourceFieldName());
+ if (nSourceEntry != -1)
+ {
+ pSourceBox->get_widget().select(nSourceEntry);
+ pSourceBox->get_widget().scroll_to_row(nSourceEntry);
+ bScrolled = true;
+ }
+
+ int nDestEntry = pDestBox->GetEntryFromText((*aIter)->GetData()->GetDestFieldName());
+ if (nDestEntry != -1)
+ {
+ pDestBox->get_widget().select(nDestEntry);
+ pDestBox->get_widget().scroll_to_row(nDestEntry);
+ bScrolled = true;
+ }
+ }
+ }
+
+ if (bScrolled)
+ {
+ // scrolling was done -> redraw
+ Invalidate(InvalidateFlags::NoChildren);
+ }
+}
+
+void OJoinTableView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ DrawConnections(rRenderContext, rRect);
+}
+
+void OJoinTableView::InvalidateConnections()
+{
+ // draw Joins
+ for (auto & conn : m_vTableConnection)
+ conn->InvalidateConnection();
+}
+
+void OJoinTableView::DrawConnections(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ // draw Joins
+ for(const auto& connection : m_vTableConnection)
+ connection->Draw(rRenderContext, rRect);
+ // finally redraw the selected one above all others
+ if (GetSelectedConn())
+ GetSelectedConn()->Draw(rRenderContext, rRect);
+}
+
+std::vector<VclPtr<OTableConnection> >::const_iterator OJoinTableView::getTableConnections(const OTableWindow* _pFromWin) const
+{
+ return std::find_if( m_vTableConnection.begin(),
+ m_vTableConnection.end(),
+ [_pFromWin](OTableConnection * p) { return p->isTableConnection(_pFromWin); });
+}
+
+sal_Int32 OJoinTableView::getConnectionCount(const OTableWindow* _pFromWin) const
+{
+ return std::count_if( m_vTableConnection.begin(),
+ m_vTableConnection.end(),
+ [_pFromWin](OTableConnection * p) { return p->isTableConnection(_pFromWin); });
+}
+
+bool OJoinTableView::ExistsAConn(const OTableWindow* pFrom) const
+{
+ return getTableConnections(pFrom) != m_vTableConnection.end();
+}
+
+void OJoinTableView::ClearAll()
+{
+ SetUpdateMode(false);
+
+ HideTabWins();
+
+ // and the same with the Connections
+ for (auto & elem : m_vTableConnection)
+ {
+ RemoveConnection(elem, true);
+ }
+ m_vTableConnection.clear();
+
+ m_pLastFocusTabWin = nullptr;
+ m_pSelectedConn = nullptr;
+
+ // scroll to the upper left
+ ScrollPane(-GetScrollOffset().X(), true, true);
+ ScrollPane(-GetScrollOffset().Y(), false, true);
+ Invalidate();
+}
+
+void OJoinTableView::ScrollWhileDragging()
+{
+ OSL_ENSURE(m_pDragWin != nullptr, "OJoinTableView::ScrollWhileDragging must not be called when a window is being dragged !");
+
+ // kill the timer
+ if (m_aDragScrollIdle.IsActive())
+ m_aDragScrollIdle.Stop();
+
+ Point aDragWinPos = m_ptPrevDraggingPos - m_aDragOffset;
+ Size aDragWinSize = m_pDragWin->GetSizePixel();
+ Point aLowerRight(aDragWinPos.X() + aDragWinSize.Width(), aDragWinPos.Y() + aDragWinSize.Height());
+
+ if (aDragWinPos == m_pDragWin->GetPosPixel())
+ return;
+
+ // avoid illustration errors (when scrolling with active TrackingRect)
+ HideTracking();
+
+ bool bScrolling = false;
+ bool bNeedScrollTimer = false;
+
+ // scroll at window borders
+ // TODO : only catch, if window would disappear completely (don't, if there is still a pixel visible)
+ if( aDragWinPos.X() < 5 )
+ {
+ bScrolling = ScrollPane( -LINE_SIZE, true, true );
+ if( !bScrolling && (aDragWinPos.X()<0) )
+ aDragWinPos.setX( 0 );
+
+ // do I need further (timer controlled) scrolling ?
+ bNeedScrollTimer = bScrolling && (aDragWinPos.X() < 5);
+ }
+
+ if( aLowerRight.X() > m_aOutputSize.Width() - 5 )
+ {
+ bScrolling = ScrollPane( LINE_SIZE, true, true ) ;
+ if( !bScrolling && ( aLowerRight.X() > m_aOutputSize.Width() ) )
+ aDragWinPos.setX( m_aOutputSize.Width() - aDragWinSize.Width() );
+
+ // do I need further (timer controlled) scrolling ?
+ bNeedScrollTimer = bScrolling && (aLowerRight.X() > m_aOutputSize.Width() - 5);
+ }
+
+ if( aDragWinPos.Y() < 5 )
+ {
+ bScrolling = ScrollPane( -LINE_SIZE, false, true );
+ if( !bScrolling && (aDragWinPos.Y()<0) )
+ aDragWinPos.setY( 0 );
+
+ bNeedScrollTimer = bScrolling && (aDragWinPos.Y() < 5);
+ }
+
+ if( aLowerRight.Y() > m_aOutputSize.Height() - 5 )
+ {
+ bScrolling = ScrollPane( LINE_SIZE, false, true );
+ if( !bScrolling && ( (aDragWinPos.Y() + aDragWinSize.Height()) > m_aOutputSize.Height() ) )
+ aDragWinPos.setY( m_aOutputSize.Height() - aDragWinSize.Height() );
+
+ bNeedScrollTimer = bScrolling && (aLowerRight.Y() > m_aOutputSize.Height() - 5);
+ }
+
+ // resetting timer, if still necessary
+ if (bNeedScrollTimer)
+ {
+ m_aDragScrollIdle.SetPriority( TaskPriority::HIGH_IDLE );
+ m_aDragScrollIdle.Start();
+ }
+
+ // redraw DraggingRect
+ m_aDragRect = tools::Rectangle(m_ptPrevDraggingPos - m_aDragOffset, m_pDragWin->GetSizePixel());
+ PaintImmediately();
+ ShowTracking( m_aDragRect, ShowTrackFlags::Small | ShowTrackFlags::TrackWindow );
+}
+
+IMPL_LINK_NOARG(OJoinTableView, OnDragScrollTimer, Timer *, void)
+{
+ ScrollWhileDragging();
+}
+
+void OJoinTableView::invalidateAndModify(std::unique_ptr<SfxUndoAction> _pAction)
+{
+ Invalidate(InvalidateFlags::NoChildren);
+ m_pView->getController().addUndoActionAndInvalidate(std::move(_pAction));
+}
+
+void OJoinTableView::TabWinMoved(OTableWindow* ptWhich, const Point& ptOldPosition)
+{
+ Point ptThumbPos(GetHScrollBar().GetThumbPos(), GetVScrollBar().GetThumbPos());
+ ptWhich->GetData()->SetPosition(ptWhich->GetPosPixel() + ptThumbPos);
+
+ invalidateAndModify(std::make_unique<OJoinMoveTabWinUndoAct>(this, ptOldPosition, ptWhich));
+}
+
+void OJoinTableView::TabWinSized(OTableWindow* ptWhich, const Point& ptOldPosition, const Size& szOldSize)
+{
+ ptWhich->GetData()->SetSize(ptWhich->GetSizePixel());
+ ptWhich->GetData()->SetPosition(ptWhich->GetPosPixel());
+
+ invalidateAndModify(std::make_unique<OJoinSizeTabWinUndoAct>(this, ptOldPosition, szOldSize, ptWhich));
+}
+
+bool OJoinTableView::IsAddAllowed()
+{
+
+ // not, if Db readonly
+ if (m_pView->getController().isReadOnly())
+ return false;
+
+ try
+ {
+ Reference< XConnection> xConnection = m_pView->getController().getConnection();
+ if(!xConnection.is())
+ return false;
+ // not, if too many tables already
+ Reference < XDatabaseMetaData > xMetaData( xConnection->getMetaData() );
+
+ sal_Int32 nMax = xMetaData.is() ? xMetaData->getMaxTablesInSelect() : 0;
+ if (nMax && nMax <= static_cast<sal_Int32>(m_aTableMap.size()))
+ return false;
+ }
+ catch(SQLException&)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void OJoinTableView::executePopup(const Point& rPos, VclPtr<OTableConnection>& rSelConnection)
+{
+ ::tools::Rectangle aRect(rPos, Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/joinviewmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
+ if (sIdent == "delete")
+ RemoveConnection(rSelConnection, true);
+ else if (sIdent == "edit")
+ ConnDoubleClicked(rSelConnection); // is the same as double clicked
+}
+
+void OJoinTableView::Command(const CommandEvent& rEvt)
+{
+
+ bool bHandled = false;
+
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ if( m_vTableConnection.empty() )
+ return;
+
+ VclPtr<OTableConnection>& rSelConnection = GetSelectedConn();
+ // when it wasn't a mouse event use the selected connection
+ if (!rEvt.IsMouseEvent())
+ {
+ if (rSelConnection)
+ {
+ const std::vector<std::unique_ptr<OConnectionLine>>& rLines = rSelConnection->GetConnLineList();
+ auto aIter = std::find_if(rLines.begin(), rLines.end(),std::mem_fn(&OConnectionLine::IsValid));
+ if( aIter != rLines.end() )
+ executePopup((*aIter)->getMidPoint(), rSelConnection);
+ }
+ }
+ else
+ {
+ DeselectConn(rSelConnection);
+
+ const Point& aMousePos = rEvt.GetMousePosPixel();
+ for (auto & elem : m_vTableConnection)
+ {
+ if( elem->CheckHit(aMousePos) )
+ {
+ SelectConn(elem);
+ if(!getDesignView()->getController().isReadOnly() && getDesignView()->getController().isConnected())
+ executePopup(rEvt.GetMousePosPixel(),elem);
+ break;
+ }
+ }
+ }
+ bHandled = true;
+ }
+ break;
+ default: break;
+ }
+ if (!bHandled)
+ Window::Command(rEvt);
+}
+
+OTableConnection* OJoinTableView::GetTabConn(const OTableWindow* pLhs,const OTableWindow* pRhs,bool _bSuppressCrossOrNaturalJoin) const
+{
+ OTableConnection* pConn = nullptr;
+ OSL_ENSURE(pRhs || pLhs, "OJoinTableView::GetTabConn : invalid args !");
+ // only one NULL-arg allowed
+
+ if ((!pLhs || pLhs->ExistsAConn()) && (!pRhs || pRhs->ExistsAConn()))
+ {
+ for(VclPtr<OTableConnection> const & pData : m_vTableConnection)
+ {
+ if ( ( (pData->GetSourceWin() == pLhs)
+ && ( (pData->GetDestWin() == pRhs)
+ || (nullptr == pRhs)
+ )
+ )
+ || ( (pData->GetSourceWin() == pRhs)
+ && ( (pData->GetDestWin() == pLhs)
+ || (nullptr == pLhs)
+ )
+ )
+ )
+ {
+ if ( _bSuppressCrossOrNaturalJoin )
+ {
+ if ( suppressCrossNaturalJoin(pData->GetData()) )
+ continue;
+ }
+ pConn = pData;
+ break;
+ }
+ }
+ }
+ return pConn;
+}
+
+bool OJoinTableView::PreNotify(NotifyEvent& rNEvt)
+{
+ bool bHandled = false;
+ switch (rNEvt.GetType())
+ {
+ case MouseNotifyEvent::COMMAND:
+ {
+ const CommandEvent* pCommand = rNEvt.GetCommandEvent();
+ if (pCommand->GetCommand() == CommandEventId::Wheel)
+ {
+ const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
+ if (pData->GetMode() == CommandWheelMode::SCROLL)
+ {
+ if (pData->GetDelta() > 0)
+ ScrollPane(-10 * pData->GetScrollLines(), pData->IsHorz(), true);
+ else
+ ScrollPane(10 * pData->GetScrollLines(), pData->IsHorz(), true);
+ bHandled = true;
+ }
+ }
+ }
+ break;
+ case MouseNotifyEvent::KEYINPUT:
+ {
+ if (m_aTableMap.empty())
+ // no tab wins -> no conns -> no traveling
+ break;
+
+ const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent();
+ if (!pKeyEvent->GetKeyCode().IsMod1())
+ {
+ switch (pKeyEvent->GetKeyCode().GetCode())
+ {
+ case KEY_TAB:
+ {
+ if (!HasChildPathFocus())
+ break;
+
+ bool bForward = !pKeyEvent->GetKeyCode().IsShift();
+ // is there an active tab win ?
+ OTableWindowMap::const_iterator aIter = std::find_if(m_aTableMap.begin(), m_aTableMap.end(),
+ [](const OTableWindowMap::value_type& rEntry) { return rEntry.second && rEntry.second->HasChildPathFocus(); });
+
+ OTableWindow* pNextWin = nullptr;
+ OTableConnection* pNextConn = nullptr;
+
+ if (aIter != m_aTableMap.end())
+ { // there is a currently active tab win
+ // check if there is an "overflow" and we should select a conn instead of a win
+ if (!m_vTableConnection.empty())
+ {
+ if ((aIter->second == m_aTableMap.rbegin()->second) && bForward)
+ // the last win is active and we're travelling forward -> select the first conn
+ pNextConn = m_vTableConnection.begin()->get();
+ if ((aIter == m_aTableMap.begin()) && !bForward)
+ // the first win is active and we're traveling backward -> select the last conn
+ pNextConn = m_vTableConnection.rbegin()->get();
+ }
+
+ if (!pNextConn)
+ {
+ // no conn for any reason -> select the next or previous tab win
+ if(bForward)
+ {
+ if ( aIter->second == m_aTableMap.rbegin()->second )
+ pNextWin = m_aTableMap.begin()->second;
+ else
+ {
+ ++aIter;
+ pNextWin = aIter->second;
+ }
+ }
+ else
+ {
+ if (aIter == m_aTableMap.begin())
+ pNextWin = m_aTableMap.rbegin()->second;
+ else
+ {
+ --aIter;
+ pNextWin = aIter->second;
+ }
+ }
+ }
+ }
+ else
+ { // no active tab win -> travel the connections
+ // find the currently selected conn within the conn list
+ sal_Int32 i(0);
+ for (auto const& elem : m_vTableConnection)
+ {
+ if ( elem.get() == GetSelectedConn() )
+ break;
+ ++i;
+ }
+ if (i == sal_Int32(m_vTableConnection.size() - 1) && bForward)
+ // the last conn is active and we're travelling forward -> select the first win
+ pNextWin = m_aTableMap.begin()->second;
+ if ((i == 0) && !bForward && !m_aTableMap.empty())
+ // the first conn is active and we're travelling backward -> select the last win
+ pNextWin = m_aTableMap.rbegin()->second;
+
+ if (pNextWin)
+ DeselectConn(GetSelectedConn());
+ else
+ // no win for any reason -> select the next or previous conn
+ if (i < static_cast<sal_Int32>(m_vTableConnection.size()))
+ // there is a currently active conn
+ pNextConn = m_vTableConnection[(i + (bForward ? 1 : m_vTableConnection.size() - 1)) % m_vTableConnection.size()].get();
+ else
+ { // no tab win selected, no conn selected
+ if (!m_vTableConnection.empty())
+ pNextConn = m_vTableConnection[bForward ? 0 : m_vTableConnection.size() - 1].get();
+ else if (!m_aTableMap.empty())
+ {
+ if(bForward)
+ pNextWin = m_aTableMap.begin()->second;
+ else
+ pNextWin = m_aTableMap.rbegin()->second;
+ }
+ }
+ }
+
+ // now select the object
+ if (pNextWin)
+ {
+ if (pNextWin->GetListBox())
+ pNextWin->GetListBox()->GrabFocus();
+ else
+ pNextWin->GrabFocus();
+ EnsureVisible(pNextWin);
+ }
+ else if (pNextConn)
+ {
+ GrabFocus();
+ // necessary : a conn may be selected even if a tab win has the focus, in this case
+ // the next travel would select the same conn again if we would not reset the focus ...
+ SelectConn(pNextConn);
+ }
+ }
+ break;
+ case KEY_RETURN:
+ {
+ if (!pKeyEvent->GetKeyCode().IsShift() && GetSelectedConn() && HasFocus())
+ ConnDoubleClicked(GetSelectedConn());
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case MouseNotifyEvent::GETFOCUS:
+ {
+ if (m_aTableMap.empty())
+ // no tab wins -> no conns -> no focus change
+ break;
+ vcl::Window* pSource = rNEvt.GetWindow();
+ if (pSource)
+ {
+ vcl::Window* pSearchFor = nullptr;
+ if (pSource->GetParent() == this)
+ // it may be one of the tab wins
+ pSearchFor = pSource;
+ else if (pSource->GetParent() && (pSource->GetParent()->GetParent() == this))
+ // it may be one of th list boxes of one of the tab wins
+ pSearchFor = pSource->GetParent();
+
+ if (pSearchFor)
+ {
+ for (auto const& elem : m_aTableMap)
+ {
+ if (elem.second == pSearchFor)
+ {
+ m_pLastFocusTabWin = elem.second;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!bHandled)
+ return Window::PreNotify(rNEvt);
+ return true;
+}
+
+void OJoinTableView::GrabTabWinFocus()
+{
+ if (m_pLastFocusTabWin && m_pLastFocusTabWin->IsVisible())
+ {
+ if (m_pLastFocusTabWin->GetListBox())
+ m_pLastFocusTabWin->GetListBox()->GrabFocus();
+ else
+ m_pLastFocusTabWin->GrabFocus();
+ }
+ else if (!m_aTableMap.empty() && m_aTableMap.begin()->second && m_aTableMap.begin()->second->IsVisible())
+ {
+ VclPtr<OTableWindow> pFirstWin = m_aTableMap.begin()->second;
+ if (pFirstWin->GetListBox())
+ pFirstWin->GetListBox()->GrabFocus();
+ else
+ pFirstWin->GrabFocus();
+ }
+}
+
+void OJoinTableView::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ // FIXME RenderContext
+ if ( nType != StateChangedType::Zoom )
+ return;
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ vcl::Font aFont = rStyleSettings.GetGroupFont();
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ SetZoomedPointFont(*GetOutDev(), aFont);
+
+ for (auto const& elem : m_aTableMap)
+ {
+ elem.second->SetZoom(GetZoom());
+ Size aSize(CalcZoom(elem.second->GetSizePixel().Width()),CalcZoom(elem.second->GetSizePixel().Height()));
+ elem.second->SetSizePixel(aSize);
+ }
+ Resize();
+}
+
+void OJoinTableView::HideTabWins()
+{
+ SetUpdateMode(false);
+
+ OTableWindowMap& rTabWins = GetTabWinMap();
+
+ // working on a copy because the real list will be cleared in inner calls
+ OTableWindowMap aCopy(rTabWins);
+ for (auto const& elem : aCopy)
+ RemoveTabWin(elem.second);
+
+ m_pView->getController().setModified(true);
+
+ SetUpdateMode(true);
+
+}
+
+sal_Int8 OJoinTableView::AcceptDrop( const AcceptDropEvent& /*_rEvt*/ )
+{
+ return DND_ACTION_NONE;
+}
+
+sal_Int8 OJoinTableView::ExecuteDrop( const ExecuteDropEvent& /*_rEvt*/ )
+{
+ return DND_ACTION_NONE;
+}
+
+void OJoinTableView::dragFinished( )
+{
+}
+
+void OJoinTableView::clearLayoutInformation()
+{
+ m_pLastFocusTabWin = nullptr;
+ m_pSelectedConn = nullptr;
+ // delete lists
+ for (auto & elem : m_aTableMap)
+ {
+ if ( elem.second )
+ elem.second->clearListBox();
+ elem.second.disposeAndClear();
+ }
+
+ m_aTableMap.clear();
+
+ for (auto & elem : m_vTableConnection)
+ elem.disposeAndClear();
+
+ m_vTableConnection.clear();
+}
+
+void OJoinTableView::lookForUiActivities()
+{
+}
+
+void OJoinTableView::LoseFocus()
+{
+ DeselectConn(GetSelectedConn());
+ Window::LoseFocus();
+}
+
+void OJoinTableView::GetFocus()
+{
+ Window::GetFocus();
+ if ( !m_aTableMap.empty() && !GetSelectedConn() )
+ GrabTabWinFocus();
+}
+
+Reference< XAccessible > OJoinTableView::CreateAccessible()
+{
+ m_pAccessible = new OJoinDesignViewAccess(this);
+ return m_pAccessible;
+}
+
+void OJoinTableView::modified()
+{
+ OJoinController& rController = m_pView->getController();
+ rController.setModified( true );
+ rController.InvalidateFeature(ID_BROWSER_ADDTABLE);
+ rController.InvalidateFeature(SID_RELATION_ADD_RELATION);
+}
+
+void OJoinTableView::addConnection(OTableConnection* _pConnection,bool _bAddData)
+{
+ if ( _bAddData )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData();
+ OSL_ENSURE( std::find(rTabConnDataList.begin(), rTabConnDataList.end(),_pConnection->GetData()) == rTabConnDataList.end(),"Data already in vector!");
+#endif
+ m_pView->getController().getTableConnectionData().push_back(_pConnection->GetData());
+ }
+ m_vTableConnection.emplace_back(_pConnection);
+ _pConnection->RecalcLines();
+ _pConnection->InvalidateConnection();
+
+ modified();
+ if ( m_pAccessible )
+ m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
+ Any(),
+ Any(_pConnection->GetAccessible()));
+}
+
+bool OJoinTableView::allowQueries() const
+{
+ return true;
+}
+
+void OJoinTableView::onNoColumns_throw()
+{
+ OSL_FAIL( "OTableWindow::onNoColumns_throw: cannot really handle this!" );
+ throw SQLException();
+}
+
+bool OJoinTableView::suppressCrossNaturalJoin(const TTableConnectionData::value_type& ) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableConnection.cxx b/dbaccess/source/ui/querydesign/QTableConnection.cxx
new file mode 100644
index 000000000..c5db155f2
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableConnection.cxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "QTableConnection.hxx"
+#include <osl/diagnose.h>
+#include <QueryTableView.hxx>
+
+using namespace dbaui;
+
+OQueryTableConnection::OQueryTableConnection(OQueryTableView* pContainer, const TTableConnectionData::value_type& pTabConnData)
+ : OTableConnection(pContainer, pTabConnData)
+ , m_bVisited(false)
+{
+}
+
+OQueryTableConnection::OQueryTableConnection(const OQueryTableConnection& rConn)
+ : VclReferenceBase(),
+ OTableConnection( rConn )
+ , m_bVisited(false)
+{
+ // no own members, so base class functionality is sufficient
+}
+
+OQueryTableConnection& OQueryTableConnection::operator=(const OQueryTableConnection& rConn)
+{
+ if (&rConn == this)
+ return *this;
+
+ OTableConnection::operator=(rConn);
+ // no own members ...
+ return *this;
+}
+
+bool OQueryTableConnection::operator==(const OQueryTableConnection& rCompare) const
+{
+ OSL_ENSURE(GetData() && rCompare.GetData(), "OQueryTableConnection::operator== : one of the two participants has no data!");
+
+ // I don't have to compare all too much (especially not all the members) : merely the windows, which we are connected to, and the indices in the corresponding table have to match.
+ OQueryTableConnectionData* pMyData = static_cast<OQueryTableConnectionData*>(GetData().get());
+ OQueryTableConnectionData* pCompData = static_cast<OQueryTableConnectionData*>(rCompare.GetData().get());
+
+ // Connections are seen as equal, if source and destination window names and source and destination field Indices match...
+ return ( ( (pMyData->getReferencedTable() == pCompData->getReferencedTable()) &&
+ (pMyData->getReferencingTable() == pCompData->getReferencingTable()) &&
+ (pMyData->GetFieldIndex(JTCS_TO) == pCompData->GetFieldIndex(JTCS_TO)) &&
+ (pMyData->GetFieldIndex(JTCS_FROM) == pCompData->GetFieldIndex(JTCS_FROM))
+ )
+ || // ... or this cross matching is given
+ ( (pMyData->getReferencingTable() == pCompData->getReferencedTable()) &&
+ (pMyData->getReferencedTable() == pCompData->getReferencingTable()) &&
+ (pMyData->GetFieldIndex(JTCS_TO) == pCompData->GetFieldIndex(JTCS_FROM)) &&
+ (pMyData->GetFieldIndex(JTCS_FROM) == pCompData->GetFieldIndex(JTCS_TO))
+ )
+ );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableConnection.hxx b/dbaccess/source/ui/querydesign/QTableConnection.hxx
new file mode 100644
index 000000000..c6bd2e10d
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableConnection.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableConnection.hxx>
+#include "QTableConnectionData.hxx"
+#include <QEnumTypes.hxx>
+
+namespace dbaui
+{
+ class OQueryTableView;
+ class OQueryTableConnection : public OTableConnection
+ {
+ bool m_bVisited; // is true if the conn was already visited through the join algorithm
+ public:
+ OQueryTableConnection(OQueryTableView* pContainer, const TTableConnectionData::value_type& pTabConnData);
+ OQueryTableConnection(const OQueryTableConnection& rConn);
+
+ OQueryTableConnection& operator=(const OQueryTableConnection& rConn);
+ bool operator==(const OQueryTableConnection& rCompare) const;
+
+ OUString const & GetAliasName(EConnectionSide nWhich) const { return static_cast<OQueryTableConnectionData*>(GetData().get())->GetAliasName(nWhich); }
+
+ bool IsVisited() const { return m_bVisited; }
+ void SetVisited(bool bVisited) { m_bVisited = bVisited; }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableConnectionData.cxx b/dbaccess/source/ui/querydesign/QTableConnectionData.cxx
new file mode 100644
index 000000000..ce66828fa
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableConnectionData.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "QTableConnectionData.hxx"
+#include "QTableWindow.hxx"
+
+#include <osl/diagnose.h>
+
+using namespace dbaui;
+
+OQueryTableConnectionData::OQueryTableConnectionData()
+ : m_nFromEntryIndex(0)
+ , m_nDestEntryIndex(0)
+ , m_eJoinType (INNER_JOIN)
+ , m_bNatural(false)
+{
+}
+
+OQueryTableConnectionData::OQueryTableConnectionData( const OQueryTableConnectionData& rConnData )
+ : OTableConnectionData( rConnData )
+ , m_nFromEntryIndex(rConnData.m_nFromEntryIndex)
+ , m_nDestEntryIndex(rConnData.m_nDestEntryIndex)
+ , m_eJoinType(rConnData.m_eJoinType)
+ , m_bNatural(rConnData.m_bNatural)
+{
+}
+
+OQueryTableConnectionData::OQueryTableConnectionData(const TTableWindowData::value_type& _pReferencingTable,
+ const TTableWindowData::value_type& _pReferencedTable)
+ : OTableConnectionData( _pReferencingTable,_pReferencedTable )
+ , m_nFromEntryIndex(0)
+ , m_nDestEntryIndex(0)
+ , m_eJoinType (INNER_JOIN)
+ , m_bNatural(false)
+{
+}
+
+OQueryTableConnectionData::~OQueryTableConnectionData()
+{
+}
+
+void OQueryTableConnectionData::CopyFrom(const OTableConnectionData& rSource)
+{
+ // same as in base class, use of (non-virtual) operator=
+ *this = static_cast<const OQueryTableConnectionData&>(rSource);
+}
+
+OQueryTableConnectionData& OQueryTableConnectionData::operator=(const OQueryTableConnectionData& rConnData)
+{
+ if (&rConnData == this)
+ return *this;
+
+ OTableConnectionData::operator=(rConnData);
+
+ m_nFromEntryIndex = rConnData.m_nFromEntryIndex;
+ m_nDestEntryIndex = rConnData.m_nDestEntryIndex;
+
+ m_eJoinType = rConnData.m_eJoinType;
+ m_bNatural = rConnData.m_bNatural;
+
+ return *this;
+}
+
+OUString const & OQueryTableConnectionData::GetAliasName(EConnectionSide nWhich) const
+{
+ return nWhich == JTCS_FROM ? m_pReferencingTable->GetWinName() : m_pReferencedTable->GetWinName();
+}
+
+void OQueryTableConnectionData::InitFromDrag(const OTableFieldDescRef& rDragLeft, const OTableFieldDescRef& rDragRight)
+{
+ // convert Information in rDrag into parameters for the base class init
+ OQueryTableWindow* pSourceWin = static_cast<OQueryTableWindow*>(rDragLeft->GetTabWindow());
+ OQueryTableWindow* pDestWin = static_cast<OQueryTableWindow*>(rDragRight->GetTabWindow());
+ OSL_ENSURE(pSourceWin,"NO Source window found!");
+ OSL_ENSURE(pDestWin,"NO Dest window found!");
+ m_pReferencingTable = pSourceWin->GetData();
+ m_pReferencedTable = pDestWin->GetData();
+
+ // set members
+ SetFieldIndex(JTCS_FROM, rDragLeft->GetFieldIndex());
+ SetFieldIndex(JTCS_TO, rDragRight->GetFieldIndex());
+
+ AppendConnLine(rDragLeft->GetField(), rDragRight->GetField());
+}
+
+std::shared_ptr<OTableConnectionData> OQueryTableConnectionData::NewInstance() const
+{
+ return std::make_shared<OQueryTableConnectionData>();
+}
+
+bool OQueryTableConnectionData::Update()
+{
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableConnectionData.hxx b/dbaccess/source/ui/querydesign/QTableConnectionData.hxx
new file mode 100644
index 000000000..7ccbb03ac
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableConnectionData.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableConnectionData.hxx>
+#include <TableFieldDescription.hxx>
+#include <QEnumTypes.hxx>
+
+namespace dbaui
+{
+ class OQueryTableConnectionData final : public OTableConnectionData
+ {
+ sal_Int32 m_nFromEntryIndex;
+ sal_Int32 m_nDestEntryIndex;
+ EJoinType m_eJoinType;
+ bool m_bNatural;
+
+ OQueryTableConnectionData& operator=( const OQueryTableConnectionData& rConnData );
+ public:
+ OQueryTableConnectionData();
+ OQueryTableConnectionData( const OQueryTableConnectionData& rConnData );
+ OQueryTableConnectionData( const TTableWindowData::value_type& _pReferencingTable,const TTableWindowData::value_type& _pReferencedTable );
+ virtual ~OQueryTableConnectionData() override;
+
+ virtual void CopyFrom(const OTableConnectionData& rSource) override;
+ virtual std::shared_ptr<OTableConnectionData> NewInstance() const override;
+
+
+ /** Update create a new connection
+
+ @return true if successful
+ */
+ virtual bool Update() override;
+
+ OUString const & GetAliasName(EConnectionSide nWhich) const;
+
+ sal_Int32 GetFieldIndex(EConnectionSide nWhich) const { return nWhich==JTCS_TO ? m_nDestEntryIndex : m_nFromEntryIndex; }
+ void SetFieldIndex(EConnectionSide nWhich, sal_Int32 nVal) { if (nWhich==JTCS_TO) m_nDestEntryIndex=nVal; else m_nFromEntryIndex=nVal; }
+
+ void InitFromDrag(const OTableFieldDescRef& rDragLeft, const OTableFieldDescRef& rDragRight);
+
+ EJoinType GetJoinType() const { return m_eJoinType; };
+ void SetJoinType(const EJoinType& eJT) { m_eJoinType = eJT; };
+
+ void setNatural(bool _bNatural) { m_bNatural = _bNatural; }
+ bool isNatural() const { return m_bNatural; }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableWindow.cxx b/dbaccess/source/ui/querydesign/QTableWindow.cxx
new file mode 100644
index 000000000..6b129c32d
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableWindow.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "QTableWindow.hxx"
+#include <QueryTableView.hxx>
+#include <JoinController.hxx>
+#include <JoinDesignView.hxx>
+#include <osl/diagnose.h>
+#include <helpids.h>
+#include <browserids.hxx>
+#include <TableWindowListBox.hxx>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include "TableFieldInfo.hxx"
+#include <comphelper/stl_types.hxx>
+#include <comphelper/types.hxx>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace dbaui;
+OQueryTableWindow::OQueryTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData)
+ :OTableWindow( pParent, pTabWinData )
+ ,m_nAliasNum(0)
+{
+ m_strInitialAlias = GetAliasName();
+
+ // if table name matches alias, do not pass to InitialAlias,
+ // as the appending of a possible token could not succeed...
+ if (m_strInitialAlias == pTabWinData->GetTableName())
+ m_strInitialAlias.clear();
+
+ SetHelpId(HID_CTL_QRYDGNTAB);
+}
+
+bool OQueryTableWindow::Init()
+{
+ bool bSuccess = OTableWindow::Init();
+ if (!bSuccess)
+ return bSuccess;
+
+ OQueryTableView* pContainer = static_cast<OQueryTableView*>(getTableView());
+
+ // first determine Alias
+ OUString sAliasName;
+
+ TTableWindowData::value_type pWinData = GetData();
+
+ if (!m_strInitialAlias.isEmpty() )
+ // Alias was explicitly given
+ sAliasName = m_strInitialAlias;
+ else if ( GetTable().is() )
+ GetTable()->getPropertyValue( PROPERTY_NAME ) >>= sAliasName;
+ else
+ return false;
+
+ // Alias with successive number
+ if (pContainer->CountTableAlias(sAliasName, m_nAliasNum))
+ {
+ sAliasName += "_" + OUString::number(m_nAliasNum);
+ }
+
+ sAliasName = sAliasName.replaceAll("\"", "");
+ SetAliasName(sAliasName);
+ // SetAliasName passes it as WinName, hence it uses the base class
+ // reset the title
+ m_xTitle->SetText( pWinData->GetWinName() );
+ m_xTitle->Show();
+
+ getTableView()->getDesignView()->getController().InvalidateFeature(ID_BROWSER_QUERY_EXECUTE);
+ return bSuccess;
+}
+
+void* OQueryTableWindow::createUserData(const Reference< XPropertySet>& _xColumn,bool _bPrimaryKey)
+{
+ OTableFieldInfo* pInfo = new OTableFieldInfo();
+ pInfo->SetKey(_bPrimaryKey ? TAB_PRIMARY_FIELD : TAB_NORMAL_FIELD);
+ if ( _xColumn.is() )
+ pInfo->SetDataType(::comphelper::getINT32(_xColumn->getPropertyValue(PROPERTY_TYPE)));
+ return pInfo;
+}
+
+void OQueryTableWindow::deleteUserData(void*& _pUserData)
+{
+ delete static_cast<OTableFieldInfo*>(_pUserData);
+ _pUserData = nullptr;
+}
+
+void OQueryTableWindow::OnEntryDoubleClicked(weld::TreeIter& rEntry)
+{
+ if (getTableView()->getDesignView()->getController().isReadOnly())
+ return;
+
+ weld::TreeView& rTreeView = m_xListBox->get_widget();
+ OTableFieldInfo* pInf = weld::fromId<OTableFieldInfo*>(rTreeView.get_id(rEntry));
+ OSL_ENSURE(pInf != nullptr, "OQueryTableWindow::OnEntryDoubleClicked : field doesn't have FieldInfo !");
+
+ // build up DragInfo
+ OTableFieldDescRef aInfo = new OTableFieldDesc(GetTableName(), rTreeView.get_text(rEntry));
+ aInfo->SetTabWindow(this);
+ aInfo->SetAlias(GetAliasName());
+ aInfo->SetFieldIndex(rTreeView.get_iter_index_in_parent(rEntry));
+ aInfo->SetDataType(pInf->GetDataType());
+
+ // and insert corresponding field
+ static_cast<OQueryTableView*>(getTableView())->InsertField(aInfo);
+}
+
+bool OQueryTableWindow::ExistsField(const OUString& strFieldName, OTableFieldDescRef const & rInfo)
+{
+ OSL_ENSURE(m_xListBox != nullptr, "OQueryTableWindow::ExistsField : doesn't have css::form::ListBox !");
+ OSL_ENSURE(rInfo.is(),"OQueryTableWindow::ExistsField: invalid argument for OTableFieldDescRef!");
+ Reference< XConnection> xConnection = getTableView()->getDesignView()->getController().getConnection();
+ bool bExists = false;
+ if(xConnection.is())
+ {
+ weld::TreeView& rTreeView = m_xListBox->get_widget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ bool bEntry = rTreeView.get_iter_first(*xEntry);
+ try
+ {
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+
+ while (bEntry)
+ {
+ if (bCase(strFieldName, rTreeView.get_text(*xEntry)))
+ {
+ OTableFieldInfo* pInf = weld::fromId<OTableFieldInfo*>(rTreeView.get_id(*xEntry));
+ assert(pInf && "OQueryTableWindow::ExistsField : field doesn't have FieldInfo !");
+
+ rInfo->SetTabWindow(this);
+ rInfo->SetField(strFieldName);
+ rInfo->SetTable(GetTableName());
+ rInfo->SetAlias(GetAliasName());
+ rInfo->SetFieldIndex(rTreeView.get_iter_index_in_parent(*xEntry));
+ rInfo->SetDataType(pInf->GetDataType());
+ bExists = true;
+ break;
+ }
+ bEntry = rTreeView.iter_next(*xEntry);
+ }
+ }
+ catch(SQLException&)
+ {
+ }
+ }
+
+ return bExists;
+}
+
+bool OQueryTableWindow::ExistsAVisitedConn() const
+{
+ return static_cast<const OQueryTableView*>(getTableView())->ExistsAVisitedConn(this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableWindow.hxx b/dbaccess/source/ui/querydesign/QTableWindow.hxx
new file mode 100644
index 000000000..72c698c83
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableWindow.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableWindow.hxx>
+#include "QTableWindowData.hxx"
+#include <TableFieldDescription.hxx>
+
+namespace dbaui
+{
+ class OQueryTableWindow : public OTableWindow
+ {
+ sal_Int32 m_nAliasNum;
+ OUString m_strInitialAlias;
+ public:
+ OQueryTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData );
+
+ OUString const & GetAliasName() const
+ {
+ return static_cast<OQueryTableWindowData*>(GetData().get())->GetAliasName();
+ }
+ void SetAliasName(const OUString& strNewAlias)
+ {
+ static_cast<OQueryTableWindowData*>(GetData().get())->SetAliasName(strNewAlias);
+ }
+
+ // late Constructor, the base class CREATES Listbox on first call
+ virtual bool Init() override;
+
+ bool ExistsField(const OUString& strFieldName, OTableFieldDescRef const & rInfo);
+ bool ExistsAVisitedConn() const;
+
+ virtual OUString GetName() const override { return GetWinName(); }
+
+ protected:
+
+ virtual void OnEntryDoubleClicked(weld::TreeIter& rEntry) override;
+ // is called from DoubleClickHdl of the ListBox
+ /** delete the user data with the equal type as created within createUserData
+ @param _pUserData
+ The user data store in the listbox entries. Created with a call to createUserData.
+ _pUserData may be <NULL/>.
+ */
+ virtual void deleteUserData(void*& _pUserData) override;
+
+ /** creates user information that will be append at the ListBoxentry
+ @param _xColumn
+ The corresponding column, can be <NULL/>.
+ @param _bPrimaryKey
+ <TRUE/> when the column belongs to the primary key
+ @return
+ the user data which will be append at the listbox entry, may be <NULL/>
+ */
+ virtual void* createUserData(const css::uno::Reference<
+ css::beans::XPropertySet>& _xColumn,
+ bool _bPrimaryKey) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableWindowData.cxx b/dbaccess/source/ui/querydesign/QTableWindowData.cxx
new file mode 100644
index 000000000..d8f2f2efd
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableWindowData.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "QTableWindowData.hxx"
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+
+OQueryTableWindowData::OQueryTableWindowData(const OUString& _rComposedName, const OUString& rTableName, const OUString& rTableAlias )
+ :OTableWindowData(nullptr,_rComposedName, rTableName, rTableAlias)
+{
+}
+
+OQueryTableWindowData::~OQueryTableWindowData()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QTableWindowData.hxx b/dbaccess/source/ui/querydesign/QTableWindowData.hxx
new file mode 100644
index 000000000..327dc27f1
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QTableWindowData.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableWindowData.hxx>
+
+
+namespace dbaui
+{
+ class OQueryTableWindowData : public OTableWindowData
+ {
+ public:
+ explicit OQueryTableWindowData(const OUString& _rComposedName, const OUString& rTableName, const OUString& rTableAlias);
+ virtual ~OQueryTableWindowData() override;
+
+ OUString const & GetAliasName() const { return GetWinName(); }
+ void SetAliasName(const OUString& rNewAlias) { SetWinName(rNewAlias); }
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx
new file mode 100644
index 000000000..dd641be1d
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "QueryTabConnUndoAction.hxx"
+
+namespace dbaui
+{
+ // OQueryAddTabConnUndoAction - Undo class for inserting a connection
+
+ class OQueryTableView;
+ class OQueryAddTabConnUndoAction : public OQueryTabConnUndoAction
+ {
+ public:
+ explicit OQueryAddTabConnUndoAction(OQueryTableView* pOwner);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ };
+
+ // OQueryDelTabConnUndoAction - Undo class for inserting a connection
+
+ class OQueryDelTabConnUndoAction : public OQueryTabConnUndoAction
+ {
+ public:
+ explicit OQueryDelTabConnUndoAction(OQueryTableView* pOwner);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx
new file mode 100644
index 000000000..13262f570
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <GeneralUndo.hxx>
+#include <strings.hrc>
+#include "SelectionBrowseBox.hxx"
+#include <osl/diagnose.h>
+
+namespace dbaui
+{
+ // OQueryDesignFieldUndoAct - Basisclass for undo's in the fieldlist of a query design
+
+ class OQueryDesignFieldUndoAct : public OCommentUndoAction
+ {
+ protected:
+ VclPtr<OSelectionBrowseBox> pOwner;
+ sal_uInt16 m_nColumnPosition;
+
+ virtual void Undo() override = 0;
+ virtual void Redo() override = 0;
+
+ public:
+ OQueryDesignFieldUndoAct(OSelectionBrowseBox* pSelBrwBox, TranslateId pCommentID);
+ virtual ~OQueryDesignFieldUndoAct() override;
+
+ void SetColumnPosition(sal_uInt16 _nColumnPosition)
+ {
+ m_nColumnPosition = _nColumnPosition;
+ OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!");
+ OSL_ENSURE(m_nColumnPosition < pOwner->GetColumnCount(),"Position outside the column count!");
+ }
+ };
+
+ // OTabFieldCellModifiedUndoAct - undo class to change a line of the column description
+
+ class OTabFieldCellModifiedUndoAct final : public OQueryDesignFieldUndoAct
+ {
+ OUString m_strNextCellContents;
+ sal_Int32 m_nCellIndex;
+
+ public:
+ explicit OTabFieldCellModifiedUndoAct(OSelectionBrowseBox* pSelBrwBox)
+ : OQueryDesignFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_MODIFY_CELL)
+ ,m_nCellIndex(BROWSER_INVALIDID){ }
+
+ void SetCellContents(const OUString& str) { m_strNextCellContents = str; }
+ void SetCellIndex(sal_Int32 nIndex) { m_nCellIndex = nIndex; }
+
+ virtual void Undo() override;
+ virtual void Redo() override { Undo(); }
+ };
+
+ // OTabFieldSizedUndoAct - undo class to change the column width
+
+ class OTabFieldSizedUndoAct final : public OQueryDesignFieldUndoAct
+ {
+ tools::Long m_nNextWidth;
+
+ public:
+ explicit OTabFieldSizedUndoAct(OSelectionBrowseBox* pSelBrwBox) : OQueryDesignFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_SIZE_COLUMN), m_nNextWidth(0) { }
+
+ void SetOriginalWidth(tools::Long nWidth) { m_nNextWidth = nWidth; }
+
+ virtual void Undo() override;
+ virtual void Redo() override { Undo(); }
+ };
+
+ // OTabFieldUndoAct - base class for undos in the fieldlist of a query design, which are used to change complete field descriptions
+
+ class OTabFieldUndoAct : public OQueryDesignFieldUndoAct
+ {
+ protected:
+ OTableFieldDescRef pDescr; // the deleted column description
+
+ public:
+ OTabFieldUndoAct(OSelectionBrowseBox* pSelBrwBox, TranslateId pCommentID) : OQueryDesignFieldUndoAct(pSelBrwBox, pCommentID) { }
+
+ void SetTabFieldDescr(OTableFieldDescRef const & pDescription) { pDescr = pDescription; }
+ };
+
+ // OTabFieldDelUndoAct - undo class to delete a field
+
+ class OTabFieldDelUndoAct : public OTabFieldUndoAct
+ {
+ protected:
+ virtual void Undo() override { pOwner->EnterUndoMode();pOwner->InsertColumn(pDescr, m_nColumnPosition);pOwner->LeaveUndoMode(); }
+ virtual void Redo() override { pOwner->EnterUndoMode();pOwner->RemoveColumn(pDescr->GetColumnId());pOwner->LeaveUndoMode(); }
+
+ public:
+ explicit OTabFieldDelUndoAct(OSelectionBrowseBox* pSelBrwBox) : OTabFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_TABFIELDDELETE) { }
+ };
+
+ // OTabFieldCreateUndoAct - undo class for creating a field
+
+ class OTabFieldCreateUndoAct : public OTabFieldUndoAct
+ {
+ protected:
+ virtual void Undo() override { pOwner->EnterUndoMode();pOwner->RemoveColumn(pDescr->GetColumnId());pOwner->LeaveUndoMode();}
+ virtual void Redo() override { pOwner->EnterUndoMode();pOwner->InsertColumn(pDescr, m_nColumnPosition);pOwner->LeaveUndoMode();}
+
+ public:
+ explicit OTabFieldCreateUndoAct(OSelectionBrowseBox* pSelBrwBox) : OTabFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_TABFIELDCREATE) { }
+ };
+
+ // OTabFieldMovedUndoAct - Undo class when a field was moved inside the selection
+
+ class OTabFieldMovedUndoAct : public OTabFieldUndoAct
+ {
+ protected:
+ virtual void Undo() override;
+ virtual void Redo() override
+ {
+ Undo();
+ }
+
+ public:
+ explicit OTabFieldMovedUndoAct(OSelectionBrowseBox* pSelBrwBox) : OTabFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_TABFIELDMOVED) { }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx
new file mode 100644
index 000000000..8a8742393
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <GeneralUndo.hxx>
+#include <JoinTableView.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace dbaui
+{
+ // OQueryDesignUndoAction - undo base class for actions in graphical query design (without field list)
+ class OJoinTableView;
+ class OQueryDesignUndoAction : public OCommentUndoAction
+ {
+ protected:
+ VclPtr<OJoinTableView> m_pOwner; // in this container it all happens
+
+ public:
+ OQueryDesignUndoAction(OJoinTableView* pOwner, TranslateId pCommentID) : OCommentUndoAction(pCommentID), m_pOwner(pOwner) { }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryDesignView.cxx b/dbaccess/source/ui/querydesign/QueryDesignView.cxx
new file mode 100644
index 000000000..f5e4288e9
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryDesignView.cxx
@@ -0,0 +1,3441 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <QueryDesignView.hxx>
+#include <QueryTableView.hxx>
+#include "QTableWindow.hxx"
+#include <querycontroller.hxx>
+#include <sqlbison.hxx>
+#include <vcl/split.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <browserids.hxx>
+#include "SelectionBrowseBox.hxx"
+#include <strings.hrc>
+#include <strings.hxx>
+#include <comphelper/string.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <connectivity/PColumn.hxx>
+#include "QTableConnection.hxx"
+#include <ConnectionLineData.hxx>
+#include "QTableConnectionData.hxx"
+#include <core_resource.hxx>
+#include <UITools.hxx>
+#include <querycontainerwindow.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <memory>
+#include <set>
+#include <string_view>
+
+using namespace ::dbaui;
+using namespace ::utl;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+// here we define our functions used in the anonymous namespace to get our header file smaller
+// please look at the book LargeScale C++ to know why
+namespace
+{
+ const char C_AND[] = " AND ";
+ const char C_OR[] = " OR ";
+
+ bool InsertJoin( const OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode *pNode);
+
+ SqlParseError InstallFields(OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode* pNode,
+ OJoinTableView::OTableWindowMap* pTabList );
+
+ SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode* pSelectRoot );
+
+ SqlParseError GetHavingCriteria(OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode* pSelectRoot,
+ sal_uInt16& rLevel );
+
+ SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode* pParseRoot );
+
+ SqlParseError AddFunctionCondition(OQueryDesignView const * _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ const sal_uInt16 nLevel,
+ bool bHaving,
+ bool _bAddOrOnOneLine);
+
+ OUString quoteTableAlias(bool _bQuote, const OUString& _sAliasName, const OUString& _sQuote)
+ {
+ OUString sRet;
+ if ( _bQuote && !_sAliasName.isEmpty() )
+ {
+ sRet = ::dbtools::quoteName(_sQuote,_sAliasName) + ".";
+ }
+ return sRet;
+ }
+ OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef)
+ {
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
+ OUString sTableRange;
+ if ( _pTableRef )
+ {
+ sTableRange = ::connectivity::OSQLParseNode::getTableRange(_pTableRef);
+ if ( sTableRange.isEmpty() )
+ _pTableRef->parseNodeToStr(sTableRange,xConnection,nullptr,false,false);
+ }
+ return sTableRange;
+ }
+ void insertConnection(const OQueryDesignView* _pView,const EJoinType& _eJoinType, const OTableFieldDescRef& _aDragLeft, const OTableFieldDescRef& _aDragRight, bool _bNatural = false)
+ {
+ OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
+ OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>( pTableView->GetTabConn(static_cast<OTableWindow*>(_aDragLeft->GetTabWindow()),static_cast<OTableWindow*>(_aDragRight->GetTabWindow()),true));
+
+ if ( !pConn )
+ {
+ auto xInfoData = std::make_shared<OQueryTableConnectionData>();
+ xInfoData->InitFromDrag(_aDragLeft, _aDragRight);
+ xInfoData->SetJoinType(_eJoinType);
+
+ if ( _bNatural )
+ {
+ xInfoData->ResetConnLines();
+ xInfoData->setNatural(_bNatural);
+ try
+ {
+ Reference<XNameAccess> xReferencedTableColumns(xInfoData->getReferencedTable()->getColumns());
+ Sequence< OUString> aSeq = xInfoData->getReferencingTable()->getColumns()->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( xReferencedTableColumns->hasByName(*pIter) )
+ xInfoData->AppendConnLine(*pIter,*pIter);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ ScopedVclPtrInstance< OQueryTableConnection > aInfo(pTableView, xInfoData);
+ // Because OQueryTableConnection never takes ownership of the data passed to it, but only remembers the pointer,
+ // this pointer to a local variable is not critical, as xInfoData and aInfo have the same lifetime
+ pTableView->NotifyTabConnection( *aInfo );
+ }
+ else
+ {
+ OUString aSourceFieldName(_aDragLeft->GetField());
+ OUString aDestFieldName(_aDragRight->GetField());
+ // the connection could point on the other side
+ if(pConn->GetSourceWin() == _aDragRight->GetTabWindow())
+ {
+ OUString aTmp(aSourceFieldName);
+ aSourceFieldName = aDestFieldName;
+ aDestFieldName = aTmp;
+ }
+ pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName);
+ pConn->UpdateLineList();
+ // Modified-Flag
+ // SetModified();
+ // and redraw
+ pConn->RecalcLines();
+ // for the following Invalidate, the new Connection must first be able
+ // to determine its BoundingRect
+ pConn->InvalidateConnection();
+ }
+ }
+ OUString ParseCondition( OQueryController& rController
+ ,const ::connectivity::OSQLParseNode* pCondition
+ ,const OUString& _sDecimal
+ ,const css::lang::Locale& _rLocale
+ ,sal_uInt32 _nStartIndex)
+ {
+ OUString aCondition;
+ Reference< XConnection> xConnection = rController.getConnection();
+ if ( xConnection.is() )
+ {
+ sal_uInt32 nCount = pCondition->count();
+ for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i)
+ pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
+ xConnection,
+ rController.getNumberFormatter(),
+ _rLocale,
+ _sDecimal,
+ &rController.getParser().getContext());
+ }
+ return aCondition;
+ }
+ SqlParseError FillOuterJoins(OQueryDesignView const * _pView,
+ const ::connectivity::OSQLParseNode* pTableRefList)
+ {
+ SqlParseError eErrorCode = eOk;
+ sal_uInt32 nCount = pTableRefList->count();
+ bool bError = false;
+ for (sal_uInt32 i=0; !bError && i < nCount; ++i)
+ {
+ const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i);
+ const ::connectivity::OSQLParseNode* pJoinNode = nullptr;
+
+ if ( SQL_ISRULE( pParseNode, qualified_join ) || SQL_ISRULE( pParseNode, joined_table ) || SQL_ISRULE( pParseNode, cross_union ) )
+ pJoinNode = pParseNode;
+ else if( SQL_ISRULE(pParseNode,table_ref)
+ && pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
+ pJoinNode = pParseNode->getChild(2);
+
+ if ( pJoinNode )
+ {
+ if ( !InsertJoin(_pView,pJoinNode) )
+ bError = true;
+ }
+ }
+ // check if error occurred
+ if ( bError )
+ eErrorCode = eIllegalJoin;
+
+ return eErrorCode;
+ }
+
+ /** FillDragInfo fills the field description out of the table
+ */
+ SqlParseError FillDragInfo( const OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode* pColumnRef,
+ OTableFieldDescRef const & _rDragInfo)
+ {
+ SqlParseError eErrorCode = eOk;
+
+ bool bErg = false;
+
+ OUString aTableRange,aColumnName;
+ ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
+ rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );
+
+ if ( !aTableRange.isEmpty() )
+ {
+ OQueryTableWindow* pSTW = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( aTableRange );
+ bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) );
+ }
+ if ( !bErg )
+ {
+ sal_uInt16 nCntAccount;
+ bErg = static_cast<OQueryTableView*>(_pView->getTableView())->FindTableFromField(aColumnName, _rDragInfo, nCntAccount);
+ if ( !bErg )
+ bErg = _pView->HasFieldByAliasName(aColumnName, _rDragInfo);
+ }
+ if ( !bErg )
+ {
+ eErrorCode = eColumnNotFound;
+ OUString sError(DBA_RES(STR_QRY_COLUMN_NOT_FOUND));
+ sError = sError.replaceFirst("$name$",aColumnName);
+ _pView->getController().appendError( sError );
+
+ try
+ {
+ Reference<XDatabaseMetaData> xMeta = _pView->getController().getConnection()->getMetaData();
+ if ( xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() )
+ _pView->getController().appendError(DBA_RES(STR_QRY_CHECK_CASESENSITIVE));
+ }
+ catch(Exception&)
+ {
+ }
+ }
+
+ return eErrorCode;
+ }
+ OUString BuildJoinCriteria( const Reference< XConnection>& _xConnection,
+ const OConnectionLineDataVec* pLineDataList,
+ const OQueryTableConnectionData* pData)
+ {
+ OUStringBuffer aCondition;
+ if ( _xConnection.is() )
+ {
+ try
+ {
+ const Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
+ const OUString aQuote = xMetaData->getIdentifierQuoteString();
+
+ for (auto const& lineData : *pLineDataList)
+ {
+ if(!aCondition.isEmpty())
+ aCondition.append(C_AND);
+ aCondition.append(quoteTableAlias(true,pData->GetAliasName(JTCS_FROM),aQuote));
+ aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_FROM) ));
+ aCondition.append(" = ");
+ aCondition.append(quoteTableAlias(true,pData->GetAliasName(JTCS_TO),aQuote));
+ aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_TO) ));
+ }
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("Failure while building Join criteria!");
+ }
+ }
+
+ return aCondition.makeStringAndClear();
+ }
+ /** JoinCycle looks for a join cycle and append it to the string
+ @param _xConnection the connection
+ @param _pEntryConn the table connection which holds the data
+ @param _pEntryTabTo the corresponding table window
+ @param _rJoin the String which will contain the resulting string
+ */
+ void JoinCycle( const Reference< XConnection>& _xConnection,
+ OQueryTableConnection* _pEntryConn,
+ const OQueryTableWindow* _pEntryTabTo,
+ OUString& _rJoin )
+ {
+ OSL_ENSURE(_pEntryConn,"TableConnection can not be null!");
+
+ OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get());
+ if ( !(pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn()) )
+ return;
+
+ bool bBrace = false;
+ if(_rJoin.endsWith(")"))
+ {
+ bBrace = true;
+ _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1, u" ");
+ }
+ _rJoin += C_AND + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
+ if(bBrace)
+ _rJoin += ")";
+ _pEntryConn->SetVisited(true);
+ }
+ OUString BuildTable( const Reference< XConnection>& _xConnection,
+ const OQueryTableWindow* pEntryTab,
+ bool _bForce = false
+ )
+ {
+ OUString aDBName(pEntryTab->GetComposedName());
+
+ if( _xConnection.is() )
+ {
+ try
+ {
+ Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
+
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents( xMetaData, aDBName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
+ OUString aTableListStr = ::dbtools::composeTableNameForSelect( _xConnection, sCatalog, sSchema, sTable );
+
+ OUString aQuote = xMetaData->getIdentifierQuoteString();
+ if ( _bForce || isAppendTableAliasEnabled( _xConnection ) || pEntryTab->GetAliasName() != aDBName )
+ {
+ aTableListStr += " ";
+ if ( generateAsBeforeTableAlias( _xConnection ) )
+ aTableListStr += "AS ";
+ aTableListStr += ::dbtools::quoteName( aQuote, pEntryTab->GetAliasName() );
+ }
+ aDBName = aTableListStr;
+ }
+ catch(const SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ return aDBName;
+ }
+ OUString BuildJoin( const Reference< XConnection>& _xConnection,
+ const OUString& rLh,
+ std::u16string_view rRh,
+ const OQueryTableConnectionData* pData)
+ {
+
+ OUString aErg(rLh);
+ if ( pData->isNatural() && pData->GetJoinType() != CROSS_JOIN )
+ aErg += " NATURAL ";
+ switch(pData->GetJoinType())
+ {
+ case LEFT_JOIN:
+ aErg += " LEFT OUTER ";
+ break;
+ case RIGHT_JOIN:
+ aErg += " RIGHT OUTER ";
+ break;
+ case CROSS_JOIN:
+ OSL_ENSURE(!pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
+ aErg += " CROSS ";
+ break;
+ case INNER_JOIN:
+ OSL_ENSURE(pData->isNatural(),"OQueryDesignView::BuildJoin: This should not happen!");
+ aErg += " INNER ";
+ break;
+ default:
+ aErg += " FULL OUTER ";
+ break;
+ }
+ aErg += OUString::Concat("JOIN ") + rRh;
+ if ( CROSS_JOIN != pData->GetJoinType() && !pData->isNatural() )
+ {
+ aErg += " ON " + BuildJoinCriteria(_xConnection,&pData->GetConnLineDataList(),pData);
+ }
+
+ return aErg;
+ }
+ OUString BuildJoin( const Reference< XConnection>& _xConnection,
+ const OQueryTableWindow* pLh,
+ const OQueryTableWindow* pRh,
+ const OQueryTableConnectionData* pData
+ )
+ {
+ bool bForce = pData->GetJoinType() == CROSS_JOIN || pData->isNatural();
+ return BuildJoin(_xConnection,BuildTable(_xConnection,pLh,bForce),BuildTable(_xConnection,pRh,bForce),pData);
+ }
+ OUString BuildJoin( const Reference< XConnection>& _xConnection,
+ const OUString &rLh,
+ const OQueryTableWindow* pRh,
+ const OQueryTableConnectionData* pData
+ )
+ {
+ return BuildJoin(_xConnection,rLh,BuildTable(_xConnection,pRh),pData);
+ }
+ OUString BuildJoin( const Reference< XConnection>& _xConnection,
+ const OQueryTableWindow* pLh,
+ const OUString &rRh,
+ const OQueryTableConnectionData* pData
+ )
+ {
+ // strict ANSI SQL:
+ // - does not support any bracketing of JOINS
+ // - supports nested joins only in the LEFT HAND SIDE
+ // In this case, we are trying to build a join with a nested join
+ // in the right hand side.
+ // So switch the direction of the join and both hand sides.
+ OQueryTableConnectionData data(*pData);
+ switch (data.GetJoinType())
+ {
+ case LEFT_JOIN:
+ data.SetJoinType(RIGHT_JOIN);
+ break;
+ case RIGHT_JOIN:
+ data.SetJoinType(LEFT_JOIN);
+ break;
+ default:
+ // the other join types are symmetric, so nothing to change
+ break;
+ }
+ return BuildJoin(_xConnection, rRh, BuildTable(_xConnection,pLh), &data);
+ }
+ void addConnectionTableNames( const Reference< XConnection>& _xConnection,
+ const OQueryTableConnection* const pEntryConn,
+ std::set<OUString> &_rTableNames )
+ {
+ // insert tables into table list to avoid double entries
+ const OQueryTableWindow* const pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
+ const OQueryTableWindow* const pEntryTabTo = static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin());
+ _rTableNames.insert(BuildTable(_xConnection,pEntryTabFrom));
+ _rTableNames.insert(BuildTable(_xConnection,pEntryTabTo));
+ }
+ void GetNextJoin( const Reference< XConnection>& _xConnection,
+ OQueryTableConnection* pEntryConn,
+ OQueryTableWindow const * pEntryTabTo,
+ OUString &aJoin,
+ std::set<OUString> &_rTableNames)
+ {
+ OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
+ if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
+ return;
+
+ if(aJoin.isEmpty())
+ {
+ addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
+ OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
+ aJoin = BuildJoin(_xConnection,pEntryTabFrom,pEntryTabTo,pEntryConnData);
+ }
+ else if(pEntryTabTo == pEntryConn->GetDestWin())
+ {
+ addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
+ aJoin = BuildJoin(_xConnection,aJoin,pEntryTabTo,pEntryConnData);
+ }
+ else if(pEntryTabTo == pEntryConn->GetSourceWin())
+ {
+ addConnectionTableNames(_xConnection, pEntryConn, _rTableNames);
+ aJoin = BuildJoin(_xConnection,pEntryTabTo,aJoin,pEntryConnData);
+ }
+
+ pEntryConn->SetVisited(true);
+
+ // first search for the "to" window
+ const auto& rConnections = pEntryConn->GetParent()->getTableConnections();
+ bool bFound = false;
+ for (auto const& connection : rConnections)
+ {
+ OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
+ if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo))
+ {
+ OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
+ // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
+ JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
+ if(!pNext->IsVisited())
+ GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
+ bFound = true;
+ }
+ }
+
+ // when nothing found look for the "from" window
+ if(bFound)
+ return;
+
+ OQueryTableWindow* pEntryTabFrom = static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin());
+ for (auto const& connection : rConnections)
+ {
+ OQueryTableConnection* pNext = static_cast<OQueryTableConnection*>(connection.get());
+ if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom))
+ {
+ OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast<OQueryTableWindow*>(pNext->GetDestWin()) : static_cast<OQueryTableWindow*>(pNext->GetSourceWin());
+ // exists there a connection to a OQueryTableWindow that holds a connection that has been already visited
+ JoinCycle(_xConnection,pNext,pEntryTab,aJoin);
+ if(!pNext->IsVisited())
+ GetNextJoin(_xConnection, pNext, pEntryTab, aJoin, _rTableNames);
+ }
+ }
+ }
+ SqlParseError InsertJoinConnection( const OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode *pNode,
+ const EJoinType& _eJoinType,
+ const ::connectivity::OSQLParseNode *pLeftTable,
+ const ::connectivity::OSQLParseNode *pRightTable)
+ {
+ SqlParseError eErrorCode = eOk;
+ if (pNode->count() == 3 && // statement between brackets
+ SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pNode->getChild(2),")"))
+ {
+ eErrorCode = InsertJoinConnection(_pView,pNode->getChild(1), _eJoinType,pLeftTable,pRightTable);
+ }
+ else if (SQL_ISRULEOR2(pNode,search_condition,boolean_term) && // AND/OR-joints:
+ pNode->count() == 3)
+ {
+ // only allow AND joints
+ if (!SQL_ISTOKEN(pNode->getChild(1),AND))
+ eErrorCode = eIllegalJoinCondition;
+ else if ( eOk == (eErrorCode = InsertJoinConnection(_pView,pNode->getChild(0), _eJoinType,pLeftTable,pRightTable)) )
+ eErrorCode = InsertJoinConnection(_pView,pNode->getChild(2), _eJoinType,pLeftTable,pRightTable);
+ }
+ else if (SQL_ISRULE(pNode,comparison_predicate))
+ {
+ // only the comparison of columns is allowed
+ OSL_ENSURE(pNode->count() == 3,"OQueryDesignView::InsertJoinConnection: Error in Parse Tree");
+ if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
+ SQL_ISRULE(pNode->getChild(2),column_ref) &&
+ pNode->getChild(1)->getNodeType() == SQLNodeType::Equal))
+ {
+ OUString sError(DBA_RES(STR_QRY_JOIN_COLUMN_COMPARE));
+ _pView->getController().appendError( sError );
+ return eIllegalJoin;
+ }
+
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ OTableFieldDescRef aDragRight = new OTableFieldDesc();
+ eErrorCode = FillDragInfo(_pView,pNode->getChild(0),aDragLeft);
+ if ( eOk != eErrorCode )
+ return eErrorCode;
+ eErrorCode = FillDragInfo(_pView,pNode->getChild(2),aDragRight);
+ if ( eOk != eErrorCode )
+ return eErrorCode;
+
+ if ( pLeftTable )
+ {
+ OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pLeftTable->getByRule(OSQLParseNode::table_ref) ));
+ if ( pLeftWindow == aDragLeft->GetTabWindow() )
+ insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
+ else
+ insertConnection(_pView,_eJoinType,aDragRight,aDragLeft);
+ }
+ else
+ insertConnection(_pView,_eJoinType,aDragLeft,aDragRight);
+ }
+ else
+ eErrorCode = eIllegalJoin;
+ return eErrorCode;
+ }
+ bool GetInnerJoinCriteria( const OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode *pCondition)
+ {
+ return InsertJoinConnection(_pView,pCondition, INNER_JOIN,nullptr,nullptr) != eOk;
+ }
+ OUString GenerateSelectList( const OQueryDesignView* _pView,
+ OTableFields& _rFieldList,
+ bool bAlias)
+ {
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
+ if ( !xConnection.is() )
+ return OUString();
+
+ OUStringBuffer aTmpStr,aFieldListStr;
+
+ bool bAsterisk = false;
+ int nVis = 0;
+ for (auto const& field : _rFieldList)
+ {
+ if ( field->IsVisible() )
+ {
+ if ( field->GetField().toChar() == '*' )
+ bAsterisk = true;
+ ++nVis;
+ }
+ }
+ if(nVis == 1)
+ bAsterisk = false;
+
+ try
+ {
+ const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ const OUString aQuote = xMetaData->getIdentifierQuoteString();
+
+ OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap();
+
+ for (auto const& field : _rFieldList)
+ {
+ OUString rFieldName = field->GetField();
+ if ( !rFieldName.isEmpty() && field->IsVisible() )
+ {
+ aTmpStr = "";
+ const OUString rAlias = field->GetAlias();
+ const OUString rFieldAlias = field->GetFieldAlias();
+
+ aTmpStr.append(quoteTableAlias((bAlias || bAsterisk),rAlias,aQuote));
+
+ // if we have a none numeric field, the table alias could be in the name
+ // otherwise we are not allowed to do this (e.g. 0.1 * PRICE )
+ if ( !field->isOtherFunction() )
+ {
+ // we have to look if we have alias.* here but before we have to check if the column doesn't already exist
+ OTableFieldDescRef aInfo = new OTableFieldDesc();
+ for (auto const& table : rTabList)
+ {
+ OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
+
+ if ( pTabWin->ExistsField( rFieldName, aInfo ) )
+ {
+ rFieldName = aInfo->GetField();
+ break;
+ }
+ }
+ if ( ( rFieldName.toChar() != '*' ) && ( rFieldName.indexOf( aQuote ) == -1 ) )
+ {
+ OSL_ENSURE(!field->GetTable().isEmpty(),"No table field name!");
+ aTmpStr.append(::dbtools::quoteName(aQuote, rFieldName));
+ }
+ else
+ aTmpStr.append(rFieldName);
+ }
+ else
+ aTmpStr.append(rFieldName);
+
+ if ( field->isAggregateFunction() )
+ {
+ OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name must not be empty! ;-(");
+ OUStringBuffer aTmpStr2( field->GetFunction() + "(" + aTmpStr + ")");
+ aTmpStr = aTmpStr2;
+ }
+
+ if (!rFieldAlias.isEmpty() &&
+ (rFieldName.toChar() != '*' ||
+ field->isNumericOrAggregateFunction() ||
+ field->isOtherFunction()))
+ {
+ aTmpStr.append(" AS ");
+ aTmpStr.append(::dbtools::quoteName(aQuote, rFieldAlias));
+ }
+ aFieldListStr.append(aTmpStr);
+ aTmpStr.setLength(0);
+ aFieldListStr.append(", ");
+ }
+ }
+ if(!aFieldListStr.isEmpty())
+ aFieldListStr.setLength(aFieldListStr.getLength()-2);
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("Failure while building select list!");
+ }
+ return aFieldListStr.makeStringAndClear();
+ }
+ bool GenerateCriterias( OQueryDesignView const * _pView,
+ OUStringBuffer& rRetStr,
+ OUStringBuffer& rHavingStr,
+ OTableFields& _rFieldList,
+ bool bMulti )
+ {
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(_pView->getController()).getConnection();
+ if(!xConnection.is())
+ return false;
+
+ OUString aFieldName,aCriteria,aWhereStr,aHavingStr,aWork/*,aOrderStr*/;
+ // print line by line joined with AND
+ sal_uInt16 nMaxCriteria = 0;
+ for (auto const& field : _rFieldList)
+ {
+ nMaxCriteria = std::max<sal_uInt16>(nMaxCriteria,static_cast<sal_uInt16>(field->GetCriteria().size()));
+ }
+ try
+ {
+ const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ const OUString aQuote = xMetaData->getIdentifierQuoteString();
+ const IParseContext& rContext = static_cast<OQueryController&>(_pView->getController()).getParser().getContext();
+ // * must not contain a filter : have I already shown the correct warning ?
+ bool bCritsOnAsteriskWarning = false; // ** TMFS **
+
+ for (sal_uInt16 i=0 ; i < nMaxCriteria ; i++)
+ {
+ aHavingStr.clear();
+ aWhereStr.clear();
+
+ for (auto const& field : _rFieldList)
+ {
+ aFieldName = field->GetField();
+
+ if (aFieldName.isEmpty())
+ continue;
+ aCriteria = field->GetCriteria( i );
+ if ( !aCriteria.isEmpty() )
+ {
+ // * is not allowed to contain any filter, only when used in combination an aggregate function
+ if ( aFieldName.toChar() == '*' && field->isNoneFunction() )
+ {
+ // only show the messagebox the first time
+ if (!bCritsOnAsteriskWarning)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ DBA_RES(STR_QRY_CRITERIA_ON_ASTERISK)));
+ xBox->run();
+ }
+ bCritsOnAsteriskWarning = true;
+ continue;
+ }
+ aWork = quoteTableAlias(bMulti,field->GetAlias(),aQuote);
+
+ if ( (field->GetFunctionType() & (FKT_OTHER|FKT_NUMERIC)) || (aFieldName.toChar() == '*') )
+ aWork += aFieldName;
+ else
+ aWork += ::dbtools::quoteName(aQuote, aFieldName);
+
+ if ( field->isAggregateFunction() || field->IsGroupBy() )
+ {
+ if (aHavingStr.isEmpty()) // no more criteria
+ aHavingStr += "("; // bracket
+ else
+ aHavingStr += C_AND;
+
+ if ( field->isAggregateFunction() )
+ {
+ OSL_ENSURE(!field->GetFunction().isEmpty(),"No function name for aggregate given!");
+ aHavingStr += field->GetFunction() + "(" + aWork + ")"; // bracket
+ }
+ else
+ aHavingStr += aWork;
+
+ OUString aErrorMsg;
+ Reference<XPropertySet> xColumn;
+ std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn));
+ if (pParseNode)
+ {
+ if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*')))
+ pParseNode->replaceNodeValue(field->GetAlias(),aFieldName);
+ OUString sHavingStr = aHavingStr;
+
+ sal_uInt32 nCount = pParseNode->count();
+ for( sal_uInt32 node = 1 ; node < nCount ; ++node)
+ pParseNode->getChild(node)->parseNodeToStr( sHavingStr,
+ xConnection,
+ &rContext,
+ false,
+ !field->isOtherFunction());
+ aHavingStr = sHavingStr;
+ }
+ else
+ aHavingStr += aCriteria;
+ }
+ else
+ {
+ if ( aWhereStr.isEmpty() ) // no more criteria
+ aWhereStr += "("; // bracket
+ else
+ aWhereStr += C_AND;
+
+ aWhereStr += " ";
+ // aCriteria could have some German numbers so I have to be sure here
+ OUString aErrorMsg;
+ Reference<XPropertySet> xColumn;
+ std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode( _pView->getPredicateTreeFromEntry(field,aCriteria,aErrorMsg,xColumn));
+ if (pParseNode)
+ {
+ if (bMulti && !(field->isOtherFunction() || (aFieldName.toChar() == '*')))
+ pParseNode->replaceNodeValue(field->GetAlias(),aFieldName);
+ OUString aWhere = aWhereStr;
+ pParseNode->parseNodeToStr( aWhere,
+ xConnection,
+ &rContext,
+ false,
+ !field->isOtherFunction() );
+ aWhereStr = aWhere;
+ }
+ else
+ {
+ aWhereStr += aWork + "=" + aCriteria;
+ }
+ }
+ }
+ // only once for each field
+ else if ( !i && field->isCondition() )
+ {
+ if (aWhereStr.isEmpty()) // no more criteria
+ aWhereStr += "("; // bracket
+ else
+ aWhereStr += C_AND;
+ aWhereStr += field->GetField();
+ }
+ }
+ if (!aWhereStr.isEmpty())
+ {
+ aWhereStr += ")"; // close bracket for the AND branch
+ if (!rRetStr.isEmpty()) // are there conditions on the field?
+ rRetStr.append(C_OR);
+ else // open bracket for the OR branch
+ rRetStr.append('(');
+ rRetStr.append(aWhereStr);
+ }
+ if (!aHavingStr.isEmpty())
+ {
+ aHavingStr += ")"; // close bracket for the AND branch
+ if (!rHavingStr.isEmpty()) // are there conditions on the field?
+ rHavingStr.append(C_OR);
+ else // Open bracket for the OR branch
+ rHavingStr.append('(');
+ rHavingStr.append(aHavingStr);
+ }
+ }
+
+ if (!rRetStr.isEmpty())
+ rRetStr.append(')'); // close bracket for the OR branch
+ if (!rHavingStr.isEmpty())
+ rHavingStr.append(')'); // close bracket for the OR branch
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("Failure while building where clause!");
+ }
+ return true;
+ }
+ SqlParseError GenerateOrder( OQueryDesignView const * _pView,
+ OTableFields& _rFieldList,
+ bool bMulti,
+ OUString& _rsRet)
+ {
+ const OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+ const Reference< XConnection>& xConnection = rController.getConnection();
+ if ( !xConnection.is() )
+ return eNoConnection;
+
+ SqlParseError eErrorCode = eOk;
+
+ OUString aColumnName;
+ OUString aWorkStr;
+ try
+ {
+ const bool bColumnAliasInOrderBy = rController.getSdbMetaData().supportsColumnAliasInOrderBy();
+ Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ OUString aQuote = xMetaData->getIdentifierQuoteString();
+ // * must not contain filter - have I already shown the warning?
+ bool bCritsOnAsteriskWarning = false; // ** TMFS **
+ for (auto const& field : _rFieldList)
+ {
+ EOrderDir eOrder = field->GetOrderDir();
+ // only create a sort expression when the table name and the sort criteria are defined
+ // otherwise they will be built in GenerateCriteria
+ if ( eOrder != ORDER_NONE )
+ {
+ aColumnName = field->GetField();
+ if(aColumnName.toChar() == '*')
+ {
+ // only show the MessageBox the first time
+ if (!bCritsOnAsteriskWarning)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ DBA_RES(STR_QRY_ORDERBY_ON_ASTERISK)));
+ xBox->run();
+ }
+ bCritsOnAsteriskWarning = true;
+ continue;
+ }
+
+ if ( bColumnAliasInOrderBy && !field->GetFieldAlias().isEmpty() )
+ {
+ aWorkStr += ::dbtools::quoteName(aQuote, field->GetFieldAlias());
+ }
+ else if ( field->isNumericOrAggregateFunction() )
+ {
+ OSL_ENSURE(!field->GetFunction().isEmpty(),"Function name cannot be empty! ;-(");
+ aWorkStr += field->GetFunction() + "("
+ + quoteTableAlias(
+ bMulti, field->GetAlias(), aQuote);
+ // only quote column name when we don't have a numeric
+ if ( field->isNumeric() )
+ aWorkStr += aColumnName;
+ else
+ aWorkStr += ::dbtools::quoteName(aQuote, aColumnName);
+
+ aWorkStr += ")";
+ }
+ else if ( field->isOtherFunction() )
+ {
+ aWorkStr += aColumnName;
+ }
+ else
+ {
+ aWorkStr += quoteTableAlias(bMulti,field->GetAlias(),aQuote) + ::dbtools::quoteName(aQuote, aColumnName);
+ }
+ aWorkStr += OUString::Concat(" ") + o3tl::getToken( u";ASC;DESC", static_cast<sal_uInt16>(eOrder), ';' ) + ",";
+ }
+ }
+
+ {
+ OUString sTemp(comphelper::string::stripEnd(aWorkStr, ','));
+ aWorkStr = sTemp;
+ }
+
+ if ( !aWorkStr.isEmpty() )
+ {
+ const sal_Int32 nMaxOrder = xMetaData->getMaxColumnsInOrderBy();
+ if ( nMaxOrder && nMaxOrder < comphelper::string::getTokenCount(aWorkStr, ',') )
+ eErrorCode = eStatementTooLong;
+ else
+ {
+ _rsRet = " ORDER BY " + aWorkStr;
+ }
+ }
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("Failure while building group by!");
+ }
+
+ return eErrorCode;
+ }
+
+ void GenerateInnerJoinCriterias(const Reference< XConnection>& _xConnection,
+ OUString& _rJoinCrit,
+ const std::vector<VclPtr<OTableConnection> >& _rConnList)
+ {
+ for (auto const& connection : _rConnList)
+ {
+ const OQueryTableConnection* pEntryConn = static_cast<const OQueryTableConnection*>(connection.get());
+ OQueryTableConnectionData* pEntryConnData = static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get());
+ if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() )
+ {
+ if(!_rJoinCrit.isEmpty())
+ _rJoinCrit += C_AND;
+ _rJoinCrit += BuildJoinCriteria(_xConnection,&pEntryConnData->GetConnLineDataList(),pEntryConnData);
+ }
+ }
+ }
+ void searchAndAppendName(const Reference< XConnection>& _xConnection,
+ const OQueryTableWindow* _pTableWindow,
+ std::set<OUString>& _rTableNames,
+ OUString& _rsTableListStr
+ )
+ {
+ OUString sTabName(BuildTable(_xConnection,_pTableWindow));
+
+ if(_rTableNames.insert(sTabName).second)
+ {
+ _rsTableListStr += sTabName + ",";
+ }
+ }
+ OUString GenerateFromClause( const Reference< XConnection>& _xConnection,
+ const OQueryTableView::OTableWindowMap* pTabList,
+ const std::vector<VclPtr<OTableConnection> >& rConnList
+ )
+ {
+
+ OUString aTableListStr;
+ // used to avoid putting a table twice in FROM clause
+ std::set<OUString> aTableNames;
+
+ // generate outer join clause in from
+ if(!rConnList.empty())
+ {
+ std::map<OTableWindow*,sal_Int32> aConnectionCount;
+ auto aEnd = rConnList.end();
+ for (auto const& connection : rConnList)
+ {
+ static_cast<OQueryTableConnection*>(connection.get())->SetVisited(false);
+ ++aConnectionCount[connection->GetSourceWin()];
+ ++aConnectionCount[connection->GetDestWin()];
+ }
+ std::multimap<sal_Int32 , OTableWindow*> aMulti;
+ for (auto const& elem : aConnectionCount)
+ {
+ aMulti.emplace(elem.second,elem.first);
+ }
+
+ const bool bUseEscape = ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_OUTERJOINESCAPE );
+ std::multimap<sal_Int32 , OTableWindow*>::const_reverse_iterator aRIter = aMulti.rbegin();
+ std::multimap<sal_Int32 , OTableWindow*>::const_reverse_iterator aREnd = aMulti.rend();
+ for(;aRIter != aREnd;++aRIter)
+ {
+ auto aConIter = aRIter->second->getTableView()->getTableConnections(aRIter->second);
+ for(;aConIter != aEnd;++aConIter)
+ {
+ OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>((*aConIter).get());
+ if(!pEntryConn->IsVisited() && pEntryConn->GetSourceWin() == aRIter->second )
+ {
+ OUString aJoin;
+ GetNextJoin(_xConnection,
+ pEntryConn,
+ static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
+ aJoin,
+ aTableNames);
+
+ if(!aJoin.isEmpty())
+ {
+ OUString aStr;
+ switch(static_cast<OQueryTableConnectionData*>(pEntryConn->GetData().get())->GetJoinType())
+ {
+ case LEFT_JOIN:
+ case RIGHT_JOIN:
+ case FULL_JOIN:
+ {
+ // create outer join
+ if ( bUseEscape )
+ aStr += "{ oj ";
+ aStr += aJoin;
+ if ( bUseEscape )
+ aStr += " }";
+ }
+ break;
+ default:
+ aStr += aJoin;
+ break;
+ }
+ aStr += ",";
+ aTableListStr += aStr;
+ }
+ }
+ }
+ }
+
+ // and now all inner joins
+ // these are implemented as
+ // "FROM tbl1, tbl2 WHERE tbl1.col1=tlb2.col2"
+ // rather than
+ // "FROM tbl1 INNER JOIN tbl2 ON tbl1.col1=tlb2.col2"
+ for (auto const& connection : rConnList)
+ {
+ OQueryTableConnection* pEntryConn = static_cast<OQueryTableConnection*>(connection.get());
+ if(!pEntryConn->IsVisited())
+ {
+ searchAndAppendName(_xConnection,
+ static_cast<OQueryTableWindow*>(pEntryConn->GetSourceWin()),
+ aTableNames,
+ aTableListStr);
+
+ searchAndAppendName(_xConnection,
+ static_cast<OQueryTableWindow*>(pEntryConn->GetDestWin()),
+ aTableNames,
+ aTableListStr);
+ }
+ }
+ }
+ // all tables that haven't a connection to anyone
+ for (auto const& table : *pTabList)
+ {
+ const OQueryTableWindow* pEntryTab = static_cast<const OQueryTableWindow*>(table.second.get());
+ if(!pEntryTab->ExistsAConn())
+ {
+ aTableListStr += BuildTable(_xConnection,pEntryTab) + ",";
+ }
+ }
+
+ if(!aTableListStr.isEmpty())
+ aTableListStr = aTableListStr.replaceAt(aTableListStr.getLength()-1,1, u"" );
+ return aTableListStr;
+ }
+ OUString GenerateGroupBy(const OQueryDesignView* _pView,OTableFields& _rFieldList, bool bMulti )
+ {
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+ const Reference< XConnection> xConnection = rController.getConnection();
+ if(!xConnection.is())
+ return OUString();
+
+ std::map< OUString,bool> aGroupByNames;
+
+ OUString aGroupByStr;
+ try
+ {
+ const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ const OUString aQuote = xMetaData->getIdentifierQuoteString();
+
+ for (auto const& field : _rFieldList)
+ {
+ if ( field->IsGroupBy() )
+ {
+ OSL_ENSURE(!field->GetField().isEmpty(),"No Field Name available!;-(");
+ OUString sGroupByPart = quoteTableAlias(bMulti,field->GetAlias(),aQuote);
+
+ // only quote the field name when it isn't calculated
+ if ( field->isNoneFunction() )
+ {
+ sGroupByPart += ::dbtools::quoteName(aQuote, field->GetField());
+ }
+ else
+ {
+ OUString aTmp = field->GetField();
+ OUString aErrorMsg;
+ Reference<XPropertySet> xColumn;
+ std::unique_ptr< ::connectivity::OSQLParseNode> pParseNode(_pView->getPredicateTreeFromEntry(field,aTmp,aErrorMsg,xColumn));
+ if (pParseNode)
+ {
+ OUString sGroupBy;
+ pParseNode->getChild(0)->parseNodeToStr( sGroupBy,
+ xConnection,
+ &rController.getParser().getContext(),
+ false,
+ !field->isOtherFunction());
+ sGroupByPart += sGroupBy;
+ }
+ else
+ sGroupByPart += field->GetField();
+ }
+ if ( aGroupByNames.find(sGroupByPart) == aGroupByNames.end() )
+ {
+ aGroupByNames.emplace(sGroupByPart,true);
+ aGroupByStr += sGroupByPart + ",";
+ }
+ }
+ }
+ if ( !aGroupByStr.isEmpty() )
+ {
+ aGroupByStr = aGroupByStr.replaceAt(aGroupByStr.getLength()-1,1, u" " );
+ OUString aGroupByStr2 = " GROUP BY " + aGroupByStr;
+ aGroupByStr = aGroupByStr2;
+ }
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("Failure while building group by!");
+ }
+ return aGroupByStr;
+ }
+ SqlParseError GetORCriteria(OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ sal_uInt16& nLevel ,
+ bool bHaving = false,
+ bool bAddOrOnOneLine = false);
+ SqlParseError GetSelectionCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode* pNode,
+ sal_uInt16& rLevel )
+ {
+ if (!pNode || !SQL_ISRULE(pNode, select_statement))
+ return eNoSelectStatement;
+
+ // nyi: more checking for the correct structure!
+ pNode = pNode->getChild(3)->getChild(1);
+ // no where clause found
+ if (!pNode || pNode->isLeaf())
+ return eOk;
+
+ // Next free sentence...
+ SqlParseError eErrorCode = eOk;
+ ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
+ if ( pCondition ) // no where clause
+ {
+ // now we have to check the other conditions
+ // first make the logical easier
+ ::connectivity::OSQLParseNode::negateSearchCondition(pCondition);
+ ::connectivity::OSQLParseNode *pNodeTmp = pNode->getChild(1);
+
+ ::connectivity::OSQLParseNode::disjunctiveNormalForm(pNodeTmp);
+ pNodeTmp = pNode->getChild(1);
+ ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
+ pNodeTmp = pNode->getChild(1);
+ // compress sort the criteria @see https://bz.apache.org/ooo/show_bug.cgi?id=24079
+ OSQLParseNode::compress(pNodeTmp);
+ pNodeTmp = pNode->getChild(1);
+
+ // first extract the inner joins conditions
+ GetInnerJoinCriteria(_pView,pNodeTmp);
+ // now simplify again, join are checked in ComparisonPredicate
+ ::connectivity::OSQLParseNode::absorptions(pNodeTmp);
+ pNodeTmp = pNode->getChild(1);
+
+ // it could happen that pCondition is not more valid
+ eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pNodeTmp, rLevel);
+ }
+ return eErrorCode;
+ }
+ SqlParseError GetANDCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ sal_uInt16& nLevel,
+ bool bHaving,
+ bool bAddOrOnOneLine);
+ SqlParseError ComparisonPredicate(OQueryDesignView const * _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ const sal_uInt16 nLevel,
+ bool bHaving,
+ bool bAddOrOnOneLine);
+ SqlParseError GetORCriteria(OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ sal_uInt16& nLevel ,
+ bool bHaving,
+ bool bAddOrOnOneLine)
+ {
+ SqlParseError eErrorCode = eOk;
+
+ // round brackets around the printout
+ if (pCondition->count() == 3 &&
+ SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
+ {
+ eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pCondition->getChild(1),nLevel,bHaving,bAddOrOnOneLine);
+ }
+ // OR condition
+ // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
+ else if (SQL_ISRULE(pCondition,search_condition))
+ {
+ for (int i = 0; i < 3 && eErrorCode == eOk ; i+=2)
+ {
+ const ::connectivity::OSQLParseNode* pChild = pCondition->getChild(i);
+ if ( SQL_ISRULE(pChild,search_condition) )
+ eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pChild,nLevel,bHaving,bAddOrOnOneLine);
+ else
+ {
+ eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pChild, nLevel,bHaving, i != 0 && bAddOrOnOneLine);
+ if ( !bAddOrOnOneLine)
+ nLevel++;
+ }
+ }
+ }
+ else
+ eErrorCode = GetANDCriteria( _pView,_pSelectionBrw,pCondition, nLevel, bHaving,bAddOrOnOneLine );
+
+ return eErrorCode;
+ }
+ bool CheckOrCriteria(const ::connectivity::OSQLParseNode* _pCondition,::connectivity::OSQLParseNode* _pFirstColumnRef)
+ {
+ bool bRet = true;
+ ::connectivity::OSQLParseNode* pFirstColumnRef = _pFirstColumnRef;
+ for (size_t i = 0; bRet && i < _pCondition->count(); ++i)
+ {
+ const ::connectivity::OSQLParseNode* pChild = _pCondition->getChild(i);
+ if ( pChild->isToken() )
+ continue;
+ else if ( SQL_ISRULE(pChild,search_condition) )
+ bRet = CheckOrCriteria(pChild,pFirstColumnRef);
+ else
+ {
+ // this is a simple way to test columns are the same, may be we have to adjust this algo a little bit in future. :-)
+ ::connectivity::OSQLParseNode* pSecondColumnRef = pChild->getByRule(::connectivity::OSQLParseNode::column_ref);
+ if ( pFirstColumnRef && pSecondColumnRef )
+ bRet = *pFirstColumnRef == *pSecondColumnRef;
+ else if ( !pFirstColumnRef )
+ pFirstColumnRef = pSecondColumnRef;
+ }
+ }
+ return bRet;
+ }
+ SqlParseError GetANDCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ sal_uInt16& nLevel,
+ bool bHaving,
+ bool bAddOrOnOneLine)
+ {
+ const css::lang::Locale aLocale = _pView->getLocale();
+ const OUString sDecimal = _pView->getDecimalSeparator();
+
+ // I will need a cast pointer to my css::sdbcx::Container
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+ SqlParseError eErrorCode = eOk;
+
+ // round brackets
+ if (SQL_ISRULE(pCondition,boolean_primary))
+ {
+ // check if we have to put the or criteria on one line.
+ const ::connectivity::OSQLParseNode* pSearchCondition = pCondition->getChild(1);
+ bool bMustAddOrOnOneLine = CheckOrCriteria(pSearchCondition,nullptr);
+ if ( SQL_ISRULE( pSearchCondition, search_condition) ) // we have a or
+ {
+ _pSelectionBrw->DuplicateConditionLevel( nLevel);
+ eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(0), nLevel,bHaving,bMustAddOrOnOneLine );
+ if ( eErrorCode == eOk )
+ {
+ ++nLevel;
+ eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition->getChild(2), nLevel,bHaving,bMustAddOrOnOneLine );
+ }
+ }
+ else
+ eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSearchCondition, nLevel,bHaving,bMustAddOrOnOneLine );
+ }
+ // The first element is (again) an AND condition
+ else if ( SQL_ISRULE(pCondition,boolean_term) )
+ {
+ OSL_ENSURE(pCondition->count() == 3,"Illegal definition of boolean_term");
+ eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(0), nLevel,bHaving,bAddOrOnOneLine );
+ if ( eErrorCode == eOk )
+ eErrorCode = GetANDCriteria(_pView,_pSelectionBrw,pCondition->getChild(2), nLevel,bHaving,bAddOrOnOneLine );
+ }
+ else if (SQL_ISRULE( pCondition, comparison_predicate))
+ {
+ eErrorCode = ComparisonPredicate(_pView,_pSelectionBrw,pCondition,nLevel,bHaving,bAddOrOnOneLine);
+ }
+ else if( SQL_ISRULE(pCondition,like_predicate) )
+ {
+ const ::connectivity::OSQLParseNode* pValueExp = pCondition->getChild(0);
+ if (SQL_ISRULE(pValueExp, column_ref ) )
+ {
+ OUString aCondition;
+ Reference< XConnection> xConnection = rController.getConnection();
+ if ( xConnection.is() )
+ {
+ OUString aColumnName;
+ // the international doesn't matter I have a string
+ pCondition->parseNodeToPredicateStr(aCondition,
+ xConnection,
+ rController.getNumberFormatter(),
+ aLocale,
+ sDecimal,
+ &rController.getParser().getContext());
+
+ pValueExp->parseNodeToPredicateStr( aColumnName,
+ xConnection,
+ rController.getNumberFormatter(),
+ aLocale,
+ sDecimal,
+ &rController.getParser().getContext());
+
+ // don't display the column name
+ aCondition = aCondition.copy(aColumnName.getLength());
+ aCondition = aCondition.trim();
+ }
+
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ if ( eOk == ( eErrorCode = FillDragInfo(_pView,pValueExp,aDragLeft) ))
+ {
+ if ( bHaving )
+ aDragLeft->SetGroupBy(true);
+ _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
+ }
+ }
+ else if(SQL_ISRULEOR3(pValueExp, general_set_fct, set_fct_spec, position_exp) ||
+ SQL_ISRULEOR3(pValueExp, extract_exp, fold, char_substring_fct) ||
+ SQL_ISRULEOR2(pValueExp, length_exp, char_value_fct))
+ {
+ AddFunctionCondition( _pView,
+ _pSelectionBrw,
+ pCondition,
+ nLevel,
+ bHaving,
+ bAddOrOnOneLine);
+ }
+ else
+ {
+ eErrorCode = eNoColumnInLike;
+ OUString sError(DBA_RES(STR_QRY_LIKE_LEFT_NO_COLUMN));
+ _pView->getController().appendError( sError );
+ }
+ }
+ else if( SQL_ISRULEOR2(pCondition,test_for_null,in_predicate)
+ || SQL_ISRULEOR2(pCondition,all_or_any_predicate,between_predicate))
+ {
+ if ( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) )
+ {
+ AddFunctionCondition( _pView,
+ _pSelectionBrw,
+ pCondition,
+ nLevel,
+ bHaving,
+ bAddOrOnOneLine);
+ }
+ else if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) )
+ {
+ // parse condition
+ OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ if ( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft)) )
+ {
+ if ( bHaving )
+ aDragLeft->SetGroupBy(true);
+ _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
+ }
+ }
+ else
+ {
+ // Parse the function condition
+ OUString sCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,1);
+ Reference< XConnection> xConnection = rController.getConnection();
+ // the international doesn't matter I have a string
+ OUString sName;
+ pCondition->getChild(0)->parseNodeToPredicateStr(sName,
+ xConnection,
+ rController.getNumberFormatter(),
+ aLocale,
+ sDecimal,
+ &rController.getParser().getContext());
+
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ aDragLeft->SetField(sName);
+ aDragLeft->SetFunctionType(FKT_OTHER);
+
+ if ( bHaving )
+ aDragLeft->SetGroupBy(true);
+ _pSelectionBrw->AddCondition(aDragLeft, sCondition, nLevel,bAddOrOnOneLine);
+ }
+ }
+ else if( SQL_ISRULEOR2(pCondition,existence_test,unique_test) )
+ {
+ // Parse the function condition
+ OUString aCondition = ParseCondition(rController,pCondition,sDecimal,aLocale,0);
+
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ aDragLeft->SetField(aCondition);
+ aDragLeft->SetFunctionType(FKT_CONDITION);
+
+ eErrorCode = _pSelectionBrw->InsertField(aDragLeft,BROWSER_INVALIDID,false).is() ? eOk : eTooManyColumns;
+ }
+ else //! TODO not supported yet
+ eErrorCode = eStatementTooComplex;
+ // Pass on the error code
+ return eErrorCode;
+ }
+ SqlParseError AddFunctionCondition(OQueryDesignView const * _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ const sal_uInt16 nLevel,
+ bool bHaving,
+ bool bAddOrOnOneLine)
+ {
+ SqlParseError eErrorCode = eOk;
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+
+ OSQLParseNode* pFunction = pCondition->getChild(0);
+
+ OSL_ENSURE(SQL_ISRULEOR3(pFunction, general_set_fct, set_fct_spec, position_exp) ||
+ SQL_ISRULEOR3(pFunction, extract_exp, fold, char_substring_fct) ||
+ SQL_ISRULEOR2(pFunction,length_exp,char_value_fct),
+ "Illegal call!");
+
+ Reference< XConnection> xConnection = rController.getConnection();
+ if(xConnection.is())
+ {
+ OUString aCondition;
+ OUString aColumnName;
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ pCondition->parseNodeToPredicateStr(aCondition,
+ xConnection,
+ rController.getNumberFormatter(),
+ _pView->getLocale(),
+ _pView->getDecimalSeparator(),
+ &rController.getParser().getContext());
+
+ pFunction->parseNodeToStr( aColumnName,
+ xConnection,
+ &rController.getParser().getContext(),
+ true); // quote is to true because we need quoted elements inside the function
+ // don't display the column name
+ aCondition = aCondition.copy(aColumnName.getLength());
+ aCondition = aCondition.trim();
+ if ( aCondition.startsWith("=") ) // ignore the equal sign
+ aCondition = aCondition.copy(1);
+
+ if ( SQL_ISRULE(pFunction, general_set_fct ) )
+ {
+ sal_Int32 nFunctionType = FKT_AGGREGATE;
+ OSQLParseNode* pParamNode = pFunction->getChild(pFunction->count()-2);
+ if ( pParamNode && pParamNode->getTokenValue().toChar() == '*' )
+ {
+ OJoinTableView::OTableWindowMap& rTabList = _pView->getTableView()->GetTabWinMap();
+ for (auto const& table : rTabList)
+ {
+ OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
+ if (pTabWin->ExistsField( "*", aDragLeft ))
+ {
+ aDragLeft->SetAlias(OUString());
+ aDragLeft->SetTable(OUString());
+ break;
+ }
+ }
+ }
+ else if (pParamNode)
+ {
+ eErrorCode = FillDragInfo(_pView,pParamNode,aDragLeft);
+ if ( eOk != eErrorCode && SQL_ISRULE(pParamNode,num_value_exp))
+ {
+ OUString sParameterValue;
+ pParamNode->parseNodeToStr( sParameterValue,
+ xConnection,
+ &rController.getParser().getContext());
+ nFunctionType |= FKT_NUMERIC;
+ aDragLeft->SetField(sParameterValue);
+ eErrorCode = eOk;
+ }
+ }
+ aDragLeft->SetFunctionType(nFunctionType);
+ if ( bHaving )
+ aDragLeft->SetGroupBy(true);
+ aDragLeft->SetFunction(aColumnName.getToken(0, '('));
+ }
+ else
+ {
+ // for an unknown function we write the whole text in the field
+ aDragLeft->SetField(aColumnName);
+ if(bHaving)
+ aDragLeft->SetGroupBy(true);
+ aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
+ }
+ _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
+ }
+
+ return eErrorCode;
+ }
+ SqlParseError ComparisonPredicate(OQueryDesignView const * _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode * pCondition,
+ const sal_uInt16 nLevel,
+ bool bHaving
+ ,bool bAddOrOnOneLine)
+ {
+ SqlParseError eErrorCode = eOk;
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+
+ OSL_ENSURE(SQL_ISRULE( pCondition, comparison_predicate),"ComparisonPredicate: pCondition is not a Comparison Predicate");
+ if ( SQL_ISRULE(pCondition->getChild(0), column_ref )
+ || SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref) )
+ {
+ OUString aCondition;
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+
+ if ( SQL_ISRULE(pCondition->getChild(0), column_ref ) && SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) )
+ {
+ OTableFieldDescRef aDragRight = new OTableFieldDesc();
+ eErrorCode = FillDragInfo(_pView,pCondition->getChild(0),aDragLeft);
+ if (eOk != eErrorCode)
+ return eErrorCode;
+ eErrorCode = FillDragInfo(_pView,pCondition->getChild(2),aDragRight);
+ if (eOk != eErrorCode)
+ return eErrorCode;
+
+ OQueryTableConnection* pConn = static_cast<OQueryTableConnection*>(
+ _pView->getTableView()->GetTabConn(static_cast<OQueryTableWindow*>(aDragLeft->GetTabWindow()),
+ static_cast<OQueryTableWindow*>(aDragRight->GetTabWindow()),
+ true));
+ if ( pConn )
+ {
+ OConnectionLineDataVec& rLineDataList = pConn->GetData()->GetConnLineDataList();
+ for (auto const& lineData : rLineDataList)
+ {
+ if(lineData->GetSourceFieldName() == aDragLeft->GetField() ||
+ lineData->GetDestFieldName() == aDragLeft->GetField() )
+ return eOk;
+ }
+ }
+ }
+
+ sal_uInt32 nPos = 0;
+ if(SQL_ISRULE(pCondition->getChild(0), column_ref ))
+ {
+ nPos = 0;
+ sal_uInt32 i=1;
+
+ // don't display the equal
+ if (pCondition->getChild(i)->getNodeType() == SQLNodeType::Equal)
+ i++;
+
+ // parse the condition
+ aCondition = ParseCondition(rController
+ ,pCondition
+ ,_pView->getDecimalSeparator()
+ ,_pView->getLocale()
+ ,i);
+ }
+ else if( SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref ) )
+ {
+ nPos = pCondition->count()-1;
+
+ sal_Int32 i = static_cast<sal_Int32>(pCondition->count() - 2);
+ switch (pCondition->getChild(i)->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ // don't display the equal
+ i--;
+ break;
+ case SQLNodeType::Less:
+ // take the opposite as we change the order
+ i--;
+ aCondition += ">";
+ break;
+ case SQLNodeType::LessEq:
+ // take the opposite as we change the order
+ i--;
+ aCondition += ">=";
+ break;
+ case SQLNodeType::Great:
+ // take the opposite as we change the order
+ i--;
+ aCondition += "<";
+ break;
+ case SQLNodeType::GreatEq:
+ // take the opposite as we change the order
+ i--;
+ aCondition += "<=";
+ break;
+ default:
+ break;
+ }
+
+ // go backward
+ Reference< XConnection> xConnection = rController.getConnection();
+ if(xConnection.is())
+ {
+ for (; i >= 0; i--)
+ pCondition->getChild(i)->parseNodeToPredicateStr(aCondition,
+ xConnection,
+ rController.getNumberFormatter(),
+ _pView->getLocale(),
+ _pView->getDecimalSeparator(),
+ &rController.getParser().getContext());
+ }
+ }
+ // else ???
+
+ if( eOk == ( eErrorCode = FillDragInfo(_pView,pCondition->getChild(nPos),aDragLeft)))
+ {
+ if(bHaving)
+ aDragLeft->SetGroupBy(true);
+ _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
+ }
+ }
+ else if( SQL_ISRULEOR2(pCondition->getChild(0), set_fct_spec , general_set_fct ) )
+ {
+ AddFunctionCondition( _pView,
+ _pSelectionBrw,
+ pCondition,
+ nLevel,
+ bHaving,
+ bAddOrOnOneLine);
+ }
+ else // it can only be an Expr
+ {
+ OUString aName,aCondition;
+
+ // Field name
+ Reference< XConnection> xConnection = rController.getConnection();
+ if(xConnection.is())
+ {
+ ::connectivity::OSQLParseNode *pLhs = pCondition->getChild(0);
+ ::connectivity::OSQLParseNode *pRhs = pCondition->getChild(2);
+ pLhs->parseNodeToStr(aName,
+ xConnection,
+ &rController.getParser().getContext(),
+ true);
+ // Criteria
+ aCondition = pCondition->getChild(1)->getTokenValue();
+ pRhs->parseNodeToPredicateStr(aCondition,
+ xConnection,
+ rController.getNumberFormatter(),
+ _pView->getLocale(),
+ _pView->getDecimalSeparator(),
+ &rController.getParser().getContext());
+ }
+
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ aDragLeft->SetField(aName);
+ aDragLeft->SetFunctionType(FKT_OTHER|FKT_NUMERIC);
+ // and add it on
+ _pSelectionBrw->AddCondition(aDragLeft, aCondition, nLevel,bAddOrOnOneLine);
+ }
+ return eErrorCode;
+ }
+
+ OQueryTableWindow* lcl_findColumnInTables( const OUString& _rColumName, const OJoinTableView::OTableWindowMap& _rTabList, OTableFieldDescRef const & _rInfo )
+ {
+ for (auto const& table : _rTabList)
+ {
+ OQueryTableWindow* pTabWin = static_cast< OQueryTableWindow* >( table.second.get() );
+ if ( pTabWin && pTabWin->ExistsField( _rColumName, _rInfo ) )
+ return pTabWin;
+ }
+ return nullptr;
+ }
+
+ void InsertColumnRef(const OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode * pColumnRef,
+ OUString& aColumnName,
+ const OUString& aColumnAlias,
+ OUString& aTableRange,
+ OTableFieldDescRef const & _raInfo,
+ OJoinTableView::OTableWindowMap const * pTabList)
+ {
+
+ // Put the table names together
+ ::connectivity::OSQLParseTreeIterator& rParseIter = static_cast<OQueryController&>(_pView->getController()).getParseIterator();
+ rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange );
+
+ bool bFound(false);
+ OSL_ENSURE(!aColumnName.isEmpty(),"Column name must not be empty");
+ if (aTableRange.isEmpty())
+ {
+ // SELECT column, ...
+ bFound = nullptr != lcl_findColumnInTables( aColumnName, *pTabList, _raInfo );
+ if ( bFound && ( aColumnName.toChar() != '*' ) )
+ _raInfo->SetFieldAlias(aColumnAlias);
+ }
+ else
+ {
+ // SELECT range.column, ...
+ OQueryTableWindow* pTabWin = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable(aTableRange);
+
+ if (pTabWin && pTabWin->ExistsField(aColumnName, _raInfo))
+ {
+ if(aColumnName.toChar() != '*')
+ _raInfo->SetFieldAlias(aColumnAlias);
+ bFound = true;
+ }
+ }
+ if (!bFound)
+ {
+ _raInfo->SetTable(OUString());
+ _raInfo->SetAlias(OUString());
+ _raInfo->SetField(aColumnName);
+ _raInfo->SetFieldAlias(aColumnAlias); // nyi : here it continues Expr_1, Expr_2 ...
+ _raInfo->SetFunctionType(FKT_OTHER);
+ }
+ }
+ bool checkJoinConditions( const OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode* _pNode )
+ {
+ const ::connectivity::OSQLParseNode* pJoinNode = nullptr;
+ bool bRet = true;
+ if (SQL_ISRULE(_pNode,qualified_join))
+ pJoinNode = _pNode;
+ else if (SQL_ISRULE(_pNode,table_ref)
+ && _pNode->count() == 3
+ && SQL_ISPUNCTUATION(_pNode->getChild(0),"(")
+ && SQL_ISPUNCTUATION(_pNode->getChild(2),")") ) // '(' joined_table ')'
+ pJoinNode = _pNode->getChild(1);
+ else if (! ( SQL_ISRULE(_pNode, table_ref) && _pNode->count() == 2) ) // table_node table_primary_as_range_column
+ bRet = false;
+
+ if (pJoinNode && !InsertJoin(_pView,pJoinNode))
+ bRet = false;
+ return bRet;
+ }
+ bool InsertJoin(const OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode *pNode)
+ {
+ OSL_ENSURE( SQL_ISRULE( pNode, qualified_join ) || SQL_ISRULE( pNode, joined_table ) || SQL_ISRULE( pNode, cross_union ),
+ "OQueryDesignView::InsertJoin: Error in the Parse Tree");
+
+ if (SQL_ISRULE(pNode,joined_table))
+ return InsertJoin(_pView,pNode->getChild(1));
+
+ // first check the left and right side
+ const ::connectivity::OSQLParseNode* pRightTableRef = pNode->getChild(3); // table_ref
+ if ( SQL_ISRULE(pNode, qualified_join) && SQL_ISTOKEN(pNode->getChild(1),NATURAL) )
+ pRightTableRef = pNode->getChild(4); // table_ref
+
+ if ( !checkJoinConditions(_pView,pNode->getChild(0)) || !checkJoinConditions(_pView,pRightTableRef))
+ return false;
+
+ // named column join may be implemented later
+ // SQL_ISRULE(pNode->getChild(4),named_columns_join)
+ EJoinType eJoinType = INNER_JOIN;
+ bool bNatural = false;
+ if ( SQL_ISRULE(pNode, qualified_join) )
+ {
+ ::connectivity::OSQLParseNode* pJoinType = pNode->getChild(1); // join_type
+ if ( SQL_ISTOKEN(pJoinType,NATURAL) )
+ {
+ bNatural = true;
+ pJoinType = pNode->getChild(2);
+ }
+
+ if (SQL_ISRULE(pJoinType,join_type) && (!pJoinType->count() || SQL_ISTOKEN(pJoinType->getChild(0),INNER)))
+ {
+ eJoinType = INNER_JOIN;
+ }
+ else
+ {
+ if (SQL_ISRULE(pJoinType,join_type)) // one level deeper
+ pJoinType = pJoinType->getChild(0);
+
+ if (SQL_ISTOKEN(pJoinType->getChild(0),LEFT))
+ eJoinType = LEFT_JOIN;
+ else if(SQL_ISTOKEN(pJoinType->getChild(0),RIGHT))
+ eJoinType = RIGHT_JOIN;
+ else
+ eJoinType = FULL_JOIN;
+ }
+ if ( SQL_ISRULE(pNode->getChild(4),join_condition) )
+ {
+ if ( InsertJoinConnection(_pView,pNode->getChild(4)->getChild(1), eJoinType,pNode->getChild(0),pRightTableRef) != eOk )
+ return false;
+ }
+ }
+ else if ( SQL_ISRULE(pNode, cross_union) )
+ {
+ eJoinType = CROSS_JOIN;
+ pRightTableRef = pNode->getChild(pNode->count() - 1);
+ }
+ else
+ return false;
+
+ if ( eJoinType != CROSS_JOIN && !bNatural )
+ return true;
+
+ OQueryTableWindow* pLeftWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pNode->getChild(0)) );
+ OQueryTableWindow* pRightWindow = static_cast<OQueryTableView*>(_pView->getTableView())->FindTable( getTableRange(_pView,pRightTableRef) );
+ OSL_ENSURE(pLeftWindow && pRightWindow,"Table Windows could not be found!");
+ if ( !pLeftWindow || !pRightWindow )
+ return false;
+
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ aDragLeft->SetTabWindow(pLeftWindow);
+ aDragLeft->SetTable(pLeftWindow->GetTableName());
+ aDragLeft->SetAlias(pLeftWindow->GetAliasName());
+
+ OTableFieldDescRef aDragRight = new OTableFieldDesc();
+ aDragRight->SetTabWindow(pRightWindow);
+ aDragRight->SetTable(pRightWindow->GetTableName());
+ aDragRight->SetAlias(pRightWindow->GetAliasName());
+
+ insertConnection(_pView,eJoinType,aDragLeft,aDragRight,bNatural);
+
+ return true;
+ }
+ void insertUnUsedFields(OQueryDesignView const * _pView,OSelectionBrowseBox* _pSelectionBrw)
+ {
+ // now we have to insert the fields which aren't in the statement
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+ OTableFields& rUnUsedFields = rController.getUnUsedFields();
+ for (auto & unusedField : rUnUsedFields)
+ if(_pSelectionBrw->InsertField(unusedField,BROWSER_INVALIDID,false,false).is())
+ unusedField = nullptr;
+ OTableFields().swap( rUnUsedFields );
+ }
+
+ SqlParseError InitFromParseNodeImpl(OQueryDesignView* _pView,OSelectionBrowseBox* _pSelectionBrw)
+ {
+ SqlParseError eErrorCode = eOk;
+
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+
+ _pSelectionBrw->PreFill();
+ _pSelectionBrw->SetReadOnly(rController.isReadOnly());
+ _pSelectionBrw->Fill();
+
+ ::connectivity::OSQLParseTreeIterator& aIterator = rController.getParseIterator();
+ const ::connectivity::OSQLParseNode* pParseTree = aIterator.getParseTree();
+
+ do
+ {
+ if ( !pParseTree )
+ {
+ // now we have to insert the fields which aren't in the statement
+ insertUnUsedFields(_pView,_pSelectionBrw);
+ break;
+ }
+
+ if ( !rController.isEscapeProcessing() ) // not allowed in this mode
+ {
+ eErrorCode = eNativeMode;
+ break;
+ }
+
+ if ( !( SQL_ISRULE( pParseTree, select_statement ) ) )
+ {
+ eErrorCode = eNoSelectStatement;
+ break;
+ }
+
+ const OSQLParseNode* pTableExp = pParseTree->getChild(3);
+ if ( pTableExp->getChild(7)->count() > 0 || pTableExp->getChild(8)->count() > 0)
+ {
+ eErrorCode = eStatementTooComplex;
+ break;
+ }
+
+ Reference< XConnection> xConnection = rController.getConnection();
+ if ( !xConnection.is() )
+ {
+ OSL_FAIL( "InitFromParseNodeImpl: no connection? no connection!" );
+ break;
+ }
+
+ const OSQLTables& aMap = aIterator.getTables();
+ ::comphelper::UStringMixLess aTmp(aMap.key_comp());
+ ::comphelper::UStringMixEqual aKeyComp( aTmp.isCaseSensitive() );
+
+ Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ try
+ {
+ sal_Int32 nMax = xMetaData->getMaxTablesInSelect();
+ if ( nMax && nMax < static_cast<sal_Int32>(aMap.size()) )
+ {
+ eErrorCode = eTooManyTables;
+ break;
+ }
+
+ OUString sComposedName;
+ OUString sAlias;
+
+ OQueryTableView* pTableView = static_cast<OQueryTableView*>(_pView->getTableView());
+ pTableView->clearLayoutInformation();
+ for (auto const& elem : aMap)
+ {
+ OSQLTable xTable = elem.second;
+ Reference< XPropertySet > xTableProps( xTable, UNO_QUERY_THROW );
+
+ sAlias = elem.first;
+
+ // check whether this is a query
+ Reference< XPropertySetInfo > xPSI = xTableProps->getPropertySetInfo();
+ bool bIsQuery = xPSI.is() && xPSI->hasPropertyByName( PROPERTY_COMMAND );
+
+ if ( bIsQuery )
+ OSL_VERIFY( xTableProps->getPropertyValue( PROPERTY_NAME ) >>= sComposedName );
+ else
+ {
+ sComposedName = ::dbtools::composeTableName( xMetaData, xTableProps, ::dbtools::EComposeRule::InDataManipulation, false );
+
+ // if the alias is the complete (composed) table, then shorten it
+ if ( aKeyComp( sComposedName, elem.first ) )
+ {
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents( xMetaData, sComposedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
+ sAlias = sTable;
+ }
+ }
+
+ // find the existent window for this alias
+ OQueryTableWindow* pExistentWin = pTableView->FindTable( sAlias );
+ if ( !pExistentWin )
+ {
+ pTableView->AddTabWin( sComposedName, sAlias ); // don't create data here
+ }
+ else
+ {
+ // there already exists a window for this alias...
+ if ( !aKeyComp( pExistentWin->GetData()->GetComposedName(), sComposedName ) )
+ // ... but for another complete table name -> new window
+ pTableView->AddTabWin(sComposedName, sAlias);
+ }
+ }
+
+ // now delete the data for which we haven't any tablewindow
+ OJoinTableView::OTableWindowMap aTableMap(pTableView->GetTabWinMap());
+ for (auto const& table : aTableMap)
+ {
+ if(aMap.find(table.second->GetComposedName()) == aMap.end() &&
+ aMap.find(table.first) == aMap.end())
+ pTableView->RemoveTabWin(table.second);
+ }
+
+ if ( eOk == (eErrorCode = FillOuterJoins(_pView,pTableExp->getChild(0)->getChild(1))) )
+ {
+ // check if we have a distinct statement
+ if(SQL_ISTOKEN(pParseTree->getChild(1),DISTINCT))
+ {
+ rController.setDistinct(true);
+ rController.InvalidateFeature(SID_QUERY_DISTINCT_VALUES);
+ }
+ else
+ {
+ rController.setDistinct(false);
+ }
+
+ ///check if query has a limit
+ if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1) )
+ {
+ rController.setLimit(
+ pTableExp->getChild(6)->getChild(1)->getTokenValue().toInt64() );
+ }
+ else
+ {
+ rController.setLimit(-1);
+ }
+
+ if ( (eErrorCode = InstallFields(_pView, pParseTree, &pTableView->GetTabWinMap())) == eOk )
+ {
+ // GetSelectionCriteria must be called before GetHavingCriteria
+ sal_uInt16 nLevel=0;
+
+ if ( eOk == (eErrorCode = GetSelectionCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
+ {
+ if ( eOk == (eErrorCode = GetGroupCriteria(_pView,_pSelectionBrw,pParseTree)) )
+ {
+ if ( eOk == (eErrorCode = GetHavingCriteria(_pView,_pSelectionBrw,pParseTree,nLevel)) )
+ {
+ if ( eOk == (eErrorCode = GetOrderCriteria(_pView,_pSelectionBrw,pParseTree)) )
+ insertUnUsedFields(_pView,_pSelectionBrw);
+ }
+ }
+ }
+ }
+ }
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("getMaxTablesInSelect!");
+ }
+ }
+ while ( false );
+
+ // New Undo-Actions were created in the Manager by the regeneration
+ rController.ClearUndoManager();
+ _pSelectionBrw->Invalidate();
+ return eErrorCode;
+ }
+ /** fillSelectSubList
+ @return
+ <TRUE/> when columns could be inserted otherwise <FALSE/>
+ */
+ SqlParseError fillSelectSubList( OQueryDesignView* _pView,
+ OJoinTableView::OTableWindowMap* _pTabList)
+ {
+ SqlParseError eErrorCode = eOk;
+ bool bFirstField = true;
+ for (auto const& table : *_pTabList)
+ {
+ OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
+ OTableFieldDescRef aInfo = new OTableFieldDesc();
+ if (pTabWin->ExistsField( "*", aInfo ))
+ {
+ eErrorCode = _pView->InsertField(aInfo, bFirstField);
+ bFirstField = false;
+ if (eErrorCode != eOk)
+ break;
+ }
+ }
+ return eErrorCode;
+ }
+ SqlParseError InstallFields(OQueryDesignView* _pView,
+ const ::connectivity::OSQLParseNode* pNode,
+ OJoinTableView::OTableWindowMap* pTabList )
+ {
+ if( pNode==nullptr || !SQL_ISRULE(pNode,select_statement))
+ return eNoSelectStatement;
+
+ ::connectivity::OSQLParseNode* pParseTree = pNode->getChild(2); // selection
+ bool bFirstField = true; // When initializing, the first field must be reactivated
+
+ SqlParseError eErrorCode = eOk;
+
+ if ( pParseTree->isRule() && SQL_ISPUNCTUATION(pParseTree->getChild(0),"*") )
+ {
+ // SELECT * ...
+ eErrorCode = fillSelectSubList(_pView,pTabList);
+ }
+ else if (SQL_ISRULE(pParseTree,scalar_exp_commalist) )
+ {
+ // SELECT column, ...
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+ Reference< XConnection> xConnection = rController.getConnection();
+
+ OUString aColumnName,aTableRange;
+ for (size_t i = 0; i < pParseTree->count() && eOk == eErrorCode ; ++i)
+ {
+ ::connectivity::OSQLParseNode * pColumnRef = pParseTree->getChild(i);
+
+ do {
+
+ if ( SQL_ISRULE(pColumnRef,select_sublist) )
+ {
+ eErrorCode = fillSelectSubList(_pView,pTabList);
+ break;
+ }
+
+ if ( SQL_ISRULE(pColumnRef,derived_column) )
+ {
+ OUString aColumnAlias(connectivity::OSQLParseTreeIterator::getColumnAlias(pColumnRef)); // might be empty
+ pColumnRef = pColumnRef->getChild(0);
+ OTableFieldDescRef aInfo = new OTableFieldDesc();
+
+ if ( pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
+ pColumnRef->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
+ )
+ pColumnRef = pColumnRef->getChild(1);
+
+ if (SQL_ISRULE(pColumnRef,column_ref))
+ {
+ InsertColumnRef(_pView,pColumnRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
+ eErrorCode = _pView->InsertField(aInfo, bFirstField);
+ bFirstField = false;
+ }
+ else if(SQL_ISRULEOR3(pColumnRef, general_set_fct, set_fct_spec, position_exp) ||
+ SQL_ISRULEOR3(pColumnRef, extract_exp, fold, char_substring_fct) ||
+ SQL_ISRULEOR2(pColumnRef,length_exp,char_value_fct))
+ {
+ OUString aColumns;
+ pColumnRef->parseNodeToPredicateStr(aColumns,
+ xConnection,
+ rController.getNumberFormatter(),
+ _pView->getLocale(),
+ _pView->getDecimalSeparator(),
+ &rController.getParser().getContext());
+
+ sal_Int32 nFunctionType = FKT_NONE;
+ ::connectivity::OSQLParseNode* pParamRef = nullptr;
+ sal_Int32 nColumnRefPos = pColumnRef->count() - 2;
+ if ( nColumnRefPos >= 0 && o3tl::make_unsigned(nColumnRefPos) < pColumnRef->count() )
+ pParamRef = pColumnRef->getChild(nColumnRefPos);
+
+ if ( SQL_ISRULE(pColumnRef,general_set_fct)
+ && pParamRef && SQL_ISRULE(pParamRef,column_ref) )
+ {
+ // Check the parameters for Column references
+ InsertColumnRef(_pView,pParamRef,aColumnName,aColumnAlias,aTableRange,aInfo,pTabList);
+ }
+ else if ( SQL_ISRULE(pColumnRef,general_set_fct) )
+ {
+ if ( pParamRef && pParamRef->getTokenValue().toChar() == '*' )
+ {
+ for (auto const& table : *pTabList)
+ {
+ OQueryTableWindow* pTabWin = static_cast<OQueryTableWindow*>(table.second.get());
+ if (pTabWin->ExistsField( "*", aInfo ))
+ {
+ aInfo->SetAlias(OUString());
+ aInfo->SetTable(OUString());
+ break;
+ }
+ }
+ }
+ else
+ {
+ OUString sFieldName = aColumns;
+ if ( pParamRef )
+ { // we got an aggregate function but without column name inside
+ // so we set the whole argument of the function as field name
+ nFunctionType |= FKT_NUMERIC;
+ sFieldName.clear();
+ pParamRef->parseNodeToStr( sFieldName,
+ xConnection,
+ &rController.getParser().getContext(),
+ true); // quote is to true because we need quoted elements inside the function
+ }
+ aInfo->SetDataType(DataType::DOUBLE);
+ aInfo->SetFieldType(TAB_NORMAL_FIELD);
+ aInfo->SetField(sFieldName);
+ }
+ aInfo->SetTabWindow(nullptr);
+ aInfo->SetFieldAlias(aColumnAlias);
+ }
+ else
+ {
+ _pView->fillFunctionInfo(pColumnRef,aColumns,aInfo);
+ aInfo->SetFieldAlias(aColumnAlias);
+ }
+
+ if ( SQL_ISRULE(pColumnRef,general_set_fct) )
+ {
+ aInfo->SetFunctionType(nFunctionType|FKT_AGGREGATE);
+ aInfo->SetFunction(OUString(comphelper::string::stripEnd(o3tl::getToken(aColumns,0,'('), ' ')));
+ }
+ else
+ aInfo->SetFunctionType(nFunctionType|FKT_OTHER);
+
+ eErrorCode = _pView->InsertField(aInfo, bFirstField);
+ bFirstField = false;
+ }
+ else
+ {
+ OUString aColumns;
+ pColumnRef->parseNodeToStr( aColumns,
+ xConnection,
+ &rController.getParser().getContext(),
+ true); // quote is to true because we need quoted elements inside the function
+
+ aInfo->SetTabWindow( nullptr );
+
+ // since we support queries in queries, the thingie might belong to an existing "table"
+ OQueryTableWindow* pExistingTable = lcl_findColumnInTables( aColumns, *pTabList, aInfo );
+ if ( pExistingTable )
+ {
+ aInfo->SetTabWindow( pExistingTable );
+ aInfo->SetTable( pExistingTable->GetTableName() );
+ aInfo->SetAlias( pExistingTable->GetAliasName() );
+ }
+
+ aInfo->SetDataType(DataType::DOUBLE);
+ aInfo->SetFieldType(TAB_NORMAL_FIELD);
+ aInfo->SetField(aColumns);
+ aInfo->SetFieldAlias(aColumnAlias);
+ aInfo->SetFunctionType(FKT_NUMERIC | FKT_OTHER);
+
+ eErrorCode = _pView->InsertField(aInfo, bFirstField);
+ bFirstField = false;
+ }
+
+ break;
+ }
+
+ OSL_FAIL( "InstallFields: don't know how to interpret this parse node!" );
+
+ } while ( false );
+ }
+ }
+ else
+ eErrorCode = eStatementTooComplex;
+
+ return eErrorCode;
+ }
+ SqlParseError GetOrderCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode* pParseRoot )
+ {
+ SqlParseError eErrorCode = eOk;
+ if (!pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->isLeaf())
+ {
+ ::connectivity::OSQLParseNode* pNode = pParseRoot->getChild(3)->getChild(ORDER_BY_CHILD_POS)->getChild(2);
+ ::connectivity::OSQLParseNode* pParamRef = nullptr;
+
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+ EOrderDir eOrderDir;
+ for( size_t i=0 ; i<pNode->count() ; i++ )
+ {
+ OTableFieldDescRef aDragLeft = new OTableFieldDesc();
+ eOrderDir = ORDER_ASC;
+ ::connectivity::OSQLParseNode* pChild = pNode->getChild( i );
+
+ if (SQL_ISTOKEN( pChild->getChild(1), DESC ) )
+ eOrderDir = ORDER_DESC;
+
+ ::connectivity::OSQLParseNode* pArgument = pChild->getChild(0);
+
+ if(SQL_ISRULE(pArgument,column_ref))
+ {
+ if( eOk == FillDragInfo(_pView,pArgument,aDragLeft))
+ _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i);
+ else // it could be an alias name for a field
+ {
+ OUString aTableRange,aColumnName;
+ ::connectivity::OSQLParseTreeIterator& rParseIter = rController.getParseIterator();
+ rParseIter.getColumnRange( pArgument, aColumnName, aTableRange );
+
+ OTableFields& aList = rController.getTableFieldDesc();
+ for (auto const& elem : aList)
+ {
+ if(elem.is() && elem->GetFieldAlias() == aColumnName)
+ elem->SetOrderDir( eOrderDir );
+ }
+ }
+ }
+ else if(SQL_ISRULE(pArgument, general_set_fct ) &&
+ SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
+ eOk == FillDragInfo(_pView,pParamRef,aDragLeft))
+ _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
+ else if( SQL_ISRULE(pArgument, set_fct_spec ) )
+ {
+
+ Reference< XConnection> xConnection = rController.getConnection();
+ if(xConnection.is())
+ {
+ OUString sCondition;
+ pArgument->parseNodeToPredicateStr(sCondition,
+ xConnection,
+ rController.getNumberFormatter(),
+ _pView->getLocale(),
+ _pView->getDecimalSeparator(),
+ &rController.getParser().getContext());
+ _pView->fillFunctionInfo(pArgument,sCondition,aDragLeft);
+ aDragLeft->SetFunctionType(FKT_OTHER);
+ aDragLeft->SetOrderDir(eOrderDir);
+ aDragLeft->SetVisible(false);
+ _pSelectionBrw->AddOrder( aDragLeft, eOrderDir, i );
+ }
+ else
+ eErrorCode = eColumnNotFound;
+ }
+ else
+ eErrorCode = eColumnNotFound;
+ }
+ }
+ return eErrorCode;
+ }
+ SqlParseError GetHavingCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode* pSelectRoot,
+ sal_uInt16& rLevel )
+ {
+ SqlParseError eErrorCode = eOk;
+ if (!pSelectRoot->getChild(3)->getChild(3)->isLeaf())
+ eErrorCode = GetORCriteria(_pView,_pSelectionBrw,pSelectRoot->getChild(3)->getChild(3)->getChild(1),rLevel, true);
+ return eErrorCode;
+ }
+ SqlParseError GetGroupCriteria( OQueryDesignView* _pView,
+ OSelectionBrowseBox* _pSelectionBrw,
+ const ::connectivity::OSQLParseNode* pSelectRoot )
+ {
+ SqlParseError eErrorCode = eOk;
+ if (!pSelectRoot->getChild(3)->getChild(2)->isLeaf()) // opt_group_by_clause
+ {
+ OQueryController& rController = static_cast<OQueryController&>(_pView->getController());
+ ::connectivity::OSQLParseNode* pGroupBy = pSelectRoot->getChild(3)->getChild(2)->getChild(2);
+
+ for( size_t i=0 ; i < pGroupBy->count() && eOk == eErrorCode; ++i )
+ {
+ OTableFieldDescRef aDragInfo = new OTableFieldDesc();
+ ::connectivity::OSQLParseNode* pParamRef = nullptr;
+ ::connectivity::OSQLParseNode* pArgument = pGroupBy->getChild( i );
+ if(SQL_ISRULE(pArgument,column_ref))
+ {
+ if ( eOk == (eErrorCode = FillDragInfo(_pView,pArgument,aDragInfo)) )
+ {
+ aDragInfo->SetGroupBy(true);
+ _pSelectionBrw->AddGroupBy(aDragInfo);
+ }
+ }
+ else if(SQL_ISRULE(pArgument, general_set_fct ) &&
+ SQL_ISRULE(pParamRef = pArgument->getChild(pArgument->count()-2),column_ref) &&
+ eOk == FillDragInfo(_pView,pParamRef,aDragInfo))
+ {
+ aDragInfo->SetGroupBy(true);
+ _pSelectionBrw->AddGroupBy( aDragInfo );
+ }
+ else if( SQL_ISRULE(pArgument, set_fct_spec ) )
+ {
+ Reference< XConnection> xConnection = rController.getConnection();
+ if(xConnection.is())
+ {
+ OUString sGroupByExpression;
+ pArgument->parseNodeToStr( sGroupByExpression,
+ xConnection,
+ &rController.getParser().getContext(),
+ true); // quote is to true because we need quoted elements inside the function
+ _pView->fillFunctionInfo(pArgument,sGroupByExpression,aDragInfo);
+ aDragInfo->SetFunctionType(FKT_OTHER);
+ aDragInfo->SetGroupBy(true);
+ aDragInfo->SetVisible(false);
+ _pSelectionBrw->AddGroupBy( aDragInfo );
+ }
+ else
+ eErrorCode = eColumnNotFound;
+ }
+ }
+ }
+ return eErrorCode;
+ }
+
+ OUString getParseErrorMessage( SqlParseError _eErrorCode )
+ {
+ TranslateId pResId;
+ switch (_eErrorCode)
+ {
+ case eIllegalJoin:
+ pResId = STR_QRY_ILLEGAL_JOIN;
+ break;
+ case eStatementTooLong:
+ pResId = STR_QRY_TOO_LONG_STATEMENT;
+ break;
+ case eNoConnection:
+ pResId = STR_QRY_SYNTAX;
+ break;
+ case eNoSelectStatement:
+ pResId = STR_QRY_NOSELECT;
+ break;
+ case eNoColumnInLike:
+ pResId = STR_QRY_SYNTAX;
+ break;
+ case eColumnNotFound:
+ pResId = STR_QRY_SYNTAX;
+ break;
+ case eNativeMode:
+ pResId = STR_QRY_NATIVE;
+ break;
+ case eTooManyTables:
+ pResId = STR_QRY_TOO_MANY_TABLES;
+ break;
+ case eTooManyColumns:
+ pResId = STR_QRY_TOO_MANY_COLUMNS;
+ break;
+ case eStatementTooComplex:
+ pResId = STR_QRY_TOOCOMPLEX;
+ break;
+ default:
+ pResId = STR_QRY_SYNTAX;
+ break;
+ }
+ return DBA_RES(pResId);
+ }
+}
+
+// end of anonymous namespace
+
+OQueryDesignView::OQueryDesignView( OQueryContainerWindow* _pParent,
+ OQueryController& _rController,
+ const Reference< XComponentContext >& _rxContext)
+ :OJoinDesignView( _pParent, _rController, _rxContext )
+ ,m_aSplitter( VclPtr<Splitter>::Create(this) )
+ ,m_eChildFocus(NONE)
+ ,m_bInSplitHandler( false )
+{
+
+ try
+ {
+ SvtSysLocale aSysLocale;
+ m_aLocale = aSysLocale.GetLanguageTag().getLocale();
+ m_sDecimalSep = aSysLocale.GetLocaleData().getNumDecimalSep();
+ }
+ catch(Exception&)
+ {
+ }
+
+ m_pSelectionBox = VclPtr<OSelectionBrowseBox>::Create(this);
+
+ setNoneVisibleRow(static_cast<OQueryController&>(getController()).getVisibleRows());
+ m_pSelectionBox->Show();
+ // setup Splitter
+ m_aSplitter->SetSplitHdl(LINK(this, OQueryDesignView,SplitHdl));
+ m_aSplitter->Show();
+
+}
+
+OQueryDesignView::~OQueryDesignView()
+{
+ disposeOnce();
+}
+
+void OQueryDesignView::dispose()
+{
+ if ( m_pTableView )
+ ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::RemoveWindow));
+ m_pSelectionBox.disposeAndClear();
+ m_aSplitter.disposeAndClear();
+ OJoinDesignView::dispose();
+}
+
+IMPL_LINK_NOARG( OQueryDesignView, SplitHdl, Splitter*, void )
+{
+ if (!getController().isReadOnly())
+ {
+ m_bInSplitHandler = true;
+ m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),m_aSplitter->GetSplitPosPixel() ) );
+ static_cast<OQueryController&>(getController()).setSplitPos(m_aSplitter->GetSplitPosPixel());
+ static_cast<OQueryController&>(getController()).setModified( true );
+ Resize();
+ m_bInSplitHandler = true;
+ }
+}
+
+void OQueryDesignView::Construct()
+{
+ m_pTableView = VclPtr<OQueryTableView>::Create(m_pScrollWindow,this);
+ ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow));
+ OJoinDesignView::Construct();
+}
+
+void OQueryDesignView::initialize()
+{
+ if(static_cast<OQueryController&>(getController()).getSplitPos() != -1)
+ {
+ m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),static_cast<OQueryController&>(getController()).getSplitPos() ) );
+ m_aSplitter->SetSplitPosPixel(static_cast<OQueryController&>(getController()).getSplitPos());
+ }
+ m_pSelectionBox->initialize();
+ reset();
+}
+
+void OQueryDesignView::resizeDocumentView(tools::Rectangle& _rPlayground)
+{
+ Point aPlaygroundPos( _rPlayground.TopLeft() );
+ Size aPlaygroundSize( _rPlayground.GetSize() );
+
+ // calc the split pos, and forward it to the controller
+ sal_Int32 nSplitPos = static_cast<OQueryController&>(getController()).getSplitPos();
+ if ( 0 != aPlaygroundSize.Height() )
+ {
+ if ( ( -1 == nSplitPos )
+ || ( nSplitPos >= aPlaygroundSize.Height() )
+ )
+ {
+ // let the selection browse box determine an optimal size
+ Size aSelectionBoxSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
+ nSplitPos = aPlaygroundSize.Height() - aSelectionBoxSize.Height() - m_aSplitter->GetSizePixel().Height();
+ // still an invalid size?
+ if ( nSplitPos == -1 || nSplitPos >= aPlaygroundSize.Height() )
+ nSplitPos = sal_Int32(aPlaygroundSize.Height()*0.6);
+
+ static_cast<OQueryController&>(getController()).setSplitPos(nSplitPos);
+ }
+
+ if ( !m_bInSplitHandler )
+ { // the resize is triggered by something else than the split handler
+ // our main focus is to try to preserve the size of the selectionbrowse box
+ Size aSelBoxSize = m_pSelectionBox->GetSizePixel();
+ if ( aSelBoxSize.Height() )
+ {
+ // keep the size of the sel box constant
+ nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxSize.Height();
+
+ // and if the box is smaller than the optimal size, try to do something about it
+ Size aSelBoxOptSize = m_pSelectionBox->CalcOptimalSize( aPlaygroundSize );
+ if ( aSelBoxOptSize.Height() > aSelBoxSize.Height() )
+ {
+ nSplitPos = aPlaygroundSize.Height() - m_aSplitter->GetSizePixel().Height() - aSelBoxOptSize.Height();
+ }
+
+ static_cast< OQueryController& >(getController()).setSplitPos( nSplitPos );
+ }
+ }
+ }
+
+ // normalize the split pos
+ Point aSplitPos( _rPlayground.Left(), nSplitPos );
+ Size aSplitSize( _rPlayground.GetSize().Width(), m_aSplitter->GetSizePixel().Height() );
+
+ if( ( aSplitPos.Y() + aSplitSize.Height() ) > ( aPlaygroundSize.Height() ))
+ aSplitPos.setY( aPlaygroundSize.Height() - aSplitSize.Height() );
+
+ if( aSplitPos.Y() <= aPlaygroundPos.Y() )
+ aSplitPos.setY( aPlaygroundPos.Y() + sal_Int32(aPlaygroundSize.Height() * 0.2) );
+
+ // position the table
+ Size aTableViewSize(aPlaygroundSize.Width(), aSplitPos.Y() - aPlaygroundPos.Y());
+ m_pScrollWindow->SetPosSizePixel(aPlaygroundPos, aTableViewSize);
+
+ // position the selection browse box
+ Point aPos( aPlaygroundPos.X(), aSplitPos.Y() + aSplitSize.Height() );
+ m_pSelectionBox->SetPosSizePixel( aPos, Size( aPlaygroundSize.Width(), aPlaygroundSize.Height() - aSplitSize.Height() - aTableViewSize.Height() ));
+
+ // set the size of the splitter
+ m_aSplitter->SetPosSizePixel( aSplitPos, aSplitSize );
+ m_aSplitter->SetDragRectPixel( _rPlayground );
+
+ // just for completeness: there is no space left, we occupied it all ...
+ _rPlayground.SetPos( _rPlayground.BottomRight() );
+ _rPlayground.SetSize( Size( 0, 0 ) );
+}
+
+void OQueryDesignView::setReadOnly(bool _bReadOnly)
+{
+ m_pSelectionBox->SetReadOnly(_bReadOnly);
+}
+
+void OQueryDesignView::clear()
+{
+ m_pSelectionBox->ClearAll(); // clear the whole selection
+ m_pTableView->ClearAll();
+}
+
+void OQueryDesignView::copy()
+{
+ if( m_eChildFocus == SELECTION)
+ m_pSelectionBox->copy();
+}
+
+bool OQueryDesignView::isCutAllowed() const
+{
+ bool bAllowed = false;
+ if ( SELECTION == m_eChildFocus )
+ bAllowed = m_pSelectionBox->isCutAllowed();
+ return bAllowed;
+}
+
+bool OQueryDesignView::isPasteAllowed() const
+{
+ bool bAllowed = false;
+ if ( SELECTION == m_eChildFocus )
+ bAllowed = m_pSelectionBox->isPasteAllowed();
+ return bAllowed;
+}
+
+bool OQueryDesignView::isCopyAllowed() const
+{
+ bool bAllowed = false;
+ if ( SELECTION == m_eChildFocus )
+ bAllowed = m_pSelectionBox->isCopyAllowed();
+ return bAllowed;
+}
+
+void OQueryDesignView::stopTimer()
+{
+ m_pSelectionBox->stopTimer();
+}
+
+void OQueryDesignView::startTimer()
+{
+ m_pSelectionBox->startTimer();
+}
+
+void OQueryDesignView::cut()
+{
+ if( m_eChildFocus == SELECTION)
+ {
+ m_pSelectionBox->cut();
+ static_cast<OQueryController&>(getController()).setModified(true);
+ }
+}
+
+void OQueryDesignView::paste()
+{
+ if( m_eChildFocus == SELECTION)
+ {
+ m_pSelectionBox->paste();
+ static_cast<OQueryController&>(getController()).setModified(true);
+ }
+}
+
+void OQueryDesignView::TableDeleted(const OUString& rAliasName)
+{
+ // message that the table was removed from the window
+ m_pSelectionBox->DeleteFields( rAliasName );
+ static_cast<OQueryController&>(getController()).InvalidateFeature(ID_BROWSER_ADDTABLE); // inform the view again
+}
+
+bool OQueryDesignView::HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const
+{
+ return m_pSelectionBox->HasFieldByAliasName( rFieldName, rInfo);
+}
+
+SqlParseError OQueryDesignView::InsertField( const OTableFieldDescRef& rInfo, bool bActivate)
+{
+ return m_pSelectionBox->InsertField( rInfo, BROWSER_INVALIDID, true/*bVis*/, bActivate ).is() ? eOk : eTooManyColumns;
+}
+
+sal_Int32 OQueryDesignView::getColWidth(sal_uInt16 _nColPos) const
+{
+ static sal_Int32 s_nDefaultWidth = GetTextWidth("0") * 15;
+ sal_Int32 nWidth = static_cast<OQueryController&>(getController()).getColWidth(_nColPos);
+ if ( !nWidth )
+ nWidth = s_nDefaultWidth;
+ return nWidth;
+}
+
+void OQueryDesignView::fillValidFields(std::u16string_view sAliasName, weld::ComboBox& rFieldList)
+{
+ rFieldList.clear();
+
+ bool bAllTables = sAliasName.empty();
+
+ OJoinTableView::OTableWindowMap& rTabWins = m_pTableView->GetTabWinMap();
+ OUString strCurrentPrefix;
+ std::vector< OUString> aFields;
+ for (auto const& tabWin : rTabWins)
+ {
+ OQueryTableWindow* pCurrentWin = static_cast<OQueryTableWindow*>(tabWin.second.get());
+ if (bAllTables || (pCurrentWin->GetAliasName() == sAliasName))
+ {
+ strCurrentPrefix = pCurrentWin->GetAliasName() + ".";
+
+ pCurrentWin->EnumValidFields(aFields);
+
+ for (auto const& field : aFields)
+ {
+ if (bAllTables || field.toChar() == '*')
+ rFieldList.append_text(strCurrentPrefix + field);
+ else
+ rFieldList.append_text(field);
+ }
+
+ if (!bAllTables)
+ // this means that I came into this block because the table name was exactly what I was looking for so I can end here
+ // (and I prevent that fields get added more than once, if a table is repeated in TabWin)
+ break;
+ }
+ }
+}
+
+bool OQueryDesignView::PreNotify(NotifyEvent& rNEvt)
+{
+ if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
+ {
+ if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() )
+ m_eChildFocus = SELECTION;
+ else
+ m_eChildFocus = TABLEVIEW;
+ }
+
+ return OJoinDesignView::PreNotify(rNEvt);
+}
+
+// check if the statement is correct when not returning false
+bool OQueryDesignView::checkStatement()
+{
+ bool bRet = true;
+ if ( m_pSelectionBox )
+ bRet = m_pSelectionBox->Save(); // an error occurred so we return no
+ return bRet;
+}
+
+OUString OQueryDesignView::getStatement()
+{
+ OQueryController& rController = static_cast<OQueryController&>(getController());
+ m_rController.clearError();
+ // used for fields which aren't any longer in the statement
+ OTableFields& rUnUsedFields = rController.getUnUsedFields();
+ OTableFields().swap( rUnUsedFields );
+
+ // create the select columns
+ sal_uInt32 nFieldcount = 0;
+ OTableFields& rFieldList = rController.getTableFieldDesc();
+ for (auto const& field : rFieldList)
+ {
+ if (!field->GetField().isEmpty() && field->IsVisible() )
+ ++nFieldcount;
+ else if (!field->GetField().isEmpty() &&
+ !field->HasCriteria() &&
+ field->isNoneFunction() &&
+ field->GetOrderDir() == ORDER_NONE &&
+ !field->IsGroupBy() &&
+ field->GetFunction().isEmpty() )
+ rUnUsedFields.push_back(field);
+ }
+ if ( !nFieldcount ) // no visible fields so return
+ {
+ rUnUsedFields = rFieldList;
+ return OUString();
+ }
+
+ OQueryTableView::OTableWindowMap& rTabList = m_pTableView->GetTabWinMap();
+ sal_uInt32 nTabcount = rTabList.size();
+
+ OUString aFieldListStr(GenerateSelectList(this,rFieldList,nTabcount>1));
+ if( aFieldListStr.isEmpty() )
+ return OUString();
+
+ // Exception handling, if no fields have been passed we should not
+ // change the tab page
+ // TabBarSelectHdl will query the SQL-OUString for STATEMENT_NOFIELDS
+ // and trigger an error message
+ // ----------------- Build table list ----------------------
+
+ const auto& rConnList = m_pTableView->getTableConnections();
+ Reference< XConnection> xConnection = rController.getConnection();
+ OUString aTableListStr(GenerateFromClause(xConnection,&rTabList,rConnList));
+ OSL_ENSURE(!aTableListStr.isEmpty(), "OQueryDesignView::getStatement() : unexpected : have Fields, but no Tables !");
+ // if fields exist now, these only can be created by inserting from an already existing table; if on the other hand
+ // a table is deleted, also the belonging fields will be deleted -> therefore it CANNOT occur that fields
+ // exist but no tables exist (and aFieldListStr has its length, I secure this above)
+ OUStringBuffer aHavingStr,aCriteriaListStr;
+
+ // ----------------- build the criteria ----------------------
+ if (!GenerateCriterias(this,aCriteriaListStr,aHavingStr,rFieldList, nTabcount > 1))
+ return OUString();
+
+ OUString aJoinCrit;
+ GenerateInnerJoinCriterias(xConnection,aJoinCrit,rConnList);
+ if(!aJoinCrit.isEmpty())
+ {
+ OUString aTmp = "( " + aJoinCrit + " )";
+ if(!aCriteriaListStr.isEmpty())
+ {
+ aTmp += C_AND;
+ }
+ aCriteriaListStr.insert(0, aTmp);
+ }
+ // ----------------- construct statement ----------------------
+ OUStringBuffer aSqlCmd("SELECT ");
+ if(rController.isDistinct())
+ aSqlCmd.append(" DISTINCT ");
+ aSqlCmd.append(aFieldListStr);
+ aSqlCmd.append(" FROM ");
+ aSqlCmd.append(aTableListStr);
+
+ if (!aCriteriaListStr.isEmpty())
+ {
+ aSqlCmd.append(" WHERE ");
+ aSqlCmd.append(aCriteriaListStr);
+ }
+ Reference<XDatabaseMetaData> xMeta;
+ if ( xConnection.is() )
+ xMeta = xConnection->getMetaData();
+ bool bUseAlias = nTabcount > 1;
+ if ( xMeta.is() )
+ bUseAlias = bUseAlias || !xMeta->supportsGroupByUnrelated();
+
+ aSqlCmd.append(GenerateGroupBy(this,rFieldList,bUseAlias));
+ // ----------------- construct GroupBy and attach ------------
+ if(!aHavingStr.isEmpty())
+ {
+ aSqlCmd.append(" HAVING ");
+ aSqlCmd.append(aHavingStr);
+ }
+ // ----------------- construct sorting and attach ------------
+ OUString sOrder;
+ SqlParseError eErrorCode = eOk;
+ if ( (eErrorCode = GenerateOrder(this,rFieldList,nTabcount > 1,sOrder)) == eOk)
+ aSqlCmd.append(sOrder);
+ else
+ {
+ if ( !m_rController.hasError() )
+ m_rController.appendError( getParseErrorMessage( eErrorCode ) );
+
+ m_rController.displayError();
+ }
+ // --------------------- Limit Clause -------------------
+ {
+ const sal_Int64 nLimit = rController.getLimit();
+ if( nLimit != -1 )
+ {
+ aSqlCmd.append( " LIMIT " + OUString::number(nLimit) );
+ }
+ }
+
+ OUString sSQL = aSqlCmd.makeStringAndClear();
+ if ( xConnection.is() )
+ {
+ ::connectivity::OSQLParser& rParser( rController.getParser() );
+ OUString sErrorMessage;
+ std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( sErrorMessage, sSQL, true ) );
+ if (pParseNode)
+ {
+ OSQLParseNode* pNode = pParseNode->getChild(3)->getChild(1);
+ if ( pNode->count() > 1 )
+ {
+ ::connectivity::OSQLParseNode * pCondition = pNode->getChild(1);
+ if ( pCondition ) // no where clause
+ {
+ OSQLParseNode::compress(pCondition);
+ OUString sTemp;
+ pParseNode->parseNodeToStr(sTemp,xConnection);
+ sSQL = sTemp;
+ }
+ }
+ }
+ }
+ return sSQL;
+}
+
+void OQueryDesignView::setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable)
+{
+ sal_uInt16 nRow;
+ switch (_nSlotId)
+ {
+ case SID_QUERY_VIEW_FUNCTIONS:
+ nRow = BROW_FUNCTION_ROW;
+ break;
+ case SID_QUERY_VIEW_TABLES:
+ nRow = BROW_TABLE_ROW;
+ break;
+ case SID_QUERY_VIEW_ALIASES:
+ nRow = BROW_COLUMNALIAS_ROW;
+ break;
+ default:
+ // ????????????
+ nRow = 0;
+ break;
+ }
+ m_pSelectionBox->SetRowVisible(nRow,_bEnable);
+ m_pSelectionBox->Invalidate();
+}
+
+bool OQueryDesignView::isSlotEnabled(sal_Int32 _nSlotId)
+{
+ sal_uInt16 nRow;
+ switch (_nSlotId)
+ {
+ case SID_QUERY_VIEW_FUNCTIONS:
+ nRow = BROW_FUNCTION_ROW;
+ break;
+ case SID_QUERY_VIEW_TABLES:
+ nRow = BROW_TABLE_ROW;
+ break;
+ case SID_QUERY_VIEW_ALIASES:
+ nRow = BROW_COLUMNALIAS_ROW;
+ break;
+ default:
+ // ?????????
+ nRow = 0;
+ break;
+ }
+ return m_pSelectionBox->IsRowVisible(nRow);
+}
+
+void OQueryDesignView::SaveUIConfig()
+{
+ OQueryController& rCtrl = static_cast<OQueryController&>(getController());
+ rCtrl.SaveTabWinsPosSize( &m_pTableView->GetTabWinMap(), m_pScrollWindow->GetHScrollBar().GetThumbPos(), m_pScrollWindow->GetVScrollBar().GetThumbPos() );
+ rCtrl.setVisibleRows( m_pSelectionBox->GetNoneVisibleRows() );
+ if ( m_aSplitter->GetSplitPosPixel() != 0 )
+ rCtrl.setSplitPos( m_aSplitter->GetSplitPosPixel() );
+}
+
+std::unique_ptr<OSQLParseNode> OQueryDesignView::getPredicateTreeFromEntry(const OTableFieldDescRef& pEntry,
+ const OUString& _sCriteria,
+ OUString& _rsErrorMessage,
+ Reference<XPropertySet>& _rxColumn) const
+{
+ OSL_ENSURE(pEntry.is(),"Entry is null!");
+ if(!pEntry.is())
+ return nullptr;
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getController()).getConnection();
+ if(!xConnection.is())
+ return nullptr;
+
+ ::connectivity::OSQLParser& rParser( static_cast<OQueryController&>(getController()).getParser() );
+ OQueryTableWindow* pWin = static_cast<OQueryTableWindow*>(pEntry->GetTabWindow());
+
+ // special handling for functions
+ if ( pEntry->GetFunctionType() & (FKT_OTHER | FKT_AGGREGATE | FKT_NUMERIC) )
+ {
+ // we have a function here so we have to distinguish the type of return value
+ OUString sFunction;
+ if ( pEntry->isNumericOrAggregateFunction() )
+ sFunction = pEntry->GetFunction().getToken(0, '(');
+
+ if ( sFunction.isEmpty() )
+ sFunction = pEntry->GetField().getToken(0, '(');
+
+ sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sFunction,&rParser.getContext());
+ if ( nType == DataType::OTHER || (sFunction.isEmpty() && pEntry->isNumericOrAggregateFunction()) )
+ {
+ // first try the international version
+ OUString sSql = "SELECT * FROM x WHERE " + pEntry->GetField() + _sCriteria;
+ std::unique_ptr<OSQLParseNode> pParseNode( rParser.parseTree( _rsErrorMessage, sSql, true ) );
+ nType = DataType::DOUBLE;
+ if (pParseNode)
+ {
+ OSQLParseNode* pColumnRef = pParseNode->getByRule(OSQLParseNode::column_ref);
+ if ( pColumnRef )
+ {
+ OTableFieldDescRef aField = new OTableFieldDesc();
+ if ( eOk == FillDragInfo(this,pColumnRef,aField) )
+ {
+ nType = aField->GetDataType();
+ }
+ }
+ }
+ }
+
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ rtl::Reference<parse::OParseColumn> pColumn = new parse::OParseColumn( pEntry->GetField(),
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ OUString(),
+ OUString(),
+ OUString());
+ _rxColumn = pColumn;
+ pColumn->setFunction(true);
+ pColumn->setRealName(pEntry->GetField());
+ }
+ else
+ {
+ if (pWin)
+ {
+ Reference<XNameAccess> xColumns = pWin->GetOriginalColumns();
+ if (xColumns.is() && xColumns->hasByName(pEntry->GetField()))
+ xColumns->getByName(pEntry->GetField()) >>= _rxColumn;
+ }
+ }
+
+ // _rxColumn, if it is a "lookup" column, not a computed column,
+ // is guaranteed to be the column taken from the *source* of the column,
+ // that is either a table or another query.
+ // _rxColumn is *not* taken from the columns of the query we are constructing
+ // (and rightfully so, since it may not be part of these columns; SELECT A FROM t WHERE B = foo)
+ // If it is a computed column, we just constructed it above, with same Name and RealName.
+ // In all cases, we should use the "external" name of the column, not the "RealName";
+ // the latter is the name that the column had in the source of the source query.
+ // An example: we are designing "SELECT A, B FROM q WHERE C='foo'"
+ // q itself is query "SELECT aye AS A, bee as B, cee as C FROM t"
+ // We are currently treating the entry "C='foo'"
+ // Then _rxColumn has Name "C" and RealName "cee". We should *obviously* use "C", not "cee".
+ std::unique_ptr<OSQLParseNode> pParseNode = rParser.predicateTree( _rsErrorMessage,
+ _sCriteria,
+ static_cast<OQueryController&>(getController()).getNumberFormatter(),
+ _rxColumn,
+ false);
+ return pParseNode;
+}
+
+void OQueryDesignView::GetFocus()
+{
+ OJoinDesignView::GetFocus();
+ if ( m_pSelectionBox && !m_pSelectionBox->HasChildPathFocus() )
+ {
+ // first we have to deactivate the current cell to refill when necessary
+ m_pSelectionBox->DeactivateCell();
+ m_pSelectionBox->ActivateCell(m_pSelectionBox->GetCurRow(), m_pSelectionBox->GetCurColumnId());
+ m_pSelectionBox->GrabFocus();
+ }
+}
+
+void OQueryDesignView::reset()
+{
+ m_pTableView->ClearAll();
+ m_pTableView->ReSync();
+}
+
+void OQueryDesignView::setNoneVisibleRow(sal_Int32 _nRows)
+{
+ m_pSelectionBox->SetNoneVisibleRow(_nRows);
+}
+
+void OQueryDesignView::initByFieldDescriptions( const Sequence< PropertyValue >& i_rFieldDescriptions )
+{
+ OQueryController& rController = static_cast< OQueryController& >( getController() );
+
+ m_pSelectionBox->PreFill();
+ m_pSelectionBox->SetReadOnly( rController.isReadOnly() );
+ m_pSelectionBox->Fill();
+
+ for ( auto const & field : i_rFieldDescriptions )
+ {
+ ::rtl::Reference< OTableFieldDesc > pField( new OTableFieldDesc() );
+ pField->Load( field, true );
+ InsertField( pField, false );
+ }
+
+ rController.ClearUndoManager();
+ m_pSelectionBox->Invalidate();
+}
+
+bool OQueryDesignView::initByParseIterator( ::dbtools::SQLExceptionInfo* _pErrorInfo )
+{
+ SqlParseError eErrorCode = eNativeMode;
+ m_rController.clearError();
+
+ try
+ {
+ eErrorCode = InitFromParseNodeImpl( this, m_pSelectionBox );
+
+ if ( eErrorCode != eOk )
+ {
+ if ( !m_rController.hasError() )
+ m_rController.appendError( getParseErrorMessage( eErrorCode ) );
+
+ if ( _pErrorInfo )
+ {
+ *_pErrorInfo = m_rController.getError();
+ }
+ else
+ {
+ m_rController.displayError();
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return eErrorCode == eOk;
+}
+
+// Utility function for fillFunctionInfo
+namespace {
+ sal_Int32 char_datatype(const::connectivity::OSQLParseNode* pDataType, const unsigned int offset) {
+ int cnt = pDataType->count() - offset;
+ if ( cnt < 0 )
+ {
+ OSL_FAIL("internal error in decoding character datatype specification");
+ return DataType::VARCHAR;
+ }
+ else if ( cnt == 0 )
+ {
+ if ( offset == 0 )
+ {
+ // The datatype is the node itself
+ if ( SQL_ISTOKENOR2 (pDataType, CHARACTER, CHAR) )
+ return DataType::CHAR;
+ else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
+ return DataType::VARCHAR;
+ else if ( SQL_ISTOKEN (pDataType, CLOB) )
+ return DataType::CLOB;
+ else
+ {
+ OSL_FAIL("unknown/unexpected token in decoding character datatype specification");
+ return DataType::VARCHAR;
+ }
+ }
+ else
+ {
+ // No child left to read!
+ OSL_FAIL("incomplete datatype in decoding character datatype specification");
+ return DataType::VARCHAR;
+ }
+ }
+
+ if ( SQL_ISTOKEN(pDataType->getChild(offset), NATIONAL) )
+ return char_datatype(pDataType, offset+1);
+ else if ( SQL_ISTOKENOR3(pDataType->getChild(offset), CHARACTER, CHAR, NCHAR) )
+ {
+ if ( cnt > 2 && SQL_ISTOKEN(pDataType->getChild(offset+1), LARGE) && SQL_ISTOKEN(pDataType->getChild(offset+2), OBJECT) )
+ return DataType::CLOB;
+ else if ( cnt > 1 && SQL_ISTOKEN(pDataType->getChild(offset+1), VARYING) )
+ return DataType::VARCHAR;
+ else
+ return DataType::CHAR;
+ }
+ else if ( SQL_ISTOKEN (pDataType->getChild(offset), VARCHAR) )
+ return DataType::VARCHAR;
+ else if ( SQL_ISTOKENOR2 (pDataType->getChild(offset), CLOB, NCLOB) )
+ return DataType::CLOB;
+
+ OSL_FAIL("unrecognised character datatype");
+ return DataType::VARCHAR;
+ }
+}
+
+// Try to guess the type of an expression in simple cases.
+// Originally meant to be called only on a function call (hence the misnomer),
+// but now tries to do the best it can also in other cases.
+// Don't completely rely on fillFunctionInfo,
+// it won't look at the function's arguments to find the return type
+// (in particular, in the case of general_set_fct,
+// the return type is the type of the argument;
+// if that is (as is typical) a column reference,
+// it is the type of the column).
+// TODO: There is similar "guess the expression's type" code in several places:
+// SelectionBrowseBox.cxx: OSelectionBrowseBox::saveField
+// QueryDesignView.cxx: InstallFields, GetOrderCriteria, GetGroupCriteria
+// If possible, they should be factorised into this function
+// (which should then be renamed...)
+
+void OQueryDesignView::fillFunctionInfo( const ::connectivity::OSQLParseNode* pNode
+ ,const OUString& sFunctionTerm
+ ,OTableFieldDescRef& aInfo)
+{
+ // get the type of the expression, as far as easily possible
+ OQueryController& rController = static_cast<OQueryController&>(getController());
+ sal_Int32 nDataType = DataType::DOUBLE;
+ switch(pNode->getNodeType())
+ {
+ case SQLNodeType::Concat:
+ case SQLNodeType::String:
+ nDataType = DataType::VARCHAR;
+ break;
+ case SQLNodeType::IntNum:
+ nDataType = DataType::INTEGER;
+ break;
+ case SQLNodeType::ApproxNum:
+ nDataType = DataType::DOUBLE;
+ break;
+ case SQLNodeType::AccessDate:
+ nDataType = DataType::TIMESTAMP;
+ break;
+ case SQLNodeType::Equal:
+ case SQLNodeType::Less:
+ case SQLNodeType::Great:
+ case SQLNodeType::LessEq:
+ case SQLNodeType::GreatEq:
+ case SQLNodeType::NotEqual:
+ nDataType = DataType::BOOLEAN;
+ break;
+ case SQLNodeType::Name:
+ case SQLNodeType::ListRule:
+ case SQLNodeType::CommaListRule:
+ case SQLNodeType::Keyword:
+ case SQLNodeType::Punctuation:
+ OSL_FAIL("Unexpected SQL Node Type");
+ break;
+ case SQLNodeType::Rule:
+ switch(pNode->getKnownRuleID())
+ {
+ case OSQLParseNode::select_statement:
+ case OSQLParseNode::table_exp:
+ case OSQLParseNode::table_ref_commalist:
+ case OSQLParseNode::table_ref:
+ case OSQLParseNode::catalog_name:
+ case OSQLParseNode::schema_name:
+ case OSQLParseNode::table_name:
+ case OSQLParseNode::opt_column_commalist:
+ case OSQLParseNode::column_commalist:
+ case OSQLParseNode::column_ref_commalist:
+ case OSQLParseNode::column_ref:
+ case OSQLParseNode::opt_order_by_clause:
+ case OSQLParseNode::ordering_spec_commalist:
+ case OSQLParseNode::ordering_spec:
+ case OSQLParseNode::opt_asc_desc:
+ case OSQLParseNode::where_clause:
+ case OSQLParseNode::opt_where_clause:
+ case OSQLParseNode::opt_escape:
+ case OSQLParseNode::scalar_exp_commalist:
+ case OSQLParseNode::scalar_exp: // Seems to never be generated?
+ case OSQLParseNode::parameter_ref:
+ case OSQLParseNode::parameter:
+ case OSQLParseNode::range_variable:
+ case OSQLParseNode::delete_statement_positioned:
+ case OSQLParseNode::delete_statement_searched:
+ case OSQLParseNode::update_statement_positioned:
+ case OSQLParseNode::update_statement_searched:
+ case OSQLParseNode::assignment_commalist:
+ case OSQLParseNode::assignment:
+ case OSQLParseNode::insert_statement:
+ case OSQLParseNode::insert_atom_commalist:
+ case OSQLParseNode::insert_atom:
+ case OSQLParseNode::from_clause:
+ case OSQLParseNode::qualified_join:
+ case OSQLParseNode::cross_union:
+ case OSQLParseNode::select_sublist:
+ case OSQLParseNode::join_type:
+ case OSQLParseNode::named_columns_join:
+ case OSQLParseNode::joined_table:
+ case OSQLParseNode::sql_not:
+ case OSQLParseNode::manipulative_statement:
+ case OSQLParseNode::value_exp_commalist:
+ case OSQLParseNode::union_statement:
+ case OSQLParseNode::outer_join_type:
+ case OSQLParseNode::selection:
+ case OSQLParseNode::base_table_def:
+ case OSQLParseNode::base_table_element_commalist:
+ case OSQLParseNode::data_type:
+ case OSQLParseNode::column_def:
+ case OSQLParseNode::table_node:
+ case OSQLParseNode::as_clause:
+ case OSQLParseNode::opt_as:
+ case OSQLParseNode::op_column_commalist:
+ case OSQLParseNode::table_primary_as_range_column:
+ case OSQLParseNode::character_string_type:
+ case OSQLParseNode::comparison:
+ OSL_FAIL("Unexpected SQL RuleID");
+ break;
+ case OSQLParseNode::column:
+ case OSQLParseNode::column_val:
+ OSL_FAIL("Cannot guess column type");
+ break;
+ case OSQLParseNode::values_or_query_spec:
+ OSL_FAIL("Cannot guess VALUES type");
+ break;
+ case OSQLParseNode::derived_column:
+ OSL_FAIL("Cannot guess computed column type");
+ break;
+ case OSQLParseNode::subquery:
+ OSL_FAIL("Cannot guess subquery return type");
+ break;
+ case OSQLParseNode::search_condition:
+ case OSQLParseNode::comparison_predicate:
+ case OSQLParseNode::between_predicate:
+ case OSQLParseNode::like_predicate:
+ case OSQLParseNode::test_for_null:
+ case OSQLParseNode::boolean_term:
+ case OSQLParseNode::boolean_primary:
+ case OSQLParseNode::in_predicate:
+ case OSQLParseNode::existence_test:
+ case OSQLParseNode::unique_test:
+ case OSQLParseNode::all_or_any_predicate:
+ case OSQLParseNode::join_condition:
+ case OSQLParseNode::boolean_factor:
+ case OSQLParseNode::comparison_predicate_part_2:
+ case OSQLParseNode::parenthesized_boolean_value_expression:
+ case OSQLParseNode::other_like_predicate_part_2:
+ case OSQLParseNode::between_predicate_part_2:
+ nDataType = DataType::BOOLEAN;
+ break;
+ case OSQLParseNode::num_value_exp:
+ case OSQLParseNode::extract_exp:
+ case OSQLParseNode::term:
+ case OSQLParseNode::factor:
+ // Might by an integer or a float; take the most generic
+ nDataType = DataType::DOUBLE;
+ break;
+ case OSQLParseNode::value_exp_primary:
+ case OSQLParseNode::value_exp:
+ case OSQLParseNode::odbc_call_spec:
+ // Really, we don't know. Let the default.
+ break;
+ case OSQLParseNode::position_exp:
+ case OSQLParseNode::length_exp:
+ nDataType = DataType::INTEGER;
+ break;
+ case OSQLParseNode::char_value_exp:
+ case OSQLParseNode::char_value_fct:
+ case OSQLParseNode::fold:
+ case OSQLParseNode::char_substring_fct:
+ case OSQLParseNode::char_factor:
+ case OSQLParseNode::concatenation:
+ nDataType = DataType::VARCHAR;
+ break;
+ case OSQLParseNode::datetime_primary:
+ nDataType = DataType::TIMESTAMP;
+ break;
+ case OSQLParseNode::bit_value_fct:
+ nDataType = DataType::BINARY;
+ break;
+ case OSQLParseNode::general_set_fct: // May depend on argument; ignore that for now
+ case OSQLParseNode::set_fct_spec:
+ {
+ if (pNode->count() == 0)
+ {
+ // This is not a function call, no sense to continue with a function return type lookup
+ OSL_FAIL("Got leaf SQL node where non-leaf expected");
+ break;
+ }
+ const OSQLParseNode* pFunctionName = pNode->getChild(0);
+ if ( SQL_ISPUNCTUATION(pFunctionName,"{") )
+ {
+ if ( pNode->count() == 3 )
+ return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
+ else
+ OSL_FAIL("ODBC escape not in recognised form");
+ break;
+ }
+ else
+ {
+ if ( SQL_ISRULEOR2(pNode,length_exp,char_value_fct) )
+ pFunctionName = pFunctionName->getChild(0);
+
+ OUString sFunctionName = pFunctionName->getTokenValue();
+ if ( sFunctionName.isEmpty() )
+ sFunctionName = OStringToOUString(OSQLParser::TokenIDToStr(pFunctionName->getTokenID()),RTL_TEXTENCODING_UTF8);
+
+ nDataType = OSQLParser::getFunctionReturnType(
+ sFunctionName
+ ,&rController.getParser().getContext());
+ }
+ break;
+ }
+ case OSQLParseNode::odbc_fct_spec:
+ {
+ if (pNode->count() != 2)
+ {
+ OSL_FAIL("interior of ODBC escape not in recognised shape");
+ break;
+ }
+
+ const OSQLParseNode* const pEscapeType = pNode->getChild(0);
+ if (SQL_ISTOKEN(pEscapeType, TS))
+ nDataType = DataType::TIMESTAMP;
+ else if (SQL_ISTOKEN(pEscapeType, D))
+ nDataType = DataType::DATE;
+ else if (SQL_ISTOKEN(pEscapeType, T))
+ nDataType = DataType::TIME;
+ else if (SQL_ISTOKEN(pEscapeType, FN))
+ return fillFunctionInfo( pNode->getChild(1), sFunctionTerm, aInfo );
+ else
+ OSL_FAIL("Unknown ODBC escape");
+ break;
+ }
+ case OSQLParseNode::cast_spec:
+ {
+ if ( pNode->count() != 6 || !SQL_ISTOKEN(pNode->getChild(3), AS) )
+ {
+ OSL_FAIL("CAST not in recognised shape");
+ break;
+ }
+ const OSQLParseNode *pCastTarget = pNode->getChild(4);
+ if ( SQL_ISTOKENOR2(pCastTarget, INTEGER, INT) )
+ nDataType = DataType::INTEGER;
+ else if ( SQL_ISTOKEN(pCastTarget, SMALLINT) )
+ nDataType = DataType::SMALLINT;
+ else if ( SQL_ISTOKEN(pCastTarget, BIGINT) )
+ nDataType = DataType::BIGINT;
+ else if ( SQL_ISTOKEN(pCastTarget, FLOAT) )
+ nDataType = DataType::FLOAT;
+ else if ( SQL_ISTOKEN(pCastTarget, REAL) )
+ nDataType = DataType::REAL;
+ else if ( SQL_ISTOKEN(pCastTarget, DOUBLE) )
+ nDataType = DataType::DOUBLE;
+ else if ( SQL_ISTOKEN(pCastTarget, BOOLEAN) )
+ nDataType = DataType::BOOLEAN;
+ else if ( SQL_ISTOKEN(pCastTarget, DATE) )
+ nDataType = DataType::DATE;
+ else if ( pCastTarget->count() > 0 )
+ {
+ const OSQLParseNode *pDataType = pCastTarget->getChild(0);
+ while (pDataType->count() > 0)
+ {
+ pCastTarget = pDataType;
+ pDataType = pDataType->getChild(0);
+ }
+ if ( SQL_ISTOKEN (pDataType, TIME) )
+ nDataType = DataType::TIME;
+ else if ( SQL_ISTOKEN (pDataType, TIMESTAMP) )
+ nDataType = DataType::TIMESTAMP;
+ else if ( SQL_ISTOKENOR3 (pDataType, CHARACTER, CHAR, NCHAR) )
+ nDataType = char_datatype(pCastTarget, 0);
+ else if ( SQL_ISTOKEN (pDataType, VARCHAR) )
+ nDataType = DataType::VARCHAR;
+ else if ( SQL_ISTOKEN (pDataType, CLOB) )
+ nDataType = DataType::CLOB;
+ else if ( SQL_ISTOKEN (pDataType, NATIONAL) )
+ nDataType = char_datatype(pCastTarget, 1);
+ else if ( SQL_ISTOKEN (pDataType, BINARY) )
+ {
+ if ( pCastTarget->count() > 2 && SQL_ISTOKEN(pCastTarget->getChild(1), LARGE) && SQL_ISTOKEN(pCastTarget->getChild(2), OBJECT) )
+ nDataType = DataType::BLOB;
+ else if ( pCastTarget->count() > 1 && SQL_ISTOKEN(pCastTarget->getChild(1), VARYING) )
+ nDataType = DataType::VARBINARY;
+ else
+ nDataType = DataType::BINARY;
+ }
+ else if ( SQL_ISTOKEN (pDataType, VARBINARY) )
+ nDataType = DataType::VARBINARY;
+ else if ( SQL_ISTOKEN (pDataType, BLOB) )
+ nDataType = DataType::BLOB;
+ else if ( SQL_ISTOKEN (pDataType, NUMERIC) )
+ nDataType = DataType::NUMERIC;
+ else if ( SQL_ISTOKENOR2 (pDataType, DECIMAL, DEC) )
+ nDataType = DataType::DECIMAL;
+ else if ( SQL_ISTOKEN (pDataType, FLOAT) )
+ nDataType = DataType::FLOAT;
+ else if ( SQL_ISTOKEN (pDataType, DOUBLE) )
+ nDataType = DataType::DOUBLE;
+ else if ( SQL_ISTOKEN (pDataType, INTERVAL) )
+ // Not in DataType published constant (because not in JDBC...)
+ nDataType = DataType::VARCHAR;
+ else
+ OSL_FAIL("Failed to decode CAST target");
+ }
+ else
+ OSL_FAIL("Could not decipher CAST target");
+ break;
+ }
+ default:
+ OSL_FAIL("Unknown SQL RuleID");
+ break;
+ }
+ break;
+ default:
+ OSL_FAIL("Unknown SQL Node Type");
+ break;
+ }
+
+ aInfo->SetDataType(nDataType);
+ aInfo->SetFieldType(TAB_NORMAL_FIELD);
+ aInfo->SetField(sFunctionTerm);
+ aInfo->SetTabWindow(nullptr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx
new file mode 100644
index 000000000..398732815
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "QueryMoveTabWinUndoAct.hxx"
+#include <JoinTableView.hxx>
+
+using namespace dbaui;
+void OJoinMoveTabWinUndoAct::TogglePosition()
+{
+ Point ptFrameScrollPos(m_pOwner->GetHScrollBar().GetThumbPos(),
+ m_pOwner->GetVScrollBar().GetThumbPos());
+ Point ptNext = m_pTabWin->GetPosPixel() + ptFrameScrollPos;
+
+ m_pTabWin->SetPosPixel(m_ptNextPosition - ptFrameScrollPos);
+
+ // it looks like ptFrameScrollPos is meaningless, then I subtract it here and add it to ptNext, and
+ // next time I subtract again...
+ // Albeit ptFrameScrollPos could have changed next time...
+ m_pOwner->EnsureVisible(m_pTabWin);
+
+ m_ptNextPosition = ptNext;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx
new file mode 100644
index 000000000..e6b58956e
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "QueryDesignUndoAction.hxx"
+#include <strings.hrc>
+#include <JoinTableView.hxx>
+#include <TableWindow.hxx>
+#include <tools/gen.hxx>
+
+namespace dbaui
+{
+
+ // OQueryMoveTabWinUndoAct - Undo class for moving a TabWin
+ class OTableWindow;
+ class OJoinMoveTabWinUndoAct final : public OQueryDesignUndoAction
+ {
+ Point m_ptNextPosition;
+ VclPtr<OTableWindow> m_pTabWin;
+
+ void TogglePosition();
+
+ public:
+ OJoinMoveTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPosition, OTableWindow* pTabWin);
+
+ virtual void Undo() override { TogglePosition(); }
+ virtual void Redo() override { TogglePosition(); }
+ };
+
+ inline OJoinMoveTabWinUndoAct::OJoinMoveTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPosition, OTableWindow* pTabWin)
+ :OQueryDesignUndoAction(pOwner, STR_QUERY_UNDO_MOVETABWIN)
+ ,m_ptNextPosition(ptOriginalPosition)
+ ,m_pTabWin(pTabWin)
+ {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx
new file mode 100644
index 000000000..de244ccb5
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "QueryDesignUndoAction.hxx"
+#include <strings.hrc>
+#include <TableWindow.hxx>
+
+namespace dbaui
+{
+
+ // OQuerySizeTabWinUndoAct - undo class to change size of TabWins
+ class OTableWindow;
+ class OJoinSizeTabWinUndoAct final : public OQueryDesignUndoAction
+ {
+ Point m_ptNextPosition;
+ Size m_szNextSize;
+ VclPtr<OTableWindow> m_pTabWin;
+
+ inline void ToggleSizePosition();
+
+ public:
+ OJoinSizeTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPos, const Size& szOriginalSize, OTableWindow* pTabWin);
+ // Boundary condition: while retrieving size/position scrolling is not allowed, meaning the position
+ // here returns physical and not logical coordinates
+ // (in contrary to QueryMoveTabWinUndoAct)
+
+ virtual void Undo() override { ToggleSizePosition(); }
+ virtual void Redo() override { ToggleSizePosition(); }
+ };
+
+ inline OJoinSizeTabWinUndoAct::OJoinSizeTabWinUndoAct(OJoinTableView* pOwner, const Point& ptOriginalPos, const Size& szOriginalSize, OTableWindow* pTabWin)
+ :OQueryDesignUndoAction(pOwner, STR_QUERY_UNDO_SIZETABWIN)
+ ,m_ptNextPosition(ptOriginalPos)
+ ,m_szNextSize(szOriginalSize)
+ ,m_pTabWin(pTabWin)
+ {
+ }
+
+ inline void OJoinSizeTabWinUndoAct::ToggleSizePosition()
+ {
+ Point ptNext = m_pTabWin->GetPosPixel();
+ Size szNext = m_pTabWin->GetSizePixel();
+
+ m_pOwner->Invalidate(InvalidateFlags::NoChildren);
+ m_pTabWin->SetPosSizePixel(m_ptNextPosition, m_szNextSize);
+ m_pOwner->Invalidate(InvalidateFlags::NoChildren);
+
+ m_ptNextPosition = ptNext;
+ m_szNextSize = szNext;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx
new file mode 100644
index 000000000..e3b6cd0e9
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "QueryTabConnUndoAction.hxx"
+#include "QTableConnection.hxx"
+#include <QueryTableView.hxx>
+#include "QueryAddTabConnUndoAction.hxx"
+#include "QueryTabWinShowUndoAct.hxx"
+#include <strings.hrc>
+
+using namespace dbaui;
+
+OQueryTabConnUndoAction::~OQueryTabConnUndoAction()
+{
+ if (m_bOwnerOfConn)
+ { // I have the connection -> delete
+ m_pOwner->DeselectConn(m_pConnection);
+ m_pConnection.disposeAndClear();
+ }
+}
+
+OQueryTabConnUndoAction::OQueryTabConnUndoAction(OQueryTableView* pOwner, TranslateId pCommentID)
+ : OQueryDesignUndoAction(pOwner, pCommentID)
+ , m_pConnection(nullptr)
+ , m_bOwnerOfConn(false)
+{
+}
+
+OQueryAddTabConnUndoAction::OQueryAddTabConnUndoAction(OQueryTableView* pOwner)
+ : OQueryTabConnUndoAction(pOwner, STR_QUERY_UNDO_INSERTCONNECTION)
+{
+}
+
+void OQueryAddTabConnUndoAction::Undo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->DropConnection(m_pConnection);
+ SetOwnership(true);
+}
+
+void OQueryAddTabConnUndoAction::Redo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->GetConnection(m_pConnection);
+ SetOwnership(false);
+}
+
+OQueryDelTabConnUndoAction::OQueryDelTabConnUndoAction(OQueryTableView* pOwner)
+ : OQueryTabConnUndoAction(pOwner, STR_QUERY_UNDO_REMOVECONNECTION)
+{
+}
+
+void OQueryDelTabConnUndoAction::Undo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->GetConnection(m_pConnection);
+ SetOwnership(false);
+}
+
+void OQueryDelTabConnUndoAction::Redo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->DropConnection(m_pConnection);
+ SetOwnership(true);
+}
+
+OQueryTabWinShowUndoAct::OQueryTabWinShowUndoAct(OQueryTableView* pOwner)
+ : OQueryTabWinUndoAct(pOwner, STR_QUERY_UNDO_TABWINSHOW)
+{
+}
+
+OQueryTabWinShowUndoAct::~OQueryTabWinShowUndoAct() {}
+
+void OQueryTabWinShowUndoAct::Undo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->HideTabWin(m_pTabWin, this);
+ SetOwnership(true);
+}
+
+void OQueryTabWinShowUndoAct::Redo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->ShowTabWin(m_pTabWin, this, true);
+ SetOwnership(false);
+}
+
+OQueryTabWinDelUndoAct::OQueryTabWinDelUndoAct(OQueryTableView* pOwner)
+ : OQueryTabWinUndoAct(pOwner, STR_QUERY_UNDO_TABWINDELETE)
+{
+}
+
+OQueryTabWinDelUndoAct::~OQueryTabWinDelUndoAct() {}
+
+void OQueryTabWinDelUndoAct::Undo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->ShowTabWin(m_pTabWin, this, true);
+ SetOwnership(false);
+}
+
+void OQueryTabWinDelUndoAct::Redo()
+{
+ static_cast<OQueryTableView*>(m_pOwner.get())->HideTabWin(m_pTabWin, this);
+ SetOwnership(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx
new file mode 100644
index 000000000..21077074e
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "QueryDesignUndoAction.hxx"
+#include "QTableConnection.hxx"
+#include <JoinTableView.hxx>
+
+namespace dbaui
+{
+ class OQueryTableConnection;
+ class OQueryTableView;
+ class OQueryTabConnUndoAction : public OQueryDesignUndoAction
+ {
+ protected:
+ VclPtr<OQueryTableConnection> m_pConnection;
+ bool m_bOwnerOfConn;
+ // am I the only owner of the connection? (changes with every redo and undo)
+
+ public:
+ OQueryTabConnUndoAction(OQueryTableView* pOwner, TranslateId pCommentID);
+ virtual ~OQueryTabConnUndoAction() override;
+
+ virtual void Undo() override = 0;
+ virtual void Redo() override = 0;
+
+ void SetConnection(OQueryTableConnection* pConn) { m_pConnection = pConn; }
+ // now SetOwnership please
+ void SetOwnership(bool bTakeIt) { m_bOwnerOfConn = bTakeIt; }
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx
new file mode 100644
index 000000000..95b740de9
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "QueryTabWinUndoAct.hxx"
+
+namespace dbaui
+{
+ // OQueryTabWinShowUndoAct - undo class to show a TabWins
+
+ class OQueryTabWinShowUndoAct : public OQueryTabWinUndoAct
+ {
+ public:
+ explicit OQueryTabWinShowUndoAct(OQueryTableView* pOwner);
+ virtual ~OQueryTabWinShowUndoAct() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ };
+
+ // OQueryTabWinDelUndoAct - undo class to delete a TabWins
+
+ class OQueryTabWinDelUndoAct : public OQueryTabWinUndoAct
+ {
+ public:
+ explicit OQueryTabWinDelUndoAct(OQueryTableView* pOwner);
+ virtual ~OQueryTabWinDelUndoAct() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx
new file mode 100644
index 000000000..2afe74db4
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "QueryTabWinUndoAct.hxx"
+#include <osl/diagnose.h>
+#include "QTableWindow.hxx"
+#include "QueryDesignFieldUndoAct.hxx"
+#include <QueryTableView.hxx>
+
+using namespace dbaui;
+OQueryDesignFieldUndoAct::OQueryDesignFieldUndoAct(OSelectionBrowseBox* pSelBrwBox, TranslateId pCommentID)
+ : OCommentUndoAction(pCommentID)
+ , pOwner(pSelBrwBox)
+ , m_nColumnPosition(BROWSER_INVALIDID)
+{
+}
+
+OQueryDesignFieldUndoAct::~OQueryDesignFieldUndoAct()
+{
+ pOwner = nullptr;
+}
+
+OQueryTabWinUndoAct::OQueryTabWinUndoAct(OQueryTableView* pOwner, TranslateId pCommentID)
+ : OQueryDesignUndoAction(pOwner, pCommentID)
+ , m_pTabWin(nullptr)
+ , m_bOwnerOfObjects(false)
+{
+}
+
+OQueryTabWinUndoAct::~OQueryTabWinUndoAct()
+{
+ if (!m_bOwnerOfObjects)
+ return;
+
+ // I should take care to delete the window if I am the only owner
+ OSL_ENSURE(m_pTabWin != nullptr, "OQueryTabWinUndoAct::~OQueryTabWinUndoAct() : m_pTabWin must not be NULL");
+ OSL_ENSURE(!m_pTabWin->IsVisible(), "OQueryTabWinUndoAct::~OQueryTabWinUndoAct() : *m_pTabWin must not be visible");
+
+ if ( m_pTabWin )
+ m_pTabWin->clearListBox();
+ m_pTabWin.disposeAndClear();
+
+ // and of course the corresponding connections
+ for (auto & connection : m_vTableConnection)
+ {
+ m_pOwner->DeselectConn(connection);
+ connection.disposeAndClear();
+ }
+ m_vTableConnection.clear();
+}
+
+void OTabFieldCellModifiedUndoAct::Undo()
+{
+ pOwner->EnterUndoMode();
+ OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!");
+ OSL_ENSURE(m_nColumnPosition < pOwner->GetColumnCount(),"Position outside the column count!");
+ if ( m_nColumnPosition != BROWSER_INVALIDID )
+ {
+ sal_uInt16 nColumnId = pOwner->GetColumnId(m_nColumnPosition);
+ OUString strNext = pOwner->GetCellContents(m_nCellIndex, nColumnId);
+ pOwner->SetCellContents(m_nCellIndex, nColumnId, m_strNextCellContents);
+ m_strNextCellContents = strNext;
+ }
+ pOwner->LeaveUndoMode();
+}
+
+void OTabFieldSizedUndoAct::Undo()
+{
+ pOwner->EnterUndoMode();
+ OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!");
+ if ( m_nColumnPosition != BROWSER_INVALIDID )
+ {
+ sal_uInt16 nColumnId = pOwner->GetColumnId(m_nColumnPosition);
+ tools::Long nNextWidth = pOwner->GetColumnWidth(nColumnId);
+ pOwner->SetColWidth(nColumnId, m_nNextWidth);
+ m_nNextWidth = nNextWidth;
+ }
+ pOwner->LeaveUndoMode();
+}
+
+void OTabFieldMovedUndoAct::Undo()
+{
+ pOwner->EnterUndoMode();
+ OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!");
+ if ( m_nColumnPosition != BROWSER_INVALIDID )
+ {
+ sal_uInt16 nId = pDescr->GetColumnId();
+ sal_uInt16 nOldPos = pOwner->GetColumnPos(nId);
+ pOwner->SetColumnPos(nId,m_nColumnPosition);
+ pOwner->ColumnMoved(nId,false);
+ m_nColumnPosition = nOldPos;
+ }
+ pOwner->LeaveUndoMode();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx
new file mode 100644
index 000000000..9b4330542
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "QueryDesignUndoAction.hxx"
+#include "QTableWindow.hxx"
+#include <TableConnection.hxx>
+#include <vector>
+
+namespace dbaui
+{
+ // OQueryTabWinUndoAct - undo base class for all which is concerned with insert/remove TabWins
+
+ class OQueryTableWindow;
+ class OTableConnection;
+ class OQueryTableView;
+ class OQueryTabWinUndoAct : public OQueryDesignUndoAction
+ {
+ protected:
+ std::vector<VclPtr<OTableConnection> > m_vTableConnection;
+ VclPtr<OQueryTableWindow> m_pTabWin;
+ bool m_bOwnerOfObjects;
+ // am I the only owner of the managed objects? (changes with every redo or undo)
+
+ public:
+ OQueryTabWinUndoAct(OQueryTableView* pOwner, TranslateId pCommentID);
+ virtual ~OQueryTabWinUndoAct() override;
+
+ void SetOwnership(bool bTakeIt) { m_bOwnerOfObjects = bTakeIt; }
+
+ virtual void Undo() override = 0;
+ virtual void Redo() override = 0;
+
+ // access to the TabWin
+ void SetTabWin(OQueryTableWindow* pTW) { m_pTabWin = pTW; }
+ // now SetOwnership should be invoked
+
+ std::vector<VclPtr<OTableConnection> >& GetTabConnList() { return m_vTableConnection; }
+
+ void InsertConnection( OTableConnection* pConnection ) { m_vTableConnection.push_back(pConnection); }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryTableView.cxx b/dbaccess/source/ui/querydesign/QueryTableView.cxx
new file mode 100644
index 000000000..399697b09
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryTableView.cxx
@@ -0,0 +1,889 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <QueryTableView.hxx>
+#include <TableFieldDescription.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <helpids.h>
+#include "QTableWindow.hxx"
+#include "QTableConnection.hxx"
+#include "QTableConnectionData.hxx"
+#include <QueryDesignView.hxx>
+#include "QueryAddTabConnUndoAction.hxx"
+#include "QueryTabWinShowUndoAct.hxx"
+#include <browserids.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <JAccess.hxx>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/sequence.hxx>
+#include "querydlg.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::accessibility;
+
+namespace
+{
+ /** appends a new TabAdd Undo action at controller
+ @param _pView the view which we use
+ @param _pUndoAction the undo action which should be added
+ @param _pConnection the connection for which the undo action should be appended
+ @param _bOwner is the undo action the owner
+ */
+ void addUndoAction( OQueryTableView const * _pView,
+ std::unique_ptr<OQueryTabConnUndoAction> _pUndoAction,
+ OQueryTableConnection* _pConnection,
+ bool _bOwner = false)
+ {
+ _pUndoAction->SetOwnership(_bOwner);
+ _pUndoAction->SetConnection(_pConnection);
+ _pView->getDesignView()->getController().addUndoActionAndInvalidate(std::move(_pUndoAction));
+ }
+ /** openJoinDialog opens the join dialog with this connection data
+ @param _pView the view which we use
+ @param _pConnectionData the connection data
+
+ @return true when OK was pressed otherwise false
+ */
+ bool openJoinDialog(OQueryTableView* _pView,const TTableConnectionData::value_type& _pConnectionData,bool _bSelectableTables)
+ {
+ OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pConnectionData.get());
+
+ DlgQryJoin aDlg(_pView,_pConnectionData,&_pView->GetTabWinMap(),_pView->getDesignView()->getController().getConnection(),_bSelectableTables);
+ bool bOk = aDlg.run() == RET_OK;
+ if( bOk )
+ {
+ pData->SetJoinType(aDlg.GetJoinType());
+ _pView->getDesignView()->getController().setModified(true);
+ }
+
+ return bOk;
+ }
+ /** connectionModified adds an undo action for the modified connection and forces a redraw
+ @param _pView the view which we use
+ @param _pConnection the connection which was modified
+ @param _bAddUndo true when an undo action should be appended
+ */
+ void connectionModified(OQueryTableView* _pView,
+ OTableConnection* _pConnection,
+ bool _bAddUndo)
+ {
+ OSL_ENSURE(_pConnection,"Invalid connection!");
+ _pConnection->UpdateLineList();
+
+ // add an undo action
+ if ( _bAddUndo )
+ addUndoAction( _pView,
+ std::make_unique<OQueryAddTabConnUndoAction>(_pView),
+ static_cast< OQueryTableConnection*>(_pConnection));
+ // redraw
+ _pConnection->RecalcLines();
+ // force an invalidation of the bounding rectangle
+ _pConnection->InvalidateConnection();
+
+ _pView->Invalidate(InvalidateFlags::NoChildren);
+ }
+ void addConnections(OQueryTableView* _pView,
+ const OQueryTableWindow& _rSource,
+ const OQueryTableWindow& _rDest,
+ const Reference<XNameAccess>& _rxSourceForeignKeyColumns)
+ {
+ if ( _rSource.GetData()->isQuery() || _rDest.GetData()->isQuery() )
+ // nothing to do if one of both denotes a query
+ return;
+
+ // we found a table in our view where we can insert some connections
+ // the key columns have a property called RelatedColumn
+ // build OQueryTableConnectionData
+ auto xNewConnData = std::make_shared<OQueryTableConnectionData>( _rSource.GetData(), _rDest.GetData() );
+
+ OUString sRelatedColumn;
+
+ // iterate through all foreignkey columns to create the connections
+ const Sequence<OUString> aKeyCols = _rxSourceForeignKeyColumns->getElementNames();
+ for(const OUString& rElement : aKeyCols)
+ {
+ Reference<XPropertySet> xColumn;
+ if ( !( _rxSourceForeignKeyColumns->getByName(rElement) >>= xColumn ) )
+ {
+ OSL_FAIL( "addConnections: invalid foreign key column!" );
+ continue;
+ }
+
+ xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn;
+
+ {
+ sal_Int32 nFindIndex = ::comphelper::findValue(_rSource.GetOriginalColumns()->getElementNames(),rElement);
+ if(nFindIndex != -1)
+ xNewConnData->SetFieldIndex(JTCS_FROM,nFindIndex+1);
+ else
+ OSL_FAIL("Column not found!");
+ }
+ // get the position inside the table
+ Reference<XNameAccess> xRefColumns = _rDest.GetOriginalColumns();
+ if(xRefColumns.is())
+ {
+ sal_Int32 nFindIndex = ::comphelper::findValue(xRefColumns->getElementNames(),sRelatedColumn);
+ if(nFindIndex != -1)
+ xNewConnData->SetFieldIndex(JTCS_TO,nFindIndex+1);
+ else
+ OSL_FAIL("Column not found!");
+ }
+ xNewConnData->AppendConnLine(rElement,sRelatedColumn);
+
+ // now add the Conn itself
+ ScopedVclPtrInstance< OQueryTableConnection > aNewConn(_pView, xNewConnData);
+ // referring to the local variable is not important, as NotifyQueryTabConn creates a new copy
+ // to add me (if not existent)
+ _pView->NotifyTabConnection(*aNewConn, false);
+ // don't create an Undo-Action for the new connection : the connection is
+ // covered by the Undo-Action for the tabwin, as the "Undo the insert" will
+ // automatically remove all connections adjacent to the win.
+ // (Because of this automatism we would have an ownership ambiguity for
+ // the connection data if we would insert the conn-Undo-Action)
+ }
+ }
+}
+
+OQueryTableView::OQueryTableView( vcl::Window* pParent,OQueryDesignView* pView)
+ : OJoinTableView( pParent,pView)
+{
+ SetHelpId(HID_CTL_QRYDGNTAB);
+}
+
+sal_Int32 OQueryTableView::CountTableAlias(const OUString& rName, sal_Int32& rMax)
+{
+ sal_Int32 nRet = 0;
+
+ OTableWindowMap::const_iterator aIter = GetTabWinMap().find(rName);
+ while(aIter != GetTabWinMap().end())
+ {
+ OUString aNewName = rName + "_" + OUString::number(++nRet);
+ aIter = GetTabWinMap().find(aNewName);
+ }
+
+ rMax = nRet;
+
+ return nRet;
+}
+
+void OQueryTableView::ReSync()
+{
+ TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData();
+ OSL_ENSURE((getTableConnections().empty()) && (GetTabWinMap().empty()),
+ "before calling OQueryTableView::ReSync() please call ClearAll !");
+
+ // I need a collection of all window names that cannot be created so that I do not initialize connections for them.
+ std::vector<OUString> arrInvalidTables;
+
+ TTableWindowData::const_reverse_iterator aIter = rTabWinDataList.rbegin();
+ // Create the window and add it
+
+ for(;aIter != rTabWinDataList.rend();++aIter)
+ {
+ OQueryTableWindowData* pData = static_cast<OQueryTableWindowData*>(aIter->get());
+ VclPtr<OTableWindow> pTabWin = createWindow(*aIter);
+
+ // I don't use ShowTabWin as this adds the window data to the list of documents.
+ // This would be bad as I am getting them from there.
+ // Instead, I do it step by step
+ if (!pTabWin->Init())
+ {
+ // The initialisation has gone wrong, this TabWin is not available, so
+ // I must clean up the data and the document
+ pTabWin->clearListBox();
+ pTabWin.disposeAndClear();
+ arrInvalidTables.push_back(pData->GetAliasName());
+
+ rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), *aIter), rTabWinDataList.end());
+ continue;
+ }
+
+ GetTabWinMap()[pData->GetAliasName()] = pTabWin; // add at the beginning as I am going backwards through the DataList
+ // Use the default if there is no position or size
+ if (!pData->HasPosition() && !pData->HasSize())
+ SetDefaultTabWinPosSize(pTabWin);
+
+ pTabWin->Show();
+ }
+
+ // Add the connections
+ TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData();
+ TTableConnectionData::const_reverse_iterator aConIter = rTabConnDataList.rbegin();
+
+ for(;aConIter != rTabConnDataList.rend();++aConIter)
+ {
+ OQueryTableConnectionData* pTabConnData = static_cast<OQueryTableConnectionData*>(aConIter->get());
+
+ // do both tables for the connection exist ?
+ OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetWinName();
+ bool bInvalid = std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
+ strTabExistenceTest = pTabConnData->getReferencedTable()->GetWinName();
+ bInvalid = bInvalid && std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
+
+ if (bInvalid)
+ {
+ // no -> bad luck, no connection
+ rTabConnDataList.erase( std::remove(rTabConnDataList.begin(), rTabConnDataList.end(), *aConIter), rTabConnDataList.end());
+ continue;
+ }
+
+ // adds a new connection to join view and notifies our accessible and invalidates the controller
+ addConnection(VclPtr<OQueryTableConnection>::Create(this, *aConIter));
+ }
+}
+
+void OQueryTableView::ClearAll()
+{
+ OJoinTableView::ClearAll();
+
+ SetUpdateMode(true);
+ m_pView->getController().setModified(true);
+}
+
+VclPtr<OTableWindow> OQueryTableView::createWindow(const TTableWindowData::value_type& _pData)
+{
+ return VclPtr<OQueryTableWindow>::Create(this,_pData);
+}
+
+void OQueryTableView::NotifyTabConnection(const OQueryTableConnection& rNewConn, bool _bCreateUndoAction)
+{
+ // let's first check if I have the connection already
+ OQueryTableConnection* pTabConn = nullptr;
+ const auto& rConnections = getTableConnections();
+ auto aEnd = rConnections.end();
+ auto aIter = std::find( rConnections.begin(),
+ aEnd,
+ VclPtr<OTableConnection>(const_cast<OTableConnection*>(static_cast<const OTableConnection*>(&rNewConn)))
+ );
+ if(aIter == aEnd)
+ {
+ for (auto const& connection : rConnections)
+ {
+ if(*static_cast<OQueryTableConnection*>(connection.get()) == rNewConn)
+ {
+ pTabConn = static_cast<OQueryTableConnection*>(connection.get());
+ break;
+ }
+ }
+ }
+ else
+ pTabConn = static_cast<OQueryTableConnection*>((*aIter).get());
+
+ // no -> insert
+ if (pTabConn == nullptr)
+ {
+ // the new data ...
+ auto pNewData = std::static_pointer_cast<OQueryTableConnectionData>(rNewConn.GetData()->NewInstance());
+ pNewData->CopyFrom(*rNewConn.GetData());
+ VclPtrInstance<OQueryTableConnection> pNewConn(this, pNewData);
+ GetConnection(pNewConn);
+
+ connectionModified(this,pNewConn,_bCreateUndoAction);
+ }
+}
+
+std::shared_ptr<OTableWindowData> OQueryTableView::CreateImpl(const OUString& _rComposedName
+ ,const OUString& _sTableName
+ ,const OUString& _rWinName)
+{
+ return std::make_shared<OQueryTableWindowData>( _rComposedName, _sTableName,_rWinName );
+}
+
+void OQueryTableView::AddTabWin(const OUString& _rTableName, const OUString& _rAliasName, bool bNewTable)
+{
+ // this method has been inherited from the base class, linking back to the parent and which constructs
+ // an Alias and which passes on to my other AddTabWin
+
+ // pity _rTableName is fully qualified, OQueryDesignView expects a string which only
+ // contains schema and tables but no catalog.
+ Reference< XConnection> xConnection = m_pView->getController().getConnection();
+ if(!xConnection.is())
+ return;
+ try
+ {
+ Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,
+ _rTableName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ OUString sRealName(sSchema);
+ if (!sRealName.isEmpty())
+ sRealName += ".";
+ sRealName += sTable;
+
+ AddTabWin(_rTableName, sRealName, _rAliasName, bNewTable);
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("qualifiedNameComponents");
+ }
+}
+
+// find the table which has a foreign key with this referencedTable name
+static Reference<XPropertySet> getKeyReferencedTo(const Reference<XIndexAccess>& _rxKeys,std::u16string_view _rReferencedTable)
+{
+ if(!_rxKeys.is())
+ return Reference<XPropertySet>();
+
+ // search the one and only primary key
+ const sal_Int32 nCount = _rxKeys->getCount();
+ for(sal_Int32 i=0;i<nCount ;++i)
+ {
+ Reference<XPropertySet> xKey(_rxKeys->getByIndex(i),UNO_QUERY);
+ if(xKey.is())
+ {
+ sal_Int32 nKeyType = 0;
+ xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
+ if(KeyType::FOREIGN == nKeyType)
+ {
+ OUString sReferencedTable;
+ xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
+ // TODO check case
+ if(sReferencedTable == _rReferencedTable)
+ return xKey;
+ }
+ }
+ }
+ return Reference<XPropertySet>();
+}
+
+void OQueryTableView::AddTabWin(const OUString& _rComposedName, const OUString& _rTableName, const OUString& strAlias, bool bNewTable)
+{
+ OSL_ENSURE(!_rTableName.isEmpty() || !strAlias.isEmpty(), "OQueryTableView::AddTabWin : no tables or aliases !");
+ // If the table is not set, then it is a dummy window, but at least the alias must be set
+
+ // build a new data structure
+ // first check if this already has its data
+ bool bAppend = bNewTable;
+ TTableWindowData::value_type pNewTabWinData;
+ TTableWindowData& rWindowData = getDesignView()->getController().getTableWindowData();
+ bool bFoundElem = false;
+ for (auto const& elem : rWindowData)
+ {
+ pNewTabWinData = elem;
+ if (pNewTabWinData && pNewTabWinData->GetWinName() == strAlias && pNewTabWinData->GetComposedName() == _rComposedName && pNewTabWinData->GetTableName() == _rTableName)
+ {
+ bFoundElem = true;
+ break;
+ }
+ }
+ if ( !bAppend )
+ bAppend = !bFoundElem;
+ if ( bAppend )
+ pNewTabWinData = createTableWindowData(_rComposedName, _rTableName, strAlias);
+ // I do not need to add TabWinData to the DocShell list, ShowTabWin does that.
+
+ // Create a new window
+ VclPtr<OQueryTableWindow> pNewTabWin = static_cast<OQueryTableWindow*>(createWindow(pNewTabWinData).get());
+ // No need to initialize, as that happens in ShowTabWin
+
+ // New UndoAction
+ std::unique_ptr<OQueryTabWinShowUndoAct> pUndoAction(new OQueryTabWinShowUndoAct(this));
+ pUndoAction->SetTabWin(pNewTabWin); // Window
+ bool bSuccess = ShowTabWin(pNewTabWin, pUndoAction.get(), bAppend);
+ if(!bSuccess)
+ {
+ // reset table window
+ pUndoAction->SetTabWin(nullptr);
+ pUndoAction->SetOwnership(false);
+ return;
+ }
+
+ // Show the relations between the individual tables
+ OTableWindowMap& rTabWins = GetTabWinMap();
+ if(bNewTable && !rTabWins.empty() && !_rTableName.isEmpty())
+ {
+ modified();
+ if ( m_pAccessible )
+ m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
+ Any(),
+ Any(pNewTabWin->GetAccessible())
+ );
+
+ do {
+
+ if ( pNewTabWin->GetData()->isQuery() )
+ break;
+
+ try
+ {
+ // find relations between the table and the tables already inserted
+ Reference< XIndexAccess> xKeyIndex = pNewTabWin->GetData()->getKeys();
+ if ( !xKeyIndex.is() )
+ break;
+
+ Reference<XNameAccess> xFKeyColumns;
+ OUString aReferencedTable;
+ Reference<XColumnsSupplier> xColumnsSupplier;
+
+ const sal_Int32 nKeyCount = xKeyIndex->getCount();
+ for ( sal_Int32 i=0; i<nKeyCount ; ++i )
+ {
+ Reference< XPropertySet > xProp( xKeyIndex->getByIndex(i), UNO_QUERY_THROW );
+ xColumnsSupplier.set( xProp, UNO_QUERY_THROW );
+ xFKeyColumns.set( xColumnsSupplier->getColumns(), UNO_SET_THROW );
+
+ sal_Int32 nKeyType = 0;
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
+
+ switch ( nKeyType )
+ {
+ case KeyType::FOREIGN:
+ { // our new table has a foreign key
+ // so look if the referenced table is already in our list
+ xProp->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= aReferencedTable;
+ OSL_ENSURE(!aReferencedTable.isEmpty(),"Foreign key without referencedTableName");
+
+ OTableWindowMap::const_iterator aIter = rTabWins.find(aReferencedTable);
+ OTableWindowMap::const_iterator aEnd = rTabWins.end();
+ if(aIter == aEnd)
+ {
+ for(aIter = rTabWins.begin();aIter != aEnd;++aIter)
+ {
+ OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(aIter->second.get());
+ OSL_ENSURE( pTabWinTmp,"TableWindow is null!" );
+ if ( pTabWinTmp != pNewTabWin && pTabWinTmp->GetComposedName() == aReferencedTable )
+ break;
+ }
+ }
+ if ( aIter != aEnd && pNewTabWin.get() != aIter->second.get() )
+ addConnections( this, *pNewTabWin, *static_cast<OQueryTableWindow*>(aIter->second.get()), xFKeyColumns );
+ }
+ break;
+
+ case KeyType::PRIMARY:
+ {
+ // we have a primary key so look in our list if there exists a key which this is referred to
+ for (auto const& tabWin : rTabWins)
+ {
+ OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(tabWin.second.get());
+ if ( pTabWinTmp == pNewTabWin )
+ continue;
+
+ if ( pTabWinTmp->GetData()->isQuery() )
+ continue;
+
+ OSL_ENSURE(pTabWinTmp,"TableWindow is null!");
+ Reference< XPropertySet > xFKKey = getKeyReferencedTo( pTabWinTmp->GetData()->getKeys(), pNewTabWin->GetComposedName() );
+ if ( !xFKKey.is() )
+ continue;
+
+ Reference<XColumnsSupplier> xFKColumnsSupplier( xFKKey, UNO_QUERY_THROW );
+ Reference< XNameAccess > xTColumns( xFKColumnsSupplier->getColumns(), UNO_SET_THROW );
+ addConnections( this, *pTabWinTmp, *pNewTabWin, xTColumns );
+ }
+ }
+ break;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ } while ( false );
+ }
+
+ // My parent needs to be informed about the delete
+ m_pView->getController().addUndoActionAndInvalidate( std::move(pUndoAction) );
+}
+
+void OQueryTableView::AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest)
+{
+ OQueryTableWindow* pSourceWin = static_cast< OQueryTableWindow*>(jxdSource.pListBox->GetTabWin());
+ OQueryTableWindow* pDestWin = static_cast< OQueryTableWindow*>(jxdDest.pListBox->GetTabWin());
+
+ OUString aSourceFieldName, aDestFieldName;
+ weld::TreeView& rSourceTreeView = jxdSource.pListBox->get_widget();
+ aSourceFieldName = rSourceTreeView.get_text(jxdSource.nEntry);
+ weld::TreeView& rDestTreeView = jxdDest.pListBox->get_widget();
+ aDestFieldName = rDestTreeView.get_text(jxdDest.nEntry);
+
+ OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true);
+ if ( !pConn )
+ {
+ // new data object
+ auto xNewConnectionData = std::make_shared<OQueryTableConnectionData>(pSourceWin->GetData(), pDestWin->GetData());
+
+ sal_uInt32 nSourceFieldIndex, nDestFieldIndex;
+
+ // Get name/position of both affected fields ...
+ // Source
+ nSourceFieldIndex = jxdSource.nEntry;
+ // Dest
+ nDestFieldIndex = jxdDest.nEntry;
+
+ // ... and set them
+ xNewConnectionData->SetFieldIndex(JTCS_FROM, nSourceFieldIndex);
+ xNewConnectionData->SetFieldIndex(JTCS_TO, nDestFieldIndex);
+
+ xNewConnectionData->AppendConnLine( aSourceFieldName,aDestFieldName );
+
+ ScopedVclPtrInstance< OQueryTableConnection > aNewConnection(this, xNewConnectionData);
+ NotifyTabConnection(*aNewConnection);
+ // As usual with NotifyTabConnection, using a local variable is fine because a copy is made
+ }
+ else
+ {
+ // the connection could point on the other side
+ if(pConn->GetSourceWin() == pDestWin)
+ {
+ OUString aTmp(aSourceFieldName);
+ aSourceFieldName = aDestFieldName;
+ aDestFieldName = aTmp;
+ }
+
+ pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName );
+
+ connectionModified(this,pConn,false);
+ }
+}
+
+void OQueryTableView::ConnDoubleClicked(VclPtr<OTableConnection>& rConnection)
+{
+ if (openJoinDialog(this, rConnection->GetData(), false))
+ {
+ connectionModified(this, rConnection, false);
+ SelectConn(rConnection);
+ }
+}
+
+void OQueryTableView::createNewConnection()
+{
+ TTableConnectionData::value_type pData = std::make_shared<OQueryTableConnectionData>();
+ if( !openJoinDialog(this,pData,true) )
+ return;
+
+ OTableWindowMap& rMap = GetTabWinMap();
+ OQueryTableWindow* pSourceWin = static_cast< OQueryTableWindow*>(rMap[pData->getReferencingTable()->GetWinName()].get());
+ OQueryTableWindow* pDestWin = static_cast< OQueryTableWindow*>(rMap[pData->getReferencedTable()->GetWinName()].get());
+ // first we have to look if the this connection already exists
+ OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true);
+ bool bNew = true;
+ if ( pConn )
+ {
+ pConn->GetData()->CopyFrom( *pData );
+ bNew = false;
+ }
+ else
+ {
+ // create a new connection and append it
+ VclPtrInstance<OQueryTableConnection> pQConn(this, pData);
+ GetConnection(pQConn);
+ pConn = pQConn;
+ }
+ connectionModified(this,pConn,bNew);
+ if ( !bNew && pConn == GetSelectedConn() ) // our connection was selected before so we have to reselect it
+ SelectConn( pConn );
+}
+
+bool OQueryTableView::RemoveConnection(VclPtr<OTableConnection>& rConnection, bool /*_bDelete*/)
+{
+ VclPtr<OQueryTableConnection> xConnection(static_cast<OQueryTableConnection*>(rConnection.get()));
+
+ // we don't want that our connection will be deleted, we put it in the undo manager
+ bool bRet = OJoinTableView::RemoveConnection(rConnection, false);
+
+ // add undo action
+ addUndoAction(this,
+ std::make_unique<OQueryDelTabConnUndoAction>(this),
+ xConnection.get(),
+ true);
+
+ return bRet;
+}
+
+OQueryTableWindow* OQueryTableView::FindTable(const OUString& rAliasName)
+{
+ OSL_ENSURE(!rAliasName.isEmpty(), "OQueryTableView::FindTable : the AliasName should not be empty !");
+ // (it is harmless but does not make sense and indicates that there is probably an error in the caller)
+ OTableWindowMap::const_iterator aIter = GetTabWinMap().find(rAliasName);
+ if(aIter != GetTabWinMap().end())
+ return static_cast<OQueryTableWindow*>(aIter->second.get());
+ return nullptr;
+}
+
+bool OQueryTableView::FindTableFromField(const OUString& rFieldName, OTableFieldDescRef const & rInfo, sal_uInt16& rCnt)
+{
+ rCnt = 0;
+ for (auto const& tabWin : GetTabWinMap())
+ {
+ if(static_cast<OQueryTableWindow*>(tabWin.second.get())->ExistsField(rFieldName, rInfo))
+ ++rCnt;
+ }
+ // TODO JNA : what should we rCnt > 1?
+
+ return rCnt == 1;
+}
+
+bool OQueryTableView::ContainsTabWin(const OTableWindow& rTabWin)
+{
+
+ for (auto const& tabWin : GetTabWinMap())
+ {
+ if ( tabWin.second == &rTabWin )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void OQueryTableView::RemoveTabWin(OTableWindow* pTabWin)
+{
+ OSL_ENSURE(pTabWin != nullptr, "OQueryTableView::RemoveTabWin : Window should not be NULL !");
+
+ if(!(pTabWin && ContainsTabWin(*pTabWin))) // #i122589# check if registered before deleting
+ return;
+
+ // I need my parent so it can be informed about the deletion
+ OQueryDesignView* pParent = static_cast<OQueryDesignView*>(getDesignView());
+
+ SfxUndoManager& rUndoMgr = m_pView->getController().GetUndoManager();
+ rUndoMgr.EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE) , OUString(), 0, ViewShellId(-1));
+
+ // add the Undo-Action
+ std::unique_ptr<OQueryTabWinDelUndoAct> pUndoAction(new OQueryTabWinDelUndoAct(this));
+ pUndoAction->SetTabWin(static_cast< OQueryTableWindow*>(pTabWin));
+
+ // and hide the window
+ HideTabWin(static_cast< OQueryTableWindow*>(pTabWin), pUndoAction.get());
+
+ // Undo Actions and delete the fields in SelectionBrowseBox
+ pParent->TableDeleted( static_cast< OQueryTableWindowData*>(pTabWin->GetData().get())->GetAliasName() );
+
+ m_pView->getController().addUndoActionAndInvalidate( std::move(pUndoAction) );
+ rUndoMgr.LeaveListAction();
+
+ modified();
+ if ( m_pAccessible )
+ m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
+ Any(pTabWin->GetAccessible()),
+ Any()
+ );
+}
+
+void OQueryTableView::EnsureVisible(const OTableWindow* pWin)
+{
+
+ Invalidate(InvalidateFlags::NoChildren);
+ OJoinTableView::EnsureVisible(pWin);
+}
+
+void OQueryTableView::GetConnection(OQueryTableConnection* pConn)
+{
+ // add to me and the document
+
+ addConnection( pConn );
+}
+
+void OQueryTableView::DropConnection(VclPtr<OQueryTableConnection> const & rConn)
+{
+ // Pay attention to the selection
+ // remove from me and the document
+ VclPtr<OTableConnection> xConn(rConn.get());
+ RemoveConnection(xConn, false);
+}
+
+void OQueryTableView::HideTabWin( OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction )
+{
+ OTableWindowMap& rTabWins = GetTabWinMap();
+
+ // Window
+ // save the position in its data
+ getDesignView()->SaveTabWinUIConfig(pTabWin);
+ // (I need to go via the parent, as only the parent knows the position of the scrollbars)
+ // and then out of the TabWins list and hide
+ OTableWindowMap::const_iterator aIter = std::find_if(rTabWins.begin(), rTabWins.end(),
+ [&pTabWin](const OTableWindowMap::value_type& rEntry) { return rEntry.second == pTabWin; });
+ if (aIter != rTabWins.end())
+ rTabWins.erase( aIter );
+
+ pTabWin->Hide(); // do not destroy it, as it is still in the undo list!!
+
+ // the TabWin data must also be passed out of my responsibility
+ TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData();
+ rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), pTabWin->GetData()), rTabWinDataList.end());
+ // The data should not be destroyed as TabWin itself - which is still alive - needs them
+ // Either it goes back into my responsibility, (via ShowTabWin), then I add the data back,
+ // or the Undo-Action, which currently has full responsibility for the window
+ // and its data, gets destroyed and destroys both the window and its data
+
+ if (m_pLastFocusTabWin == pTabWin)
+ m_pLastFocusTabWin = nullptr;
+
+ // collect connections belonging to the window and pass to UndoAction
+ sal_Int16 nCnt = 0;
+ const auto& rTabConList = getTableConnections();
+ auto aIter2 = rTabConList.begin();
+ for(;aIter2 != rTabConList.end();)// the end may change
+ {
+ VclPtr<OTableConnection> xTmpEntry = *aIter2;
+ OQueryTableConnection* pTmpEntry = static_cast<OQueryTableConnection*>(xTmpEntry.get());
+ OSL_ENSURE(pTmpEntry,"OQueryTableConnection is null!");
+ if( pTmpEntry->GetAliasName(JTCS_FROM) == pTabWin->GetAliasName() ||
+ pTmpEntry->GetAliasName(JTCS_TO) == pTabWin->GetAliasName() )
+ {
+ // add to undo list
+ pUndoAction->InsertConnection(xTmpEntry);
+
+ // call base class because we append an undo action
+ // but this time we are in an undo action list
+ OJoinTableView::RemoveConnection(xTmpEntry, false);
+ aIter2 = rTabConList.begin();
+ ++nCnt;
+ }
+ else
+ ++aIter2;
+ }
+
+ if (nCnt)
+ InvalidateConnections();
+
+ m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE);
+
+ // inform the UndoAction that the window and connections belong to it
+ pUndoAction->SetOwnership(true);
+
+ // by doing so, we have modified the document
+ m_pView->getController().setModified( true );
+ m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
+}
+
+bool OQueryTableView::ShowTabWin( OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction, bool _bAppend )
+{
+
+ bool bSuccess = false;
+
+ if (pTabWin)
+ {
+ if (pTabWin->Init())
+ {
+ TTableWindowData::value_type pData = pTabWin->GetData();
+ OSL_ENSURE(pData != nullptr, "OQueryTableView::ShowTabWin : TabWin has no data !");
+ // If there is a position and size defined, we use them
+ if (pData->HasPosition() && pData->HasSize())
+ {
+ Size aSize(CalcZoom(pData->GetSize().Width()),CalcZoom(pData->GetSize().Height()));
+ pTabWin->SetPosSizePixel(pData->GetPosition(), aSize);
+ }
+ else
+ // else set a default position
+ SetDefaultTabWinPosSize(pTabWin);
+
+ // Show the window and add to the list
+ OUString sName = static_cast< OQueryTableWindowData*>(pData.get())->GetAliasName();
+ OSL_ENSURE(GetTabWinMap().find(sName) == GetTabWinMap().end(),"Alias name already in list!");
+ GetTabWinMap().emplace(sName,pTabWin);
+
+ pTabWin->Show();
+
+ pTabWin->PaintImmediately();
+ // We must call Update() in order to show the connections in the window correctly. This sounds strange,
+ // but the Listbox has an internal Member which is initialized when the Listbox is first shown (after the Listbox
+ // is filled in Init). This Member will eventually be needed for
+ // GetEntryPos, and then in turn by the Connection, when its starting point to the window must be determined.
+
+ // the Connections
+ auto rTableCon = pUndoAction->GetTabConnList();
+ for(const auto& conn : rTableCon)
+ addConnection(conn); // add all connections from the undo action
+
+ rTableCon.clear();
+
+ // and add the window's data to the list (of the document)
+ if(_bAppend)
+ m_pView->getController().getTableWindowData().push_back(pTabWin->GetData());
+
+ m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE);
+
+ // and inform the UndoAction that the window belongs to me
+ pUndoAction->SetOwnership(false);
+
+ bSuccess = true;
+ }
+ else
+ {
+ // Initialisation failed
+ // (for example when the Connection to the database is not available at the moment)
+ pTabWin->clearListBox();
+ pTabWin->disposeOnce();
+ }
+ }
+
+ // show that I have changed the document
+ if(!m_pView->getController().isReadOnly())
+ m_pView->getController().setModified( true );
+
+ m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
+
+ return bSuccess;
+}
+
+void OQueryTableView::InsertField(const OTableFieldDescRef& rInfo)
+{
+ OSL_ENSURE(getDesignView() != nullptr, "OQueryTableView::InsertField : has no Parent !");
+ static_cast<OQueryDesignView*>(getDesignView())->InsertField(rInfo);
+}
+
+bool OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow* pFrom) const
+{
+ for(const auto& conn : getTableConnections())
+ {
+ OQueryTableConnection* pTemp = static_cast<OQueryTableConnection*>(conn.get());
+ if (pTemp->IsVisited() &&
+ (pFrom == static_cast< OQueryTableWindow*>(pTemp->GetSourceWin()) || pFrom == static_cast< OQueryTableWindow*>(pTemp->GetDestWin())))
+ return true;
+ }
+
+ return false;
+}
+
+void OQueryTableView::onNoColumns_throw()
+{
+ OUString sError(DBA_RES(STR_STATEMENT_WITHOUT_RESULT_SET));
+ ::dbtools::throwSQLException( sError, ::dbtools::StandardSQLState::GENERAL_ERROR, nullptr );
+}
+
+bool OQueryTableView::suppressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const
+{
+ OQueryTableConnectionData* pQueryData = static_cast<OQueryTableConnectionData*>(_pData.get());
+ return pQueryData && (pQueryData->GetJoinType() == CROSS_JOIN);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryTextView.cxx b/dbaccess/source/ui/querydesign/QueryTextView.cxx
new file mode 100644
index 000000000..daeb6ee14
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryTextView.cxx
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxids.hrc>
+#include <QueryTextView.hxx>
+#include <querycontainerwindow.hxx>
+#include <helpids.h>
+#include <querycontroller.hxx>
+#include <sqledit.hxx>
+#include <undosqledit.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+// end of temp classes
+OQueryTextView::OQueryTextView(OQueryContainerWindow* pParent, OQueryController& rController)
+ : InterimItemWindow(pParent, "dbaccess/ui/queryview.ui", "QueryView")
+ , m_rController(rController)
+ , m_xSQL(new SQLEditView(m_xBuilder->weld_scrolled_window("scrolledwindow", true)))
+ , m_xSQLEd(new weld::CustomWeld(*m_xBuilder, "sql", *m_xSQL))
+ , m_timerUndoActionCreation("dbaccess OQueryTextView m_timerUndoActionCreation")
+ , m_timerInvalidate("dbaccess OQueryTextView m_timerInvalidate")
+ , m_bStopTimer(false)
+{
+ m_xSQL->DisableInternalUndo();
+ m_xSQL->SetHelpId(HID_CTL_QRYSQLEDIT);
+ m_xSQL->SetModifyHdl(LINK(this, OQueryTextView, ModifyHdl));
+ m_xSQL->SetAcceptsTab(true);
+
+ m_timerUndoActionCreation.SetTimeout(1000);
+ m_timerUndoActionCreation.SetInvokeHandler(LINK(this, OQueryTextView, OnUndoActionTimer));
+
+ m_timerInvalidate.SetTimeout(200);
+ m_timerInvalidate.SetInvokeHandler(LINK(this, OQueryTextView, OnInvalidateTimer));
+ m_timerInvalidate.Start();
+}
+
+IMPL_LINK_NOARG(OQueryTextView, ModifyHdl, LinkParamNone*, void)
+{
+ if (m_timerUndoActionCreation.IsActive())
+ m_timerUndoActionCreation.Stop();
+ m_timerUndoActionCreation.Start();
+
+ if (!m_rController.isModified())
+ m_rController.setModified(true);
+
+ m_rController.InvalidateFeature(SID_SBA_QRY_EXECUTE);
+ m_rController.InvalidateFeature(SID_CUT);
+ m_rController.InvalidateFeature(SID_COPY);
+}
+
+IMPL_LINK_NOARG(OQueryTextView, OnUndoActionTimer, Timer*, void)
+{
+ OUString aText = m_xSQL->GetText();
+ if (aText == m_strOrigText)
+ return;
+
+ SfxUndoManager& rUndoMgr = m_rController.GetUndoManager();
+ std::unique_ptr<OSqlEditUndoAct> xUndoAct(new OSqlEditUndoAct(*this));
+
+ xUndoAct->SetOriginalText(m_strOrigText);
+ rUndoMgr.AddUndoAction(std::move(xUndoAct));
+
+ m_rController.InvalidateFeature(SID_UNDO);
+ m_rController.InvalidateFeature(SID_REDO);
+
+ m_strOrigText = aText;
+}
+
+IMPL_LINK_NOARG(OQueryTextView, OnInvalidateTimer, Timer*, void)
+{
+ m_rController.InvalidateFeature(SID_CUT);
+ m_rController.InvalidateFeature(SID_COPY);
+ if (!m_bStopTimer)
+ m_timerInvalidate.Start();
+}
+
+void OQueryTextView::startTimer()
+{
+ m_bStopTimer = false;
+ if (!m_timerInvalidate.IsActive())
+ m_timerInvalidate.Start();
+}
+
+void OQueryTextView::stopTimer()
+{
+ m_bStopTimer = true;
+ if (m_timerInvalidate.IsActive())
+ m_timerInvalidate.Stop();
+}
+
+OQueryTextView::~OQueryTextView() { disposeOnce(); }
+
+void OQueryTextView::dispose()
+{
+ if (m_timerUndoActionCreation.IsActive())
+ m_timerUndoActionCreation.Stop();
+
+ m_xSQLEd.reset();
+ m_xSQL.reset();
+ InterimItemWindow::dispose();
+}
+
+void OQueryTextView::GetFocus()
+{
+ if (m_xSQL)
+ {
+ m_xSQL->GrabFocus();
+ m_strOrigText = m_xSQL->GetText();
+ }
+ InterimItemWindow::GetFocus();
+}
+
+OUString OQueryTextView::getStatement() const { return m_xSQL->GetText(); }
+
+void OQueryTextView::clear()
+{
+ std::unique_ptr<OSqlEditUndoAct> xUndoAct(new OSqlEditUndoAct(*this));
+
+ xUndoAct->SetOriginalText(m_xSQL->GetText());
+ m_rController.addUndoActionAndInvalidate(std::move(xUndoAct));
+
+ SetSQLText(OUString());
+}
+
+void OQueryTextView::setStatement(const OUString& rsStatement) { SetSQLText(rsStatement); }
+
+OUString OQueryTextView::GetSQLText() const { return m_xSQL->GetText(); }
+
+void OQueryTextView::SetSQLText(const OUString& rNewText)
+{
+ if (m_timerUndoActionCreation.IsActive())
+ {
+ // create the trailing undo-actions
+ m_timerUndoActionCreation.Stop();
+ OnUndoActionTimer(nullptr);
+ }
+
+ m_xSQL->SetTextAndUpdate(rNewText);
+
+ m_strOrigText = rNewText;
+}
+
+void OQueryTextView::copy() { m_xSQL->Copy(); }
+
+bool OQueryTextView::isCutAllowed() const { return m_xSQL->HasSelection(); }
+
+void OQueryTextView::cut()
+{
+ m_xSQL->Cut();
+ m_rController.setModified(true);
+}
+
+void OQueryTextView::paste()
+{
+ m_xSQL->Paste();
+ m_rController.setModified(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx b/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx
new file mode 100644
index 000000000..a51f2941a
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx
@@ -0,0 +1,292 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <QueryViewSwitch.hxx>
+#include <QueryDesignView.hxx>
+#include <QueryTextView.hxx>
+#include <querycontainerwindow.hxx>
+#include <adtabdlg.hxx>
+#include <querycontroller.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+OQueryViewSwitch::OQueryViewSwitch(OQueryContainerWindow* _pParent, OQueryController& _rController,const Reference< XComponentContext >& _rxContext)
+: m_bAddTableDialogWasVisible(false)
+{
+
+ m_pTextView = VclPtr<OQueryTextView>::Create(_pParent, _rController);
+ m_pDesignView = VclPtr<OQueryDesignView>::Create( _pParent, _rController, _rxContext );
+}
+
+OQueryViewSwitch::~OQueryViewSwitch()
+{
+ // destroy children
+ m_pDesignView.disposeAndClear();
+ m_pTextView.disposeAndClear();
+}
+
+void OQueryViewSwitch::Construct()
+{
+ m_pDesignView->Construct( );
+}
+
+void OQueryViewSwitch::initialize()
+{
+ // initially be in SQL mode
+ m_pTextView->Show();
+ m_pDesignView->initialize();
+}
+
+bool OQueryViewSwitch::checkStatement()
+{
+ if(m_pTextView->IsVisible())
+ return true;
+ return m_pDesignView->checkStatement();
+}
+
+OUString OQueryViewSwitch::getStatement()
+{
+ if(m_pTextView->IsVisible())
+ return m_pTextView->getStatement();
+ return m_pDesignView->getStatement();
+}
+
+void OQueryViewSwitch::clear()
+{
+ if(m_pTextView->IsVisible())
+ m_pTextView->clear();
+ else
+ m_pDesignView->clear();
+}
+
+void OQueryViewSwitch::GrabFocus()
+{
+ if ( m_pTextView && m_pTextView->IsVisible() )
+ m_pTextView->GrabFocus();
+ else if ( m_pDesignView && m_pDesignView->IsVisible() )
+ m_pDesignView->GrabFocus();
+}
+
+void OQueryViewSwitch::setStatement(const OUString& _rsStatement)
+{
+ if(m_pTextView->IsVisible())
+ m_pTextView->setStatement(_rsStatement);
+}
+
+void OQueryViewSwitch::copy()
+{
+ if(m_pTextView->IsVisible())
+ m_pTextView->copy();
+ else
+ m_pDesignView->copy();
+}
+
+bool OQueryViewSwitch::isCutAllowed() const
+{
+ if(m_pTextView->IsVisible())
+ return m_pTextView->isCutAllowed();
+ return m_pDesignView->isCutAllowed();
+}
+
+bool OQueryViewSwitch::isCopyAllowed() const
+{
+ if(m_pTextView->IsVisible())
+ return true;
+ return m_pDesignView->isCopyAllowed();
+}
+
+bool OQueryViewSwitch::isPasteAllowed() const
+{
+ if(m_pTextView->IsVisible())
+ return true;
+ return m_pDesignView->isPasteAllowed();
+}
+
+void OQueryViewSwitch::cut()
+{
+ if(m_pTextView->IsVisible())
+ m_pTextView->cut();
+ else
+ m_pDesignView->cut();
+}
+
+void OQueryViewSwitch::paste()
+{
+ if(m_pTextView->IsVisible())
+ m_pTextView->paste();
+ else
+ m_pDesignView->paste();
+}
+
+OQueryContainerWindow* OQueryViewSwitch::getContainer() const
+{
+ vcl::Window* pDesignParent = getDesignView() ? getDesignView()->GetParent() : nullptr;
+ return static_cast< OQueryContainerWindow* >( pDesignParent );
+}
+
+void OQueryViewSwitch::impl_forceSQLView()
+{
+ OAddTableDlg* pAddTabDialog( getAddTableDialog() );
+
+ // hide the "Add Table" dialog
+ m_bAddTableDialogWasVisible = pAddTabDialog != nullptr;
+ if (m_bAddTableDialogWasVisible)
+ pAddTabDialog->response(RET_CLOSE);
+
+ // tell the views they're in/active
+ m_pDesignView->stopTimer();
+ m_pTextView->startTimer();
+
+ // set the most recent statement at the text view
+ m_pTextView->clear();
+ m_pTextView->setStatement(static_cast<OQueryController&>(m_pDesignView->getController()).getStatement());
+}
+
+void OQueryViewSwitch::forceInitialView()
+{
+ OQueryController& rQueryController( static_cast< OQueryController& >( m_pDesignView->getController() ) );
+ const bool bGraphicalDesign = rQueryController.isGraphicalDesign();
+ if ( !bGraphicalDesign )
+ impl_forceSQLView();
+ else
+ {
+ // tell the text view it's inactive now
+ m_pTextView->stopTimer();
+
+ // update the "Add Table" dialog
+ OAddTableDlg* pAddTabDialog( getAddTableDialog() );
+ if ( pAddTabDialog )
+ pAddTabDialog->Update();
+
+ // initialize the design view
+ m_pDesignView->initByFieldDescriptions( rQueryController.getFieldInformation() );
+
+ // tell the design view it's active now
+ m_pDesignView->startTimer();
+ }
+
+ impl_postViewSwitch( bGraphicalDesign, true );
+}
+
+bool OQueryViewSwitch::switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo )
+{
+ bool bRet = true;
+ bool bGraphicalDesign = static_cast<OQueryController&>(m_pDesignView->getController()).isGraphicalDesign();
+
+ if ( !bGraphicalDesign )
+ {
+ impl_forceSQLView();
+ }
+ else
+ {
+ // tell the text view it's inactive now
+ m_pTextView->stopTimer();
+
+ // update the "Add Table" dialog
+ OAddTableDlg* pAddTabDialog( getAddTableDialog() );
+ if ( pAddTabDialog )
+ pAddTabDialog->Update();
+
+ // initialize the design view
+ bRet = m_pDesignView->initByParseIterator( _pErrorInfo );
+
+ // tell the design view it's active now
+ m_pDesignView->startTimer();
+ }
+
+ return impl_postViewSwitch( bGraphicalDesign, bRet );
+}
+
+bool OQueryViewSwitch::impl_postViewSwitch( const bool i_bGraphicalDesign, const bool i_bSuccess )
+{
+ if ( i_bSuccess )
+ {
+ m_pTextView->Show ( !i_bGraphicalDesign );
+ m_pDesignView->Show ( i_bGraphicalDesign );
+ OAddTableDlg* pAddTabDialog( getAddTableDialog() );
+ if ( pAddTabDialog )
+ if ( i_bGraphicalDesign && m_bAddTableDialogWasVisible )
+ m_pDesignView->getController().runDialogAsync();
+
+ GrabFocus();
+ }
+
+ OQueryContainerWindow* pContainer = getContainer();
+ if ( pContainer )
+ pContainer->Resize();
+
+ m_pDesignView->getController().ClearUndoManager();
+ m_pDesignView->getController().InvalidateAll();
+
+ return i_bSuccess;
+}
+
+OAddTableDlg* OQueryViewSwitch::getAddTableDialog()
+{
+ if ( !m_pDesignView )
+ return nullptr;
+ return m_pDesignView->getController().getAddTableDialog();
+}
+
+bool OQueryViewSwitch::isSlotEnabled(sal_Int32 _nSlotId)
+{
+ return m_pDesignView->isSlotEnabled(_nSlotId);
+}
+
+void OQueryViewSwitch::setSlotEnabled(sal_Int32 _nSlotId, bool _bEnable)
+{
+ m_pDesignView->setSlotEnabled(_nSlotId,_bEnable);
+}
+
+void OQueryViewSwitch::SaveUIConfig()
+{
+ if(m_pDesignView->IsVisible())
+ m_pDesignView->SaveUIConfig();
+}
+
+void OQueryViewSwitch::SetPosSizePixel( Point _rPt,Size _rSize)
+{
+ m_pDesignView->SetPosSizePixel( _rPt,_rSize);
+ m_pDesignView->Resize();
+ m_pTextView->SetPosSizePixel( _rPt,_rSize);
+}
+
+Reference< XComponentContext > const & OQueryViewSwitch::getORB() const
+{
+ return m_pDesignView->getORB();
+}
+
+void OQueryViewSwitch::reset()
+{
+ m_pDesignView->reset();
+ if ( !m_pDesignView->initByParseIterator( nullptr ) )
+ return;
+
+ switchView( nullptr );
+}
+
+void OQueryViewSwitch::setNoneVisibleRow(sal_Int32 _nRows)
+{
+ if(m_pDesignView)
+ m_pDesignView->setNoneVisibleRow(_nRows);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx b/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx
new file mode 100644
index 000000000..414d6bbdc
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx
@@ -0,0 +1,2720 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "SelectionBrowseBox.hxx"
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <JoinExchange.hxx>
+#include <QueryDesignView.hxx>
+#include <querycontroller.hxx>
+#include <sqlbison.hxx>
+#include <QueryTableView.hxx>
+#include <browserids.hxx>
+#include <comphelper/stl_types.hxx>
+#include <comphelper/string.hxx>
+#include "TableFieldInfo.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <helpids.h>
+#include "QTableWindow.hxx"
+#include <vcl/weld.hxx>
+#include <vcl/settings.hxx>
+#include "QueryDesignFieldUndoAct.hxx"
+#include <sqlmessage.hxx>
+#include <UITools.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <i18nlangtag/languagetag.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+using namespace ::svt;
+using namespace ::dbaui;
+using namespace ::connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::accessibility;
+
+#define DEFAULT_QUERY_COLS 20
+#define DEFAULT_SIZE GetTextWidth("0") * 30
+#define HANDLE_ID 0
+#define HANDLE_COLUMN_WIDTH 70
+#define SORT_COLUMN_NONE 0xFFFFFFFF
+
+namespace
+{
+ bool isFieldNameAsterisk(const OUString& _sFieldName )
+ {
+ bool bAsterisk = _sFieldName.isEmpty() || _sFieldName.toChar() == '*';
+ if ( !bAsterisk )
+ {
+ sal_Int32 nTokenCount = comphelper::string::getTokenCount(_sFieldName, '.');
+ if ( (nTokenCount == 2 && o3tl::getToken(_sFieldName,1,'.')[0] == '*' )
+ || (nTokenCount == 3 && o3tl::getToken(_sFieldName,2,'.')[0] == '*' ) )
+ {
+ bAsterisk = true;
+ }
+ }
+ return bAsterisk;
+ }
+ bool lcl_SupportsCoreSQLGrammar(const Reference< XConnection>& _xConnection)
+ {
+ bool bSupportsCoreGrammar = false;
+ if ( _xConnection.is() )
+ {
+ try
+ {
+ Reference< XDatabaseMetaData > xMetaData = _xConnection->getMetaData();
+ bSupportsCoreGrammar = xMetaData.is() && xMetaData->supportsCoreSQLGrammar();
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ return bSupportsCoreGrammar;
+ }
+}
+
+OSelectionBrowseBox::OSelectionBrowseBox( vcl::Window* pParent )
+ :EditBrowseBox( pParent,EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT, WB_3DLOOK, BrowserMode::COLUMNSELECTION | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HIDESELECT |
+ BrowserMode::HIDECURSOR | BrowserMode::HLINES | BrowserMode::VLINES )
+ ,m_timerInvalidate("dbaccess OSelectionBrowseBox m_timerInvalidate")
+ ,m_nSeekRow(0)
+ ,m_nMaxColumns(0)
+ ,m_aFunctionStrings(DBA_RES(STR_QUERY_FUNCTIONS))
+ ,m_nVisibleCount(0)
+ ,m_nLastSortColumn(SORT_COLUMN_NONE)
+ ,m_bOrderByUnRelated(true)
+ ,m_bGroupByUnRelated(true)
+ ,m_bStopTimer(false)
+ ,m_bWasEditing(false)
+ ,m_bDisableErrorBox(false)
+ ,m_bInUndoMode(false)
+{
+ SetHelpId(HID_CTL_QRYDGNCRIT);
+
+ m_nMode = BrowserMode::COLUMNSELECTION | BrowserMode::HIDESELECT
+ | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HIDECURSOR
+ | BrowserMode::HLINES | BrowserMode::VLINES
+ | BrowserMode::HEADERBAR_NEW ;
+
+ m_pTextCell = VclPtr<EditControl>::Create(&GetDataWindow());
+ m_pVisibleCell = VclPtr<CheckBoxControl>::Create(&GetDataWindow());
+ m_pTableCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
+ m_pFieldCell = VclPtr<ComboBoxControl>::Create(&GetDataWindow());
+ m_pOrderCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
+ m_pFunctionCell = VclPtr<ListBoxControl>::Create(&GetDataWindow());
+
+ m_pVisibleCell->SetHelpId(HID_QRYDGN_ROW_VISIBLE);
+ m_pTableCell->SetHelpId(HID_QRYDGN_ROW_TABLE);
+ m_pFieldCell->SetHelpId(HID_QRYDGN_ROW_FIELD);
+ weld::ComboBox& rOrderBox = m_pOrderCell->get_widget();
+ m_pOrderCell->SetHelpId(HID_QRYDGN_ROW_ORDER);
+ m_pFunctionCell->SetHelpId(HID_QRYDGN_ROW_FUNCTION);
+
+ // switch off triState of css::form::CheckBox
+ m_pVisibleCell->EnableTriState( false );
+
+ vcl::Font aTitleFont = OutputDevice::GetDefaultFont( DefaultFontType::SANS_UNICODE,Window::GetSettings().GetLanguageTag().getLanguageType(),GetDefaultFontFlags::OnlyOne);
+ aTitleFont.SetFontSize(Size(0, 6));
+ SetTitleFont(aTitleFont);
+
+ const OUString aTxt(DBA_RES(STR_QUERY_SORTTEXT));
+ for (sal_Int32 nIdx {0}; nIdx>=0;)
+ rOrderBox.append_text(OUString(o3tl::getToken(aTxt, 0, ';', nIdx)));
+
+ m_bVisibleRow.insert(m_bVisibleRow.end(), BROW_ROW_CNT, true);
+
+ m_bVisibleRow[BROW_FUNCTION_ROW] = false; // first hide
+
+ m_timerInvalidate.SetTimeout(200);
+ m_timerInvalidate.SetInvokeHandler(LINK(this, OSelectionBrowseBox, OnInvalidateTimer));
+ m_timerInvalidate.Start();
+}
+
+OSelectionBrowseBox::~OSelectionBrowseBox()
+{
+ disposeOnce();
+}
+
+void OSelectionBrowseBox::dispose()
+{
+ m_pTextCell.disposeAndClear();
+ m_pVisibleCell.disposeAndClear();
+ m_pFieldCell.disposeAndClear();
+ m_pTableCell.disposeAndClear();
+ m_pOrderCell.disposeAndClear();
+ m_pFunctionCell.disposeAndClear();
+ ::svt::EditBrowseBox::dispose();
+}
+
+void OSelectionBrowseBox::initialize()
+{
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
+ if(xConnection.is())
+ {
+ const IParseContext& rContext = static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext();
+ const IParseContext::InternationalKeyCode eFunctions[] = {
+ IParseContext::InternationalKeyCode::Avg,IParseContext::InternationalKeyCode::Count,IParseContext::InternationalKeyCode::Max
+ ,IParseContext::InternationalKeyCode::Min,IParseContext::InternationalKeyCode::Sum
+ ,IParseContext::InternationalKeyCode::Every
+ ,IParseContext::InternationalKeyCode::Any
+ ,IParseContext::InternationalKeyCode::Some
+ ,IParseContext::InternationalKeyCode::StdDevPop
+ ,IParseContext::InternationalKeyCode::StdDevSamp
+ ,IParseContext::InternationalKeyCode::VarSamp
+ ,IParseContext::InternationalKeyCode::VarPop
+ ,IParseContext::InternationalKeyCode::Collect
+ ,IParseContext::InternationalKeyCode::Fusion
+ ,IParseContext::InternationalKeyCode::Intersection
+ };
+
+ OUString sGroup = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1);
+ m_aFunctionStrings = m_aFunctionStrings.getToken(0, ';');
+
+ for (IParseContext::InternationalKeyCode eFunction : eFunctions)
+ {
+ m_aFunctionStrings += ";" + OStringToOUString(rContext.getIntlKeywordAscii(eFunction), RTL_TEXTENCODING_UTF8);
+ }
+ m_aFunctionStrings += ";" + sGroup;
+
+ // Aggregate functions in general available only with Core SQL
+ // We slip in a few optionals one, too.
+ if ( lcl_SupportsCoreSQLGrammar(xConnection) )
+ {
+ weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
+ for (sal_Int32 nIdx {0}; nIdx>=0;)
+ rComboBox.append_text(m_aFunctionStrings.getToken(0, ';', nIdx));
+ }
+ else // else only COUNT(*) and COUNT("table".*)
+ {
+ weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
+ rComboBox.append_text(m_aFunctionStrings.getToken(0, ';'));
+ rComboBox.append_text(m_aFunctionStrings.getToken(2, ';')); // 2 -> COUNT
+ }
+ try
+ {
+ Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ if ( xMetaData.is() )
+ {
+ m_bOrderByUnRelated = xMetaData->supportsOrderByUnrelated();
+ m_bGroupByUnRelated = xMetaData->supportsGroupByUnrelated();
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+
+ Init();
+}
+
+OQueryDesignView* OSelectionBrowseBox::getDesignView()
+{
+ OSL_ENSURE(static_cast<const OQueryDesignView*>(GetParent()),"Parent isn't an OQueryDesignView!");
+ return static_cast<OQueryDesignView*>(GetParent());
+}
+
+OQueryDesignView* OSelectionBrowseBox::getDesignView() const
+{
+ OSL_ENSURE(static_cast<const OQueryDesignView*>(GetParent()),"Parent isn't an OQueryDesignView!");
+ return static_cast<OQueryDesignView*>(GetParent());
+}
+
+namespace
+{
+ class OSelectionBrwBoxHeader : public ::svt::EditBrowserHeader
+ {
+ VclPtr<OSelectionBrowseBox> m_pBrowseBox;
+ protected:
+ virtual void Select() override;
+ public:
+ explicit OSelectionBrwBoxHeader(OSelectionBrowseBox* pParent);
+ virtual ~OSelectionBrwBoxHeader() override { disposeOnce(); }
+ virtual void dispose() override { m_pBrowseBox.clear(); ::svt::EditBrowserHeader::dispose(); }
+ };
+ OSelectionBrwBoxHeader::OSelectionBrwBoxHeader(OSelectionBrowseBox* pParent)
+ : ::svt::EditBrowserHeader(pParent,WB_BUTTONSTYLE|WB_DRAG)
+ ,m_pBrowseBox(pParent)
+ {
+ }
+
+ void OSelectionBrwBoxHeader::Select()
+ {
+ EditBrowserHeader::Select();
+ m_pBrowseBox->GrabFocus();
+
+ BrowserMode nMode = m_pBrowseBox->GetMode();
+ if ( 0 == m_pBrowseBox->GetSelectColumnCount() )
+ {
+ m_pBrowseBox->DeactivateCell();
+ // we are in the right mode if a row has been selected row
+ if ( nMode & BrowserMode::HIDESELECT )
+ {
+ nMode &= ~BrowserMode::HIDESELECT;
+ nMode |= BrowserMode::MULTISELECTION;
+ m_pBrowseBox->SetMode( nMode );
+ }
+ }
+ m_pBrowseBox->SelectColumnId( GetCurItemId() );
+ m_pBrowseBox->DeactivateCell();
+ }
+}
+
+VclPtr<BrowserHeader> OSelectionBrowseBox::imp_CreateHeaderBar(BrowseBox* /*pParent*/)
+{
+ return VclPtr<OSelectionBrwBoxHeader>::Create(this);
+}
+
+void OSelectionBrowseBox::ColumnMoved( sal_uInt16 nColId, bool _bCreateUndo )
+{
+ EditBrowseBox::ColumnMoved( nColId );
+ // swap the two columns
+ sal_uInt16 nNewPos = GetColumnPos( nColId );
+ OTableFields& rFields = getFields();
+ if ( rFields.size() > o3tl::make_unsigned(nNewPos-1) )
+ {
+ sal_uInt16 nOldPos = 0;
+ bool bFoundElem = false;
+ for (auto const& field : rFields)
+ {
+ if (field->GetColumnId() == nColId)
+ {
+ bFoundElem = true;
+ break;
+ }
+ ++nOldPos;
+ }
+
+ OSL_ENSURE( (nNewPos-1) != nOldPos && nOldPos < rFields.size(),"Old and new position are equal!");
+ if (bFoundElem)
+ {
+ OTableFieldDescRef pOldEntry = rFields[nOldPos];
+ rFields.erase(rFields.begin() + nOldPos);
+ rFields.insert(rFields.begin() + nNewPos - 1,pOldEntry);
+
+ // create the undo action
+ if ( !m_bInUndoMode && _bCreateUndo )
+ {
+ std::unique_ptr<OTabFieldMovedUndoAct> pUndoAct(new OTabFieldMovedUndoAct(this));
+ pUndoAct->SetColumnPosition( nOldPos + 1);
+ pUndoAct->SetTabFieldDescr(pOldEntry);
+
+ getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndoAct));
+ }
+ }
+ }
+ else
+ OSL_FAIL("Invalid column id!");
+}
+
+void OSelectionBrowseBox::Init()
+{
+
+ EditBrowseBox::Init();
+
+ // set the header bar
+ VclPtr<BrowserHeader> pNewHeaderBar = CreateHeaderBar(this);
+ pNewHeaderBar->SetMouseTransparent(false);
+
+ SetHeaderBar(pNewHeaderBar);
+ SetMode(m_nMode);
+
+ vcl::Font aFont( GetDataWindow().GetFont() );
+ aFont.SetWeight( WEIGHT_NORMAL );
+ GetDataWindow().SetFont( aFont );
+
+ Size aHeight;
+ const Control* pControls[] = { m_pTextCell,m_pVisibleCell,m_pTableCell,m_pFieldCell };
+
+ for (const Control* pControl : pControls)
+ {
+ const Size aTemp(pControl->GetOptimalSize());
+ if ( aTemp.Height() > aHeight.Height() )
+ aHeight.setHeight( aTemp.Height() );
+ }
+ SetDataRowHeight(aHeight.Height());
+ SetTitleLines(1);
+ // get number of visible rows
+ for(tools::Long i=0;i<BROW_ROW_CNT;i++)
+ {
+ if(m_bVisibleRow[i])
+ m_nVisibleCount++;
+ }
+ RowInserted(0, m_nVisibleCount, false);
+ try
+ {
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
+ if(xConnection.is())
+ {
+ Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
+ m_nMaxColumns = xMetaData.is() ? xMetaData->getMaxColumnsInSelect() : 0;
+
+ }
+ else
+ m_nMaxColumns = 0;
+ }
+ catch(const SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "Caught Exception when asking for database metadata options!");
+ m_nMaxColumns = 0;
+ }
+}
+
+void OSelectionBrowseBox::PreFill()
+{
+ SetUpdateMode(false);
+
+ if (GetCurRow() != 0)
+ GoToRow(0);
+
+ static_cast< OQueryController& >( getDesignView()->getController() ).clearFields();
+
+ DeactivateCell();
+
+ RemoveColumns();
+ InsertHandleColumn( HANDLE_COLUMN_WIDTH );
+ SetUpdateMode(true);
+}
+
+void OSelectionBrowseBox::ClearAll()
+{
+ SetUpdateMode(false);
+
+ OTableFields::const_reverse_iterator aIter = getFields().rbegin();
+ for ( ;aIter != getFields().rend(); ++aIter )
+ {
+ if ( !(*aIter)->IsEmpty() )
+ {
+ RemoveField( (*aIter)->GetColumnId() );
+ aIter = getFields().rbegin();
+ }
+ }
+ m_nLastSortColumn = SORT_COLUMN_NONE;
+ SetUpdateMode(true);
+}
+
+void OSelectionBrowseBox::SetReadOnly(bool bRO)
+{
+ if (bRO)
+ {
+ DeactivateCell();
+ m_nMode &= ~BrowserMode::HIDECURSOR;
+ SetMode(m_nMode);
+ }
+ else
+ {
+ m_nMode |= BrowserMode::HIDECURSOR;
+ SetMode(m_nMode);
+ ActivateCell();
+ }
+}
+
+CellController* OSelectionBrowseBox::GetController(sal_Int32 nRow, sal_uInt16 nColId)
+{
+ if ( nColId > getFields().size() )
+ return nullptr;
+ OTableFieldDescRef pEntry = getFields()[nColId-1];
+ OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::GetController : invalid FieldDescription !");
+
+ if (!pEntry.is())
+ return nullptr;
+
+ if (static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
+ return nullptr;
+
+ sal_Int32 nCellIndex = GetRealRow(nRow);
+ switch (nCellIndex)
+ {
+ case BROW_FIELD_ROW:
+ return new ComboBoxCellController(m_pFieldCell);
+ case BROW_TABLE_ROW:
+ return new ListBoxCellController(m_pTableCell);
+ case BROW_VIS_ROW:
+ return new CheckBoxCellController(m_pVisibleCell);
+ case BROW_ORDER_ROW:
+ return new ListBoxCellController(m_pOrderCell);
+ case BROW_FUNCTION_ROW:
+ return new ListBoxCellController(m_pFunctionCell);
+ default:
+ return new EditCellController(m_pTextCell);
+ }
+}
+
+void OSelectionBrowseBox::InitController(CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColId)
+{
+ OSL_ENSURE(nColId != BROWSER_INVALIDID,"An Invalid Id was set!");
+ if ( nColId == BROWSER_INVALIDID )
+ return;
+ sal_uInt16 nPos = GetColumnPos(nColId);
+ if ( nPos == 0 || nPos == BROWSER_INVALIDID || nPos > getFields().size() )
+ return;
+ OTableFieldDescRef pEntry = getFields()[nPos-1];
+ OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::InitController : invalid FieldDescription !");
+ sal_Int32 nCellIndex = GetRealRow(nRow);
+
+ switch (nCellIndex)
+ {
+ case BROW_FIELD_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
+ rComboBox.clear();
+ rComboBox.set_entry_text(OUString());
+
+ OUString aField(pEntry->GetField());
+ OUString aTable(pEntry->GetAlias());
+
+ getDesignView()->fillValidFields(aTable, rComboBox);
+
+ // replace with alias.*
+ if (o3tl::trim(aField) == u"*")
+ {
+ aField = aTable + ".*";
+ }
+ rComboBox.set_entry_text(aField);
+ } break;
+ case BROW_TABLE_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pTableCell->get_widget();
+ rComboBox.clear();
+ enableControl(pEntry, m_pTableCell);
+ if ( !pEntry->isCondition() )
+ {
+ for (auto const& tabWin : getDesignView()->getTableView()->GetTabWinMap())
+ rComboBox.append_text(static_cast<OQueryTableWindow*>(tabWin.second.get())->GetAliasName());
+
+ rComboBox.insert_text(0, DBA_RES(STR_QUERY_NOTABLE));
+ if (!pEntry->GetAlias().isEmpty())
+ rComboBox.set_active_text(pEntry->GetAlias());
+ else
+ rComboBox.set_active_text(DBA_RES(STR_QUERY_NOTABLE));
+ }
+ } break;
+ case BROW_VIS_ROW:
+ {
+ m_pVisibleCell->GetBox().set_active(pEntry->IsVisible());
+ m_pVisibleCell->GetBox().save_state();
+
+ enableControl(pEntry,m_pTextCell);
+
+ if(!pEntry->IsVisible() && pEntry->GetOrderDir() != ORDER_NONE && !m_bOrderByUnRelated)
+ {
+ // a column has to visible in order to show up in ORDER BY
+ pEntry->SetVisible();
+ m_pVisibleCell->GetBox().set_active(pEntry->IsVisible());
+ m_pVisibleCell->GetBox().save_state();
+ m_pVisibleCell->GetBox().set_sensitive(false);
+ OUString aMessage(DBA_RES(STR_QRY_ORDERBY_UNRELATED));
+ OQueryDesignView* paDView = getDesignView();
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(paDView ? paDView->GetFrameWeld() : nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ aMessage));
+ xInfoBox->run();
+ }
+ } break;
+ case BROW_ORDER_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pOrderCell->get_widget();
+ rComboBox.set_active(
+ sal::static_int_cast< sal_uInt16 >(pEntry->GetOrderDir()));
+ enableControl(pEntry,m_pOrderCell);
+ break;
+ }
+ case BROW_COLUMNALIAS_ROW:
+ setTextCellContext(pEntry,pEntry->GetFieldAlias(),HID_QRYDGN_ROW_ALIAS);
+ break;
+ case BROW_FUNCTION_ROW:
+ setFunctionCell(pEntry);
+ break;
+ default:
+ {
+ sal_uInt16 nIdx = sal_uInt16(nCellIndex - BROW_CRIT1_ROW);
+ setTextCellContext(pEntry,pEntry->GetCriteria( nIdx ),HID_QRYDGN_ROW_CRIT);
+ }
+ }
+ Controller()->SaveValue();
+}
+
+void OSelectionBrowseBox::notifyTableFieldChanged(const OUString& _sOldAlias, std::u16string_view _sAlias, bool& _bListAction, sal_uInt16 _nColumnId)
+{
+ appendUndoAction(_sOldAlias,_sAlias,BROW_TABLE_ROW,_bListAction);
+ if ( m_bVisibleRow[BROW_TABLE_ROW] )
+ RowModified(GetBrowseRow(BROW_TABLE_ROW), _nColumnId);
+}
+
+void OSelectionBrowseBox::notifyFunctionFieldChanged(const OUString& _sOldFunctionName, std::u16string_view _sFunctionName, bool& _bListAction, sal_uInt16 _nColumnId)
+{
+ appendUndoAction(_sOldFunctionName,_sFunctionName,BROW_FUNCTION_ROW,_bListAction);
+ if ( !m_bVisibleRow[BROW_FUNCTION_ROW] )
+ SetRowVisible(BROW_FUNCTION_ROW, true);
+ RowModified(GetBrowseRow(BROW_FUNCTION_ROW), _nColumnId);
+}
+
+void OSelectionBrowseBox::clearEntryFunctionField(const OUString& _sFieldName,OTableFieldDescRef const & _pEntry, bool& _bListAction,sal_uInt16 _nColumnId)
+{
+ if ( !(isFieldNameAsterisk( _sFieldName ) && (!_pEntry->isNoneFunction() || _pEntry->IsGroupBy())) )
+ return;
+
+ OUString sFunctionName;
+ GetFunctionName(SQL_TOKEN_COUNT,sFunctionName);
+ OUString sOldLocalizedFunctionName = _pEntry->GetFunction();
+ if ( sOldLocalizedFunctionName != sFunctionName || _pEntry->IsGroupBy() )
+ {
+ // append undo action for the function field
+ _pEntry->SetFunctionType(FKT_NONE);
+ _pEntry->SetFunction(OUString());
+ _pEntry->SetGroupBy(false);
+ notifyFunctionFieldChanged(sOldLocalizedFunctionName,_pEntry->GetFunction(),_bListAction,_nColumnId);
+ }
+}
+
+bool OSelectionBrowseBox::fillColumnRef(const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection, OTableFieldDescRef const & _pEntry, bool& _bListAction )
+{
+ OSL_ENSURE(_pColumnRef,"No valid parsenode!");
+ OUString sColumnName,sTableRange;
+ OSQLParseTreeIterator::getColumnRange(_pColumnRef,_rxConnection,sColumnName,sTableRange);
+ return fillColumnRef(sColumnName,sTableRange,_rxConnection->getMetaData(),_pEntry,_bListAction);
+}
+
+bool OSelectionBrowseBox::fillColumnRef(const OUString& _sColumnName, std::u16string_view _sTableRange, const Reference<XDatabaseMetaData>& _xMetaData, OTableFieldDescRef const & _pEntry, bool& _bListAction)
+{
+ bool bError = false;
+ ::comphelper::UStringMixEqual bCase(_xMetaData->supportsMixedCaseQuotedIdentifiers());
+ // check if the table name is the same
+ if ( !_sTableRange.empty() && (bCase(_pEntry->GetTable(),_sTableRange) || bCase(_pEntry->GetAlias(),_sTableRange)) )
+ { // a table was already inserted and the tables contains that column name
+
+ if ( !_pEntry->GetTabWindow() )
+ { // fill tab window
+ OUString sOldAlias = _pEntry->GetAlias();
+ if ( !fillEntryTable(_pEntry,_pEntry->GetTable()) )
+ fillEntryTable(_pEntry,_pEntry->GetAlias()); // only when the first failed
+ if ( !bCase(sOldAlias,_pEntry->GetAlias()) )
+ notifyTableFieldChanged(sOldAlias,_pEntry->GetAlias(),_bListAction,GetCurColumnId());
+ }
+ }
+ // check if the table window
+ OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(_pEntry->GetTabWindow());
+ if ( !pEntryTab ) // no table found with this name so we have to travel through all tables
+ {
+ sal_uInt16 nTabCount = 0;
+ if ( !static_cast<OQueryTableView*>(getDesignView()->getTableView())->FindTableFromField(_sColumnName,_pEntry,nTabCount) ) // error occurred: column not in table window
+ {
+ OUString sErrorMsg(DBA_RES(RID_STR_FIELD_DOESNT_EXIST));
+ sErrorMsg = sErrorMsg.replaceFirst("$name$",_sColumnName);
+ OSQLErrorBox aWarning(GetFrameWeld(), sErrorMsg);
+ aWarning.run();
+ bError = true;
+ }
+ else
+ {
+ pEntryTab = static_cast<OQueryTableWindow*>(_pEntry->GetTabWindow());
+ notifyTableFieldChanged(OUString(),_pEntry->GetAlias(),_bListAction,GetCurColumnId());
+ }
+ }
+ if ( pEntryTab ) // here we got a valid table
+ _pEntry->SetField(_sColumnName);
+
+ return bError;
+}
+
+bool OSelectionBrowseBox::saveField(OUString& _sFieldName ,OTableFieldDescRef const & _pEntry, bool& _bListAction)
+{
+ bool bError = false;
+
+ OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
+
+ // first look if the name can be found in our tables
+ sal_uInt16 nTabCount = 0;
+ OUString sOldAlias = _pEntry->GetAlias();
+ if ( static_cast<OQueryTableView*>(getDesignView()->getTableView())->FindTableFromField(_sFieldName,_pEntry,nTabCount) )
+ {
+ // append undo action for the alias name
+ _pEntry->SetField(_sFieldName);
+ notifyTableFieldChanged(sOldAlias,_pEntry->GetAlias(),_bListAction,GetCurColumnId());
+ clearEntryFunctionField(_sFieldName,_pEntry,_bListAction,_pEntry->GetColumnId());
+ return bError;
+ }
+
+ Reference<XConnection> xConnection( rController.getConnection() );
+ Reference< XDatabaseMetaData > xMetaData;
+ if ( xConnection.is() )
+ xMetaData = xConnection->getMetaData();
+ OSL_ENSURE( xMetaData.is(), "OSelectionBrowseBox::saveField: invalid connection/meta data!" );
+ if ( !xMetaData.is() )
+ return true;
+
+ OUString sErrorMsg;
+ // second test if the name can be set as select columns in a pseudo statement
+ // we have to look which entries we should quote
+
+ const OUString sFieldAlias = _pEntry->GetFieldAlias();
+ ::connectivity::OSQLParser& rParser( rController.getParser() );
+ {
+ // automatically add parentheses around subqueries
+ OUString devnull;
+ std::unique_ptr<OSQLParseNode> pParseNode = rParser.parseTree( devnull, _sFieldName, true );
+ if (pParseNode == nullptr)
+ pParseNode = rParser.parseTree( devnull, _sFieldName );
+ if (pParseNode != nullptr && SQL_ISRULE(pParseNode, select_statement))
+ _sFieldName = "(" + _sFieldName + ")";
+ }
+
+ std::unique_ptr<OSQLParseNode> pParseNode;
+ {
+ // 4 passes in trying to interpret the field name
+ // - don't quote the field name, parse internationally
+ // - don't quote the field name, parse en-US
+ // - quote the field name, parse internationally
+ // - quote the field name, parse en-US
+ size_t nPass = 4;
+ OUString sQuotedFullFieldName(::dbtools::quoteName( xMetaData->getIdentifierQuoteString(), _sFieldName ));
+ OUString sFullFieldName(_sFieldName);
+
+ if ( _pEntry->isAggregateFunction() )
+ {
+ OSL_ENSURE(!_pEntry->GetFunction().isEmpty(),"No empty Function name allowed here! ;-(");
+ sQuotedFullFieldName = _pEntry->GetFunction() + "(" + sQuotedFullFieldName + ")";
+ sFullFieldName = _pEntry->GetFunction() + "(" + sFullFieldName + ")";
+ }
+
+ do
+ {
+ bool bQuote = ( nPass <= 2 );
+ bool bInternational = ( nPass % 2 ) == 0;
+
+ OUString sSql {"SELECT "};
+ if ( bQuote )
+ sSql += sQuotedFullFieldName;
+ else
+ sSql += sFullFieldName;
+
+ if ( !sFieldAlias.isEmpty() )
+ { // always quote the alias name: there cannot be a function in it
+ sSql += " " + ::dbtools::quoteName( xMetaData->getIdentifierQuoteString(), sFieldAlias );
+ }
+ sSql += " FROM x";
+
+ pParseNode = rParser.parseTree( sErrorMsg, sSql, bInternational );
+ }
+ while ( ( pParseNode == nullptr ) && ( --nPass > 0 ) );
+ }
+
+ if ( pParseNode == nullptr )
+ {
+ // something different which we have to check
+ OUString sErrorMessage( DBA_RES( STR_QRY_COLUMN_NOT_FOUND ) );
+ sErrorMessage = sErrorMessage.replaceFirst("$name$",_sFieldName);
+ OSQLErrorBox aWarning(GetFrameWeld(), sErrorMessage);
+ aWarning.run();
+
+ return true;
+ }
+
+ // we got a valid select column
+ // find what type of column has be inserted
+ ::connectivity::OSQLParseNode* pSelection = pParseNode->getChild(2);
+ if ( SQL_ISRULE(pSelection,selection) ) // we found the asterisk
+ {
+ _pEntry->SetField(_sFieldName);
+ clearEntryFunctionField(_sFieldName,_pEntry,_bListAction,_pEntry->GetColumnId());
+ }
+ else // travel through the select column parse node
+ {
+ OTableFieldDescRef aSelEntry = _pEntry;
+ sal_uInt16 nColumnId = aSelEntry->GetColumnId();
+
+ sal_uInt32 nCount = pSelection->count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ if ( i > 0 ) // may we have to append more than one field
+ {
+ sal_uInt16 nColumnPosition;
+ aSelEntry = FindFirstFreeCol(nColumnPosition);
+ if ( !aSelEntry.is() )
+ {
+ AppendNewCol();
+ aSelEntry = FindFirstFreeCol(nColumnPosition);
+ }
+ ++nColumnPosition;
+ nColumnId = GetColumnId(nColumnPosition);
+ }
+
+ ::connectivity::OSQLParseNode* pChild = pSelection->getChild( i );
+ OSL_ENSURE(SQL_ISRULE(pChild,derived_column), "No derived column found!");
+ // get the column alias
+ OUString sColumnAlias = OSQLParseTreeIterator::getColumnAlias(pChild);
+ if ( !sColumnAlias.isEmpty() ) // we found an as clause
+ {
+ OUString aSelectionAlias = aSelEntry->GetFieldAlias();
+ aSelEntry->SetFieldAlias( sColumnAlias );
+ // append undo
+ appendUndoAction(aSelectionAlias,aSelEntry->GetFieldAlias(),BROW_COLUMNALIAS_ROW,_bListAction);
+ if ( m_bVisibleRow[BROW_COLUMNALIAS_ROW] )
+ RowModified(GetBrowseRow(BROW_COLUMNALIAS_ROW), nColumnId);
+ }
+
+ ::connectivity::OSQLParseNode* pColumnRef = pChild->getChild(0);
+ if (
+ pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
+ pColumnRef->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
+ )
+ pColumnRef = pColumnRef->getChild(1);
+
+ if ( SQL_ISRULE(pColumnRef,column_ref) ) // we found a valid column name or more column names
+ {
+ // look if we can find the corresponding table
+ bError = fillColumnRef( pColumnRef, xConnection, aSelEntry, _bListAction );
+
+ // we found a simple column so we must clear the function fields but only when the column name is '*'
+ // and the function is different to count
+ clearEntryFunctionField(_sFieldName,aSelEntry,_bListAction,nColumnId);
+ }
+ // do we have an aggregate function and only a function?
+ else if ( SQL_ISRULE(pColumnRef,general_set_fct) )
+ {
+ OUString sLocalizedFunctionName;
+ if ( GetFunctionName(pColumnRef->getChild(0)->getTokenID(),sLocalizedFunctionName) )
+ {
+ OUString sOldLocalizedFunctionName = aSelEntry->GetFunction();
+ aSelEntry->SetFunction(sLocalizedFunctionName);
+ sal_uInt32 nFunCount = pColumnRef->count() - 1;
+ sal_Int32 nFunctionType = FKT_AGGREGATE;
+ bool bQuote = false;
+ // may be there exists only one parameter which is a column, fill all information into our fields
+ if ( nFunCount == 4 && SQL_ISRULE(pColumnRef->getChild(3),column_ref) )
+ bError = fillColumnRef( pColumnRef->getChild(3), xConnection, aSelEntry, _bListAction );
+ else if ( nFunCount == 3 ) // we have a COUNT(*) here, so take the first table
+ bError = fillColumnRef( "*", std::u16string_view(), xMetaData, aSelEntry, _bListAction );
+ else
+ {
+ nFunctionType |= FKT_NUMERIC;
+ bQuote = true;
+ aSelEntry->SetDataType(DataType::DOUBLE);
+ aSelEntry->SetFieldType(TAB_NORMAL_FIELD);
+ }
+
+ // now parse the parameters
+ OUString sParameters;
+ for(sal_uInt32 function = 2; function < nFunCount; ++function) // we only want to parse the parameters of the function
+ pColumnRef->getChild(function)->parseNodeToStr( sParameters, xConnection, &rParser.getContext(), true, bQuote );
+
+ aSelEntry->SetFunctionType(nFunctionType);
+ aSelEntry->SetField(sParameters);
+ if ( aSelEntry->IsGroupBy() )
+ {
+ sOldLocalizedFunctionName = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1);
+ aSelEntry->SetGroupBy(false);
+ }
+
+ // append undo action
+ notifyFunctionFieldChanged(sOldLocalizedFunctionName,sLocalizedFunctionName,_bListAction, nColumnId);
+ }
+ else
+ OSL_FAIL("Unsupported function inserted!");
+
+ }
+ else
+ {
+ // so we first clear the function field
+ clearEntryFunctionField(_sFieldName,aSelEntry,_bListAction,nColumnId);
+ OUString sFunction;
+ pColumnRef->parseNodeToStr( sFunction,
+ xConnection,
+ &rController.getParser().getContext(),
+ true); // quote is to true because we need quoted elements inside the function
+
+ getDesignView()->fillFunctionInfo(pColumnRef,sFunction,aSelEntry);
+
+ if( SQL_ISRULEOR3(pColumnRef, position_exp, extract_exp, fold) ||
+ SQL_ISRULEOR3(pColumnRef, char_substring_fct, length_exp, char_value_fct) )
+ // a calculation has been found ( can be calc and function )
+ {
+ // now parse the whole statement
+ sal_uInt32 nFunCount = pColumnRef->count();
+ OUString sParameters;
+ for(sal_uInt32 function = 0; function < nFunCount; ++function)
+ pColumnRef->getChild(function)->parseNodeToStr( sParameters, xConnection, &rParser.getContext(), true );
+
+ sOldAlias = aSelEntry->GetAlias();
+ sal_Int32 nNewFunctionType = aSelEntry->GetFunctionType() | FKT_NUMERIC | FKT_OTHER;
+ aSelEntry->SetFunctionType(nNewFunctionType);
+ aSelEntry->SetField(sParameters);
+ }
+ else
+ {
+ aSelEntry->SetFieldAlias(sColumnAlias);
+ if ( SQL_ISRULE(pColumnRef,set_fct_spec) )
+ aSelEntry->SetFunctionType(/*FKT_NUMERIC | */FKT_OTHER);
+ else
+ aSelEntry->SetFunctionType(FKT_NUMERIC | FKT_OTHER);
+ }
+
+ aSelEntry->SetAlias(OUString());
+ notifyTableFieldChanged(sOldAlias,aSelEntry->GetAlias(),_bListAction, nColumnId);
+ }
+
+ if ( i > 0 && !InsertField(aSelEntry,BROWSER_INVALIDID,true,false).is() ) // may we have to append more than one field
+ { // the field could not be inserted
+ OUString sErrorMessage( DBA_RES( RID_STR_FIELD_DOESNT_EXIST ) );
+ sErrorMessage = sErrorMessage.replaceFirst("$name$",aSelEntry->GetField());
+ OSQLErrorBox aWarning(GetFrameWeld(), sErrorMessage);
+ aWarning.run();
+ bError = true;
+ }
+ }
+ }
+
+ return bError;
+}
+
+bool OSelectionBrowseBox::SaveModified()
+{
+ OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
+ OTableFieldDescRef pEntry;
+ sal_uInt16 nCurrentColumnPos = GetColumnPos(GetCurColumnId());
+ if(getFields().size() > o3tl::make_unsigned(nCurrentColumnPos - 1))
+ pEntry = getEntry(nCurrentColumnPos - 1);
+
+ bool bWasEmpty = pEntry.is() && pEntry->IsEmpty();
+ bool bError = false;
+ bool bListAction = false;
+
+ if (pEntry.is() && Controller().is() && Controller()->IsValueChangedFromSaved())
+ {
+ // for the Undo-action
+ OUString strOldCellContents,sNewValue;
+ sal_Int32 nRow = GetRealRow(GetCurRow());
+ bool bAppendRow = false;
+ switch (nRow)
+ {
+ case BROW_VIS_ROW:
+ {
+ bool bOldValue = m_pVisibleCell->GetBox().get_saved_state() != TRISTATE_FALSE;
+ strOldCellContents
+ = bOldValue ? std::u16string_view(u"1") : std::u16string_view(u"0");
+ sNewValue
+ = !bOldValue ? std::u16string_view(u"1") : std::u16string_view(u"0");
+ }
+ if((m_bOrderByUnRelated || pEntry->GetOrderDir() == ORDER_NONE) &&
+ (m_bGroupByUnRelated || !pEntry->IsGroupBy()))
+ {
+ pEntry->SetVisible(m_pVisibleCell->GetBox().get_active());
+ }
+ else
+ {
+ pEntry->SetVisible();
+ m_pVisibleCell->GetBox().set_active(true);
+ }
+ break;
+
+ case BROW_FIELD_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
+ OUString aFieldName(rComboBox.get_active_text());
+ try
+ {
+ if (aFieldName.isEmpty())
+ {
+ OTableFieldDescRef pNewEntry = new OTableFieldDesc();
+ pNewEntry->SetColumnId( pEntry->GetColumnId() );
+ std::replace(getFields().begin(),getFields().end(),pEntry,pNewEntry);
+ sal_uInt16 nCol = GetCurColumnId();
+ for (int i = 0; i < m_nVisibleCount; i++) // redraw column
+ RowModified(i,nCol);
+ }
+ else
+ {
+ strOldCellContents = pEntry->GetField();
+ bListAction = true;
+ if ( !m_bInUndoMode )
+ rController.GetUndoManager().EnterListAction(OUString(),OUString(),0,ViewShellId(-1));
+
+ sal_Int32 nPos = rComboBox.find_text(aFieldName);
+ OUString aAliasName = pEntry->GetAlias();
+ if ( nPos != -1 && aAliasName.isEmpty() && aFieldName.indexOf('.') >= 0 )
+ { // special case, we have a table field so we must cut the table name
+ OUString sTableAlias = aFieldName.getToken(0,'.');
+ pEntry->SetAlias(sTableAlias);
+ OUString sColumnName = aFieldName.copy(sTableAlias.getLength()+1);
+ const Reference<XConnection>& xConnection = rController.getConnection();
+ if ( !xConnection.is() )
+ return false;
+ bError = fillColumnRef( sColumnName, sTableAlias, xConnection->getMetaData(), pEntry, bListAction );
+ }
+ else
+ bError = true;
+
+ if ( bError )
+ bError = saveField(aFieldName,pEntry,bListAction);
+ }
+ }
+ catch(Exception&)
+ {
+ bError = true;
+ }
+ if ( bError )
+ {
+ sNewValue = aFieldName;
+ if ( !m_bInUndoMode )
+ static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().LeaveListAction();
+ bListAction = false;
+ }
+ else
+ sNewValue = pEntry->GetField();
+ rController.InvalidateFeature( ID_BROWSER_QUERY_EXECUTE );
+ }
+ break;
+
+ case BROW_TABLE_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pTableCell->get_widget();
+ OUString aAliasName = rComboBox.get_active_text();
+ strOldCellContents = pEntry->GetAlias();
+ if (rComboBox.get_active() != 0)
+ {
+ pEntry->SetAlias(aAliasName);
+ // we have to set the table name as well as the table window
+ OJoinTableView::OTableWindowMap& rTabWinList = getDesignView()->getTableView()->GetTabWinMap();
+ OJoinTableView::OTableWindowMap::const_iterator aIter = rTabWinList.find(aAliasName);
+ if(aIter != rTabWinList.end())
+ {
+ OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(aIter->second.get());
+ if (pEntryTab)
+ {
+ pEntry->SetTable(pEntryTab->GetTableName());
+ pEntry->SetTabWindow(pEntryTab);
+ }
+ }
+ }
+ else
+ {
+ pEntry->SetAlias(OUString());
+ pEntry->SetTable(OUString());
+ pEntry->SetTabWindow(nullptr);
+ }
+ sNewValue = pEntry->GetAlias();
+
+ } break;
+
+ case BROW_ORDER_ROW:
+ {
+ strOldCellContents = OUString::number(static_cast<sal_uInt16>(pEntry->GetOrderDir()));
+ weld::ComboBox& rComboBox = m_pOrderCell->get_widget();
+ sal_Int32 nIdx = rComboBox.get_active();
+ if (nIdx == -1)
+ nIdx = 0;
+ pEntry->SetOrderDir(EOrderDir(nIdx));
+ if(!m_bOrderByUnRelated)
+ {
+ pEntry->SetVisible();
+ m_pVisibleCell->GetBox().set_active(true);
+ RowModified(GetBrowseRow(BROW_VIS_ROW), GetCurColumnId());
+ }
+ sNewValue = OUString::number(static_cast<sal_uInt16>(pEntry->GetOrderDir()));
+ } break;
+
+ case BROW_COLUMNALIAS_ROW:
+ strOldCellContents = pEntry->GetFieldAlias();
+ pEntry->SetFieldAlias(m_pTextCell->get_widget().get_text());
+ sNewValue = pEntry->GetFieldAlias();
+ break;
+ case BROW_FUNCTION_ROW:
+ {
+ strOldCellContents = pEntry->GetFunction();
+ weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
+ sal_Int32 nPos = rComboBox.get_active();
+ // these functions are only available in CORE
+ OUString sFunctionName = rComboBox.get_text(nPos);
+ std::u16string_view sGroupFunctionName = m_aFunctionStrings.subView(m_aFunctionStrings.lastIndexOf(';')+1);
+ bool bGroupBy = false;
+ if ( sGroupFunctionName == sFunctionName ) // check if the function name is GROUP
+ {
+ bGroupBy = true;
+
+ if ( !m_bGroupByUnRelated && !pEntry->IsVisible() )
+ {
+ // we have to change the visible flag, so we must append also an undo action
+ pEntry->SetVisible();
+ m_pVisibleCell->GetBox().set_active(true);
+ appendUndoAction("0",u"1",BROW_VIS_ROW,bListAction);
+ RowModified(GetBrowseRow(BROW_VIS_ROW), GetCurColumnId());
+ }
+
+ pEntry->SetFunction(OUString());
+ pEntry->SetFunctionType(pEntry->GetFunctionType() & ~FKT_AGGREGATE );
+ }
+ else if ( nPos ) // we found an aggregate function
+ {
+ pEntry->SetFunctionType(pEntry->GetFunctionType() | FKT_AGGREGATE );
+ pEntry->SetFunction(sFunctionName);
+ }
+ else
+ {
+ sFunctionName.clear();
+ pEntry->SetFunction(OUString());
+ pEntry->SetFunctionType(pEntry->GetFunctionType() & ~FKT_AGGREGATE );
+ }
+
+ pEntry->SetGroupBy(bGroupBy);
+
+ sNewValue = sFunctionName;
+ }
+ break;
+ default:
+ {
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
+ if(!xConnection.is())
+ break;
+
+ sal_uInt16 nIdx = sal_uInt16(nRow - BROW_CRIT1_ROW);
+ OUString aText = comphelper::string::stripStart(m_pTextCell->get_widget().get_text(), ' ');
+
+ OUString aCrit;
+ if(!aText.isEmpty())
+ {
+ OUString aErrorMsg;
+ Reference<XPropertySet> xColumn;
+ std::unique_ptr<OSQLParseNode> pParseNode = getDesignView()->getPredicateTreeFromEntry(pEntry,aText,aErrorMsg,xColumn);
+
+ if (pParseNode)
+ {
+ pParseNode->parseNodeToPredicateStr(aCrit,
+ xConnection,
+ static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(),
+ xColumn,
+ pEntry->GetAlias(),
+ getDesignView()->getLocale(),
+ getDesignView()->getDecimalSeparator(),
+ &(static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext()));
+ }
+ else
+ {
+ if(xColumn.is())
+ {
+ sal_Int32 nType = 0;
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ switch(nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ if(!aText.startsWith("'") || !aText.endsWith("'"))
+ {
+ aText = aText.replaceAll("'", "''");
+ aText = "'" + aText + "'";
+ }
+ break;
+ default:
+ ;
+ }
+ ::connectivity::OSQLParser& rParser = static_cast<OQueryController&>(getDesignView()->getController()).getParser();
+ pParseNode = rParser.predicateTree(aErrorMsg,
+ aText,
+ static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(),
+ xColumn);
+ if (pParseNode)
+ {
+ pParseNode->parseNodeToPredicateStr(aCrit,
+ xConnection,
+ static_cast<OQueryController&>(getDesignView()->getController()).getNumberFormatter(),
+ xColumn,
+ pEntry->GetAlias(),
+ getDesignView()->getLocale(),
+ getDesignView()->getDecimalSeparator(),
+ &(static_cast<OQueryController&>(getDesignView()->getController()).getParser().getContext()));
+ }
+ else
+ {
+ if ( !m_bDisableErrorBox )
+ {
+ OSQLWarningBox aWarning(GetFrameWeld(), aErrorMsg);
+ aWarning.run();
+ }
+ bError = true;
+ }
+ }
+ else
+ {
+ if ( !m_bDisableErrorBox )
+ {
+ OSQLWarningBox aWarning(GetFrameWeld(), aErrorMsg);
+ aWarning.run();
+ }
+ bError = true;
+ }
+ }
+ }
+ strOldCellContents = pEntry->GetCriteria(nIdx);
+ pEntry->SetCriteria(nIdx, aCrit);
+ sNewValue = pEntry->GetCriteria(nIdx);
+ if(!aCrit.isEmpty() && nRow >= (GetRowCount()-1))
+ bAppendRow = true;
+ }
+ }
+ if( !bError && Controller().is() )
+ Controller()->SaveValue();
+
+ RowModified(GetCurRow(), GetCurColumnId());
+
+ if ( bAppendRow )
+ {
+ RowInserted( GetRowCount()-1 );
+ m_bVisibleRow.push_back(true);
+ ++m_nVisibleCount;
+ }
+
+ if(!bError)
+ {
+ // and now the undo-action for the total
+ appendUndoAction(strOldCellContents,sNewValue,nRow);
+
+ }
+ }
+
+ // did I store data in a FieldDescription which was empty before and which is not empty anymore after the changes?
+ if ( pEntry.is() && bWasEmpty && !pEntry->IsEmpty() && !bError )
+ {
+ // Default to visible
+ pEntry->SetVisible();
+ appendUndoAction("0",u"1",BROW_VIS_ROW,bListAction);
+ RowModified(BROW_VIS_ROW, GetCurColumnId());
+
+ // if required add empty columns
+ sal_uInt16 nDummy;
+ CheckFreeColumns(nDummy);
+ }
+
+ if ( bListAction && !m_bInUndoMode )
+ static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().LeaveListAction();
+
+ return pEntry != nullptr && !bError;
+}
+
+bool OSelectionBrowseBox::SeekRow(sal_Int32 nRow)
+{
+ m_nSeekRow = nRow;
+ return nRow < m_nVisibleCount;
+}
+
+void OSelectionBrowseBox::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId) const
+{
+ rDev.SetClipRegion(vcl::Region(rRect));
+
+ OTableFieldDescRef pEntry;
+ sal_uInt16 nPos = GetColumnPos(nColumnId);
+ if(getFields().size() > o3tl::make_unsigned(nPos - 1))
+ pEntry = getFields()[nPos - 1];
+
+ if (!pEntry.is())
+ return;
+
+ sal_Int32 nRow = GetRealRow(m_nSeekRow);
+ if (nRow == BROW_VIS_ROW)
+ PaintTristate(rRect, pEntry->IsVisible() ? TRISTATE_TRUE : TRISTATE_FALSE);
+ else
+ rDev.DrawText(rRect, GetCellText(nRow, nColumnId),DrawTextFlags::VCenter);
+
+ rDev.SetClipRegion( );
+}
+
+void OSelectionBrowseBox::PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const
+{
+ tools::Rectangle aRect(rRect);
+ aRect.TopLeft().AdjustY( -2 );
+ OUString aLabel(DBA_RES(STR_QUERY_HANDLETEXT));
+
+ // from BROW_CRIT2_ROW onwards all rows are shown "or"
+ sal_Int32 nToken = (m_nSeekRow >= GetBrowseRow(BROW_CRIT2_ROW))
+ ? BROW_CRIT2_ROW : GetRealRow(m_nSeekRow);
+ rDev.DrawText(aRect, aLabel.getToken(nToken, ';'),DrawTextFlags::VCenter);
+}
+
+void OSelectionBrowseBox::RemoveColumn(sal_uInt16 _nColumnId)
+{
+ OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
+
+ sal_uInt16 nPos = GetColumnPos(_nColumnId);
+ // the control should always have exactly one more column: the HandleColumn
+ OSL_ENSURE((nPos == 0) || (nPos <= getFields().size()), "OSelectionBrowseBox::RemoveColumn : invalid parameter nColId");
+ // ColId is synonymous to Position, and the condition should be valid
+
+ sal_uInt16 nCurCol = GetCurColumnId();
+ sal_Int32 nCurrentRow = GetCurRow();
+
+ DeactivateCell();
+
+ getFields().erase( getFields().begin() + (nPos - 1) );
+ OTableFieldDescRef pEntry = new OTableFieldDesc();
+ pEntry->SetColumnId(_nColumnId);
+ getFields().push_back(pEntry);
+
+ EditBrowseBox::RemoveColumn( _nColumnId );
+ InsertDataColumn( _nColumnId , OUString(), DEFAULT_SIZE );
+
+ // redraw
+ tools::Rectangle aInvalidRect = GetInvalidRect( _nColumnId );
+ Invalidate( aInvalidRect );
+
+ ActivateCell( nCurrentRow, nCurCol );
+
+ rController.setModified( true );
+
+ invalidateUndoRedo();
+}
+
+void OSelectionBrowseBox::RemoveField(sal_uInt16 nColumnId )
+{
+ OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
+
+ sal_uInt16 nPos = GetColumnPos(nColumnId);
+ OSL_ENSURE(getFields().size() > o3tl::make_unsigned(nPos-1),"ID is to great!");
+
+ OTableFieldDescRef pDesc = getEntry(static_cast<sal_uInt32>(nPos - 1)) ;
+ pDesc->SetColWidth( static_cast<sal_uInt16>(GetColumnWidth(nColumnId)) ); // was not stored this before
+
+ // trigger UndoAction
+ if ( !m_bInUndoMode )
+ {
+ std::unique_ptr<OTabFieldDelUndoAct> pUndoAction(new OTabFieldDelUndoAct( this ));
+ pUndoAction->SetTabFieldDescr(pDesc);
+ pUndoAction->SetColumnPosition(nPos);
+ rController.addUndoActionAndInvalidate( std::move(pUndoAction) );
+ }
+
+ RemoveColumn(nColumnId);
+
+ invalidateUndoRedo();
+}
+
+void OSelectionBrowseBox::adjustSelectionMode( bool _bClickedOntoHeader, bool _bClickedOntoHandleCol )
+{
+ // if a Header has been selected it should be shown otherwise not
+ if ( _bClickedOntoHeader )
+ {
+ if (0 == GetSelectColumnCount() )
+ // I am in the correct mode if a selected column exists
+ if ( BrowserMode::HIDESELECT == ( m_nMode & BrowserMode::HIDESELECT ) )
+ {
+ m_nMode &= ~BrowserMode::HIDESELECT;
+ m_nMode |= BrowserMode::MULTISELECTION;
+ SetMode( m_nMode );
+ }
+ }
+ else if ( BrowserMode::HIDESELECT != ( m_nMode & BrowserMode::HIDESELECT ) )
+ {
+ if ( GetSelectColumnCount() != 0 )
+ SetNoSelection();
+
+ if ( _bClickedOntoHandleCol )
+ {
+ m_nMode |= BrowserMode::HIDESELECT;
+ m_nMode &= ~BrowserMode::MULTISELECTION;
+ SetMode( m_nMode );
+ }
+ }
+}
+
+void OSelectionBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt)
+{
+ if( rEvt.IsLeft() )
+ {
+ bool bOnHandle = HANDLE_ID == rEvt.GetColumnId();
+ bool bOnHeader = ( rEvt.GetRow() < 0 ) && !bOnHandle;
+ adjustSelectionMode( bOnHeader, bOnHandle );
+ }
+ EditBrowseBox::MouseButtonDown(rEvt);
+}
+
+void OSelectionBrowseBox::MouseButtonUp(const BrowserMouseEvent& rEvt)
+{
+ EditBrowseBox::MouseButtonUp( rEvt );
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( ID_BROWSER_QUERY_EXECUTE );
+}
+
+void OSelectionBrowseBox::KeyInput( const KeyEvent& rEvt )
+{
+ if (IsColumnSelected(GetCurColumnId()))
+ {
+ if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows
+ !rEvt.GetKeyCode().IsShift() &&
+ !rEvt.GetKeyCode().IsMod1())
+ {
+ RemoveField(GetCurColumnId());
+ return;
+ }
+ }
+ EditBrowseBox::KeyInput(rEvt);
+}
+
+sal_Int8 OSelectionBrowseBox::AcceptDrop( const BrowserAcceptDropEvent& rEvt )
+{
+ sal_Int8 nDropAction = DND_ACTION_NONE;
+ if ( rEvt.GetRow() >= -1 )
+ {
+ if ( IsEditing() )
+ {
+ // allow the asterisk again
+ m_bDisableErrorBox = true;
+ SaveModified();
+ m_bDisableErrorBox = false;
+ DeactivateCell();
+ }
+ // check if the format is already supported, if not deactivate the current cell and try again
+ if ( OJoinExchObj::isFormatAvailable(GetDataFlavors()) )
+ nDropAction = DND_ACTION_LINK;
+ }
+
+ return nDropAction;
+}
+
+sal_Int8 OSelectionBrowseBox::ExecuteDrop( const BrowserExecuteDropEvent& _rEvt )
+{
+
+ TransferableDataHelper aDropped(_rEvt.maDropEvent.Transferable);
+ if (!OJoinExchObj::isFormatAvailable(aDropped.GetDataFlavorExVector()))
+ {
+ OSL_FAIL("OSelectionBrowseBox::ExecuteDrop: this should never have passed AcceptDrop!");
+ return DND_ACTION_NONE;
+ }
+
+ // insert the field at the selected position
+ OJoinExchangeData jxdSource = OJoinExchObj::GetSourceDescription(_rEvt.maDropEvent.Transferable);
+ InsertField(jxdSource);
+
+ return DND_ACTION_LINK;
+}
+
+OTableFieldDescRef const & OSelectionBrowseBox::AppendNewCol( sal_uInt16 nCnt)
+{
+ // one or more can be created, but the first one will is not returned
+ sal_uInt32 nCount = getFields().size();
+ for (sal_uInt16 i=0 ; i<nCnt ; i++)
+ {
+ OTableFieldDescRef pEmptyEntry = new OTableFieldDesc();
+ getFields().push_back(pEmptyEntry);
+ sal_uInt16 nColumnId = sal::static_int_cast< sal_uInt16 >(getFields().size());
+ pEmptyEntry->SetColumnId( nColumnId );
+
+ InsertDataColumn( nColumnId , OUString(), DEFAULT_SIZE );
+ }
+
+ return getFields()[nCount];
+}
+
+void OSelectionBrowseBox::DeleteFields(const OUString& rAliasName)
+{
+ if (getFields().empty())
+ return;
+
+ sal_uInt16 nColId = GetCurColumnId();
+ sal_uInt32 nRow = GetCurRow();
+
+ bool bWasEditing = IsEditing();
+ if (bWasEditing)
+ DeactivateCell();
+
+ auto aIter = std::find_if(getFields().rbegin(), getFields().rend(),
+ [&rAliasName](const OTableFieldDescRef pEntry) { return pEntry->GetAlias() == rAliasName; });
+ if (aIter != getFields().rend())
+ {
+ sal_uInt16 nPos = sal::static_int_cast<sal_uInt16>(std::distance(aIter, getFields().rend()));
+ RemoveField( GetColumnId( nPos ) );
+ }
+
+ if (bWasEditing)
+ ActivateCell(nRow , nColId);
+}
+
+void OSelectionBrowseBox::SetColWidth(sal_uInt16 nColId, tools::Long nNewWidth)
+{
+ bool bWasEditing = IsEditing();
+ if (bWasEditing)
+ DeactivateCell();
+
+ // create the BaseClass
+ SetColumnWidth(nColId, nNewWidth);
+
+ // tell it the FieldDescription
+ OTableFieldDescRef pEntry = getEntry(GetColumnPos(nColId) - 1);
+ if (pEntry.is())
+ pEntry->SetColWidth(sal_uInt16(GetColumnWidth(nColId)));
+
+ if (bWasEditing)
+ ActivateCell(GetCurRow(), GetCurColumnId());
+}
+
+tools::Rectangle OSelectionBrowseBox::GetInvalidRect( sal_uInt16 nColId )
+{
+ // The rectangle is the full output area of the window
+ tools::Rectangle aInvalidRect( Point(0,0), GetOutputSizePixel() );
+
+ // now update the left side
+ tools::Rectangle aFieldRect(GetCellRect( 0, nColId )); // used instead of GetFieldRectPixel
+ aInvalidRect.SetLeft( aFieldRect.Left() );
+
+ return aInvalidRect;
+}
+
+void OSelectionBrowseBox::InsertColumn(const OTableFieldDescRef& pEntry, sal_uInt16& _nColumnPosition)
+{
+ // the control should have exactly one more column: the HandleColumn
+ OSL_ENSURE(_nColumnPosition == BROWSER_INVALIDID || (_nColumnPosition <= static_cast<tools::Long>(getFields().size())), "OSelectionBrowseBox::InsertColumn : invalid parameter nColId.");
+ // -1 means at the end. Count means at the end, others denotes a correct position
+
+ sal_uInt16 nCurCol = GetCurColumnId();
+ sal_Int32 nCurrentRow = GetCurRow();
+
+ DeactivateCell();
+
+ // remember the column id of the current position
+ sal_uInt16 nColumnId = GetColumnId(_nColumnPosition);
+ // put at the end of the list if too small or too big,
+ if ((_nColumnPosition == BROWSER_INVALIDID) || (_nColumnPosition >= getFields().size())) // append the field
+ {
+ if (FindFirstFreeCol(_nColumnPosition) == nullptr) // no more free columns
+ {
+ AppendNewCol();
+ _nColumnPosition = sal::static_int_cast< sal_uInt16 >(
+ getFields().size());
+ }
+ else
+ ++_nColumnPosition; // within the list
+ nColumnId = GetColumnId(_nColumnPosition);
+ pEntry->SetColumnId( nColumnId );
+ getFields()[ _nColumnPosition - 1] = pEntry;
+ }
+
+ // check if the column ids are identical, if not we have to move
+ if ( pEntry->GetColumnId() != nColumnId )
+ {
+ sal_uInt16 nOldPosition = GetColumnPos(pEntry->GetColumnId());
+ OSL_ENSURE( nOldPosition != 0,"Old position was 0. Not possible!");
+ SetColumnPos(pEntry->GetColumnId(),_nColumnPosition);
+ // we have to delete an empty field for the fields list, because the columns must have equal length
+ if ( nOldPosition > 0 && nOldPosition <= getFields().size() )
+ getFields()[nOldPosition - 1] = pEntry;
+
+ ColumnMoved(pEntry->GetColumnId(),false);
+ }
+
+ if ( pEntry->GetFunctionType() & FKT_AGGREGATE )
+ {
+ OUString sFunctionName = pEntry->GetFunction();
+ if ( GetFunctionName(sal_uInt32(-1),sFunctionName) )
+ pEntry->SetFunction(sFunctionName);
+ }
+
+ nColumnId = pEntry->GetColumnId();
+
+ SetColWidth(nColumnId,getDesignView()->getColWidth(GetColumnPos(nColumnId)-1));
+ // redraw
+ tools::Rectangle aInvalidRect = GetInvalidRect( nColumnId );
+ Invalidate( aInvalidRect );
+
+ ActivateCell( nCurrentRow, nCurCol );
+ static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
+
+ invalidateUndoRedo();
+}
+
+OTableFieldDescRef OSelectionBrowseBox::InsertField(const OJoinExchangeData& jxdSource)
+{
+ OQueryTableWindow* pSourceWin = static_cast<OQueryTableWindow*>(jxdSource.pListBox->GetTabWin());
+ if (!pSourceWin)
+ return nullptr;
+
+ // name and position of the selected field
+ weld::TreeView& rTreeView = jxdSource.pListBox->get_widget();
+ OUString aFieldName = rTreeView.get_text(jxdSource.nEntry);
+ sal_uInt32 nFieldIndex = jxdSource.nEntry;
+ OTableFieldInfo* pInf = weld::fromId<OTableFieldInfo*>(rTreeView.get_id(jxdSource.nEntry));
+
+ // construct DragInfo, such that I use the other InsertField
+ OTableFieldDescRef aInfo = new OTableFieldDesc(pSourceWin->GetTableName(),aFieldName);
+ aInfo->SetTabWindow(pSourceWin);
+ aInfo->SetFieldIndex(nFieldIndex);
+ aInfo->SetFieldType(pInf->GetKeyType());
+ aInfo->SetAlias(pSourceWin->GetAliasName());
+
+ aInfo->SetDataType(pInf->GetDataType());
+ aInfo->SetVisible();
+
+ return InsertField(aInfo);
+}
+
+OTableFieldDescRef OSelectionBrowseBox::InsertField(const OTableFieldDescRef& _rInfo, sal_uInt16 _nColumnPosition, bool bVis, bool bActivate)
+{
+
+ if(m_nMaxColumns && m_nMaxColumns <= FieldsCount())
+ return nullptr;
+ if (bActivate)
+ SaveModified();
+
+ // new column description
+ OTableFieldDescRef pEntry = _rInfo;
+ pEntry->SetVisible(bVis);
+
+ // insert column
+ InsertColumn( pEntry, _nColumnPosition );
+
+ if ( !m_bInUndoMode )
+ {
+ // trigger UndoAction
+ std::unique_ptr<OTabFieldCreateUndoAct> pUndoAction(new OTabFieldCreateUndoAct( this ));
+ pUndoAction->SetTabFieldDescr( pEntry );
+ pUndoAction->SetColumnPosition(_nColumnPosition);
+ getDesignView()->getController().addUndoActionAndInvalidate( std::move(pUndoAction) );
+ }
+
+ return pEntry;
+}
+
+sal_uInt16 OSelectionBrowseBox::FieldsCount()
+{
+ sal_uInt16 nCount = 0;
+ for (auto const& field : getFields())
+ {
+ if (field.is() && !field->IsEmpty())
+ ++nCount;
+ }
+
+ return nCount;
+}
+
+OTableFieldDescRef OSelectionBrowseBox::FindFirstFreeCol(sal_uInt16& _rColumnPosition )
+{
+
+ _rColumnPosition = BROWSER_INVALIDID;
+
+ for (auto const& field : getFields())
+ {
+ ++_rColumnPosition;
+ OTableFieldDescRef pEntry = field;
+ if ( pEntry.is() && pEntry->IsEmpty() )
+ return pEntry;
+ }
+
+ return nullptr;
+}
+
+void OSelectionBrowseBox::CheckFreeColumns(sal_uInt16& _rColumnPosition)
+{
+ if (FindFirstFreeCol(_rColumnPosition) == nullptr)
+ {
+ // it is full, so append a pack of columns
+ AppendNewCol(DEFAULT_QUERY_COLS);
+ OSL_VERIFY(FindFirstFreeCol(_rColumnPosition).is());
+ }
+}
+
+void OSelectionBrowseBox::AddGroupBy( const OTableFieldDescRef& rInfo )
+{
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
+ if(!xConnection.is())
+ return;
+ OSL_ENSURE(!rInfo->IsEmpty(),"AddGroupBy:: OTableFieldDescRef should not be empty!");
+ OTableFieldDescRef pEntry;
+ const Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ const ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+ //sal_Bool bAppend = sal_False;
+
+ bool bAllFieldsSearched = true;
+ for (auto const& field : getFields())
+ {
+ pEntry = field;
+ OSL_ENSURE(pEntry.is(),"OTableFieldDescRef was null!");
+
+ const OUString aField = pEntry->GetField();
+ const OUString aAlias = pEntry->GetAlias();
+
+ if (bCase(aField,rInfo->GetField()) &&
+ bCase(aAlias,rInfo->GetAlias()) &&
+ pEntry->GetFunctionType() == rInfo->GetFunctionType() &&
+ pEntry->GetFunction() == rInfo->GetFunction())
+ {
+ if ( pEntry->isNumericOrAggregateFunction() && rInfo->IsGroupBy() )
+ {
+ pEntry->SetGroupBy(false);
+ // we do want to consider that bAllFieldsSearched still true here
+ // bAllFieldsSearched = false;
+ break;
+ }
+ else
+ {
+ if ( !pEntry->IsGroupBy() && !pEntry->HasCriteria() ) // here we have a where condition which is no having clause
+ {
+ pEntry->SetGroupBy(rInfo->IsGroupBy());
+ if(!m_bGroupByUnRelated && pEntry->IsGroupBy())
+ pEntry->SetVisible();
+ bAllFieldsSearched = false;
+ break;
+ }
+ }
+
+ }
+ }
+
+ if (bAllFieldsSearched)
+ {
+ OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false );
+ if ( pTmp->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) // the GroupBy is inherited from rInfo
+ pTmp->SetGroupBy(false);
+ }
+}
+
+void OSelectionBrowseBox::DuplicateConditionLevel( const sal_uInt16 nLevel)
+{
+ const sal_uInt16 nNewLevel = nLevel +1;
+ for (auto const& field : getFields())
+ {
+ const OTableFieldDescRef& pEntry = field;
+ OUString sValue = pEntry->GetCriteria(nLevel);
+ if ( !sValue.isEmpty() )
+ {
+ pEntry->SetCriteria( nNewLevel, sValue);
+ if ( nNewLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1) )
+ {
+ RowInserted( GetRowCount()-1 );
+ m_bVisibleRow.push_back(true);
+ ++m_nVisibleCount;
+ }
+ m_bVisibleRow[BROW_CRIT1_ROW + nNewLevel] = true;
+ }
+ }
+}
+
+void OSelectionBrowseBox::AddCondition( const OTableFieldDescRef& rInfo, const OUString& rValue, const sal_uInt16 nLevel,bool _bAddOrOnOneLine )
+{
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
+ if(!xConnection.is())
+ return;
+ OSL_ENSURE(rInfo.is() && !rInfo->IsEmpty(),"AddCondition:: OTableFieldDescRef should not be Empty!");
+
+ OTableFieldDescRef pLastEntry;
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+
+ bool bAllFieldsSearched = true;
+ for (auto const& field : getFields())
+ {
+ const OTableFieldDescRef& pEntry = field;
+ const OUString aField = pEntry->GetField();
+ const OUString aAlias = pEntry->GetAlias();
+
+ if (bCase(aField,rInfo->GetField()) &&
+ bCase(aAlias,rInfo->GetAlias()) &&
+ pEntry->GetFunctionType() == rInfo->GetFunctionType() &&
+ pEntry->GetFunction() == rInfo->GetFunction() &&
+ pEntry->IsGroupBy() == rInfo->IsGroupBy() )
+ {
+ if ( pEntry->isNumericOrAggregateFunction() && rInfo->IsGroupBy() )
+ pEntry->SetGroupBy(false);
+ else
+ {
+ if(!m_bGroupByUnRelated && pEntry->IsGroupBy())
+ pEntry->SetVisible();
+ }
+ if (pEntry->GetCriteria(nLevel).isEmpty() )
+ {
+ pEntry->SetCriteria( nLevel, rValue);
+ if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1))
+ {
+ RowInserted( GetRowCount()-1 );
+ m_bVisibleRow.push_back(true);
+ ++m_nVisibleCount;
+ }
+ m_bVisibleRow[BROW_CRIT1_ROW + nLevel] = true;
+ bAllFieldsSearched = false;
+ break;
+ }
+ if ( _bAddOrOnOneLine )
+ {
+ pLastEntry = pEntry;
+ }
+ }
+ }
+ if ( pLastEntry.is() )
+ {
+ OUString sCriteria = rValue;
+ OUString sOldCriteria = pLastEntry->GetCriteria( nLevel );
+ if ( !sOldCriteria.isEmpty() )
+ {
+ sCriteria = "( " + sOldCriteria + " OR " + rValue + " )";
+ }
+ pLastEntry->SetCriteria( nLevel, sCriteria);
+ if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1))
+ {
+ RowInserted( GetRowCount()-1 );
+ m_bVisibleRow.push_back(true);
+ ++m_nVisibleCount;
+ }
+ m_bVisibleRow[BROW_CRIT1_ROW + nLevel] = true;
+ }
+ else if (bAllFieldsSearched)
+ {
+ OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false );
+ if ( pTmp->isNumericOrAggregateFunction() && rInfo->IsGroupBy() ) // the GroupBy was inherited from rInfo
+ pTmp->SetGroupBy(false);
+ if ( pTmp.is() )
+ {
+ pTmp->SetCriteria( nLevel, rValue);
+ if(nLevel == (m_nVisibleCount-BROW_CRIT1_ROW-1))
+ {
+ RowInserted( GetRowCount()-1 );
+ m_bVisibleRow.push_back(true);
+ ++m_nVisibleCount;
+ }
+ }
+ }
+}
+
+void OSelectionBrowseBox::AddOrder( const OTableFieldDescRef& rInfo, const EOrderDir eDir, sal_uInt32 _nCurrentPos)
+{
+ if (_nCurrentPos == 0)
+ m_nLastSortColumn = SORT_COLUMN_NONE;
+
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
+ if(!xConnection.is())
+ return;
+ OSL_ENSURE(!rInfo->IsEmpty(),"AddOrder:: OTableFieldDescRef should not be Empty!");
+ OTableFieldDescRef pEntry;
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+
+ bool bAppend = false;
+ sal_uInt32 nPos = 0;
+ bool bAllFieldsSearched = true;
+ for (auto const& field : getFields())
+ {
+ pEntry = field;
+ OUString aField = pEntry->GetField();
+ OUString aAlias = pEntry->GetAlias();
+
+ if (bCase(aField,rInfo->GetField()) &&
+ bCase(aAlias,rInfo->GetAlias()))
+ {
+ bAppend = (m_nLastSortColumn != SORT_COLUMN_NONE) && (nPos <= m_nLastSortColumn);
+ if ( bAppend )
+ {
+ // we do want to consider that bAllFieldsSearched still true here
+ // bAllFieldsSearched = false;
+ break;
+ }
+ else
+ {
+ if ( !m_bOrderByUnRelated )
+ pEntry->SetVisible();
+ pEntry->SetOrderDir( eDir );
+ m_nLastSortColumn = nPos;
+ }
+ bAllFieldsSearched = false;
+ break;
+ }
+ ++nPos;
+ }
+
+ if (bAllFieldsSearched)
+ {
+ OTableFieldDescRef pTmp = InsertField(rInfo, BROWSER_INVALIDID, false, false );
+ if(pTmp.is())
+ {
+ m_nLastSortColumn = pTmp->GetColumnId() - 1;
+ if ( !m_bOrderByUnRelated && !bAppend )
+ pTmp->SetVisible();
+ pTmp->SetOrderDir( eDir );
+ }
+ }
+}
+
+bool OSelectionBrowseBox::Save()
+{
+ bool bRet = true;
+ if (IsModified())
+ bRet = SaveModified();
+ return bRet;
+}
+
+void OSelectionBrowseBox::CellModified()
+{
+ sal_Int32 nRow = GetRealRow(GetCurRow());
+ switch (nRow)
+ {
+ case BROW_VIS_ROW:
+ {
+ OTableFieldDescRef pEntry = getEntry(GetColumnPos(GetCurColumnId()) - 1);
+
+ weld::ComboBox& rComboBox = m_pOrderCell->get_widget();
+ sal_Int32 nIdx = rComboBox.get_active();
+ if(!m_bOrderByUnRelated && nIdx > 0 &&
+ nIdx != -1 &&
+ !pEntry->IsEmpty() &&
+ pEntry->GetOrderDir() != ORDER_NONE)
+ {
+ m_pVisibleCell->GetBox().set_active(true);
+ pEntry->SetVisible();
+ }
+ else
+ pEntry->SetVisible(m_pVisibleCell->GetBox().get_active());
+ }
+ break;
+ }
+ static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
+}
+
+void OSelectionBrowseBox::Fill()
+{
+ OSL_ENSURE(ColCount() >= 1, "OSelectionBrowseBox::Fill : please call only after inserting the handle column !");
+
+ sal_uInt16 nColCount = ColCount() - 1;
+ if (nColCount < DEFAULT_QUERY_COLS)
+ AppendNewCol(DEFAULT_QUERY_COLS - nColCount);
+}
+
+Size OSelectionBrowseBox::CalcOptimalSize( const Size& _rAvailable )
+{
+ Size aReturn( _rAvailable.Width(), GetTitleHeight() );
+
+ aReturn.AdjustHeight(( m_nVisibleCount ? m_nVisibleCount : 15 ) * GetDataRowHeight() );
+ aReturn.AdjustHeight(40 ); // just some space
+
+ return aReturn;
+}
+
+void OSelectionBrowseBox::Command(const CommandEvent& rEvt)
+{
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ Point aMenuPos( rEvt.GetMousePosPixel() );
+
+ if (!rEvt.IsMouseEvent())
+ {
+ if ( 1 == GetSelectColumnCount() )
+ {
+ sal_uInt16 nSelId = GetColumnId(
+ sal::static_int_cast< sal_uInt16 >(
+ FirstSelectedColumn() ) );
+ ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) );
+
+ aMenuPos = aColRect.TopCenter();
+ }
+ else
+ {
+ EditBrowseBox::Command(rEvt);
+ return;
+ }
+ }
+
+ sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel( aMenuPos.X() ));
+ sal_Int32 nRow = GetRowAtYPosPixel( aMenuPos.Y() );
+
+ if (nRow < 0 && nColId > HANDLE_ID )
+ {
+ if ( !IsColumnSelected( nColId ) )
+ {
+ adjustSelectionMode( true /* clicked onto a header */ , false /* not onto the handle col */ );
+ SelectColumnId( nColId );
+ }
+
+ if (!static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
+ {
+ ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
+ if (sIdent == "delete")
+ RemoveField(nColId);
+ else if (sIdent == "width")
+ adjustBrowseBoxColumnWidth( this, nColId );
+ }
+ }
+ else if(nRow >= 0 && nColId <= HANDLE_ID)
+ {
+ if (!static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
+ {
+ ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/queryfuncmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ xContextMenu->set_active("functions", m_bVisibleRow[BROW_FUNCTION_ROW]);
+ xContextMenu->set_active("tablename", m_bVisibleRow[BROW_TABLE_ROW]);
+ xContextMenu->set_active("alias", m_bVisibleRow[BROW_COLUMNALIAS_ROW]);
+ xContextMenu->set_active("distinct", static_cast<OQueryController&>(getDesignView()->getController()).isDistinct());
+
+ OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
+ if (sIdent == "functions")
+ {
+ SetRowVisible(BROW_FUNCTION_ROW, !IsRowVisible(BROW_FUNCTION_ROW));
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_FUNCTIONS );
+ }
+ else if (sIdent == "tablename")
+ {
+ SetRowVisible(BROW_TABLE_ROW, !IsRowVisible(BROW_TABLE_ROW));
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_TABLES );
+ }
+ else if (sIdent == "alias")
+ {
+ SetRowVisible(BROW_COLUMNALIAS_ROW, !IsRowVisible(BROW_COLUMNALIAS_ROW));
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_ALIASES );
+ }
+ else if (sIdent == "distinct")
+ {
+ static_cast<OQueryController&>(getDesignView()->getController()).setDistinct(!static_cast<OQueryController&>(getDesignView()->getController()).isDistinct());
+ static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature( SID_QUERY_DISTINCT_VALUES );
+ }
+
+ static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
+ }
+ }
+ else
+ {
+ EditBrowseBox::Command(rEvt);
+ return;
+ }
+
+ [[fallthrough]];
+ }
+ default:
+ EditBrowseBox::Command(rEvt);
+ }
+}
+
+bool OSelectionBrowseBox::IsRowVisible(sal_uInt16 _nWhich) const
+{
+ OSL_ENSURE(_nWhich<(m_bVisibleRow.size()), "OSelectionBrowseBox::IsRowVisible : invalid parameter !");
+ return m_bVisibleRow[_nWhich];
+}
+
+void OSelectionBrowseBox::SetRowVisible(sal_uInt16 _nWhich, bool _bVis)
+{
+ OSL_ENSURE(_nWhich<m_bVisibleRow.size(), "OSelectionBrowseBox::SetRowVisible : invalid parameter !");
+
+ bool bWasEditing = IsEditing();
+ if (bWasEditing)
+ DeactivateCell();
+
+ // do this before removing or inserting rows, as this triggers ActivateCell-calls, which rely on m_bVisibleRow
+ m_bVisibleRow[_nWhich] = !m_bVisibleRow[_nWhich];
+
+ tools::Long nId = GetBrowseRow(_nWhich);
+ if (_bVis)
+ {
+ RowInserted(nId);
+ ++m_nVisibleCount;
+ }
+ else
+ {
+ RowRemoved(nId);
+ --m_nVisibleCount;
+ }
+
+ if (bWasEditing)
+ ActivateCell();
+}
+
+sal_Int32 OSelectionBrowseBox::GetBrowseRow(sal_Int32 nRowId) const
+{
+ sal_Int32 nCount(0);
+ for(sal_Int32 i = 0 ; i < nRowId ; ++i)
+ {
+ if ( m_bVisibleRow[i] )
+ ++nCount;
+ }
+ return nCount;
+}
+
+sal_Int32 OSelectionBrowseBox::GetRealRow(sal_Int32 nRowId) const
+{
+ sal_Int32 nErg=0,i;
+ const sal_Int32 nCount = m_bVisibleRow.size();
+ for(i=0;i < nCount; ++i)
+ {
+ if(m_bVisibleRow[i] && nErg++ == nRowId)
+ break;
+ }
+ OSL_ENSURE(nErg <= tools::Long(m_bVisibleRow.size()),"nErg cannot be greater than BROW_ROW_CNT!");
+ return i;
+}
+
+const tools::Long nVisibleRowMask[] =
+ {
+ 0x0001,
+ 0x0002,
+ 0x0004,
+ 0x0008,
+ 0x0010,
+ 0x0020,
+ 0x0040,
+ 0x0080,
+ 0x0100,
+ 0x0200,
+ 0x0400,
+ 0x0800
+ };
+sal_Int32 OSelectionBrowseBox::GetNoneVisibleRows() const
+{
+ sal_Int32 nErg(0);
+ // only the first 11 rows are interesting
+ sal_Int32 const nSize = SAL_N_ELEMENTS(nVisibleRowMask);
+ for(sal_Int32 i=0;i<nSize;i++)
+ {
+ if(!m_bVisibleRow[i])
+ nErg |= nVisibleRowMask[i];
+ }
+ return nErg;
+}
+
+void OSelectionBrowseBox::SetNoneVisibleRow(sal_Int32 nRows)
+{
+ // only the first 11 rows are interesting
+ sal_Int32 const nSize = SAL_N_ELEMENTS(nVisibleRowMask);
+ for(sal_Int32 i=0;i< nSize;i++)
+ m_bVisibleRow[i] = !(nRows & nVisibleRowMask[i]);
+}
+
+OUString OSelectionBrowseBox::GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const
+{
+
+ sal_uInt16 nPos = GetColumnPos(nColId);
+ if ( nPos == 0 || nPos == BROWSER_INVALIDID || nPos > getFields().size() )
+ return OUString();
+
+ OTableFieldDescRef pEntry = getFields()[nPos-1];
+ OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::GetCellText : invalid column id, prepare for GPF ... ");
+ if ( pEntry->IsEmpty() )
+ return OUString();
+
+ OUString aText;
+ switch (nRow)
+ {
+ case BROW_TABLE_ROW:
+ aText = pEntry->GetAlias();
+ break;
+ case BROW_FIELD_ROW:
+ {
+ OUString aField = pEntry->GetField();
+ if (!aField.isEmpty() && aField[0] == '*') // * replace with alias.*
+ {
+ aField = pEntry->GetAlias();
+ if(!aField.isEmpty())
+ aField += ".";
+ aField += "*";
+ }
+ aText = aField;
+ } break;
+ case BROW_ORDER_ROW:
+ if (pEntry->GetOrderDir() != ORDER_NONE)
+ aText = DBA_RES(STR_QUERY_SORTTEXT).getToken(sal::static_int_cast< sal_uInt16 >(pEntry->GetOrderDir()), ';');
+ break;
+ case BROW_VIS_ROW:
+ break;
+ case BROW_COLUMNALIAS_ROW:
+ aText = pEntry->GetFieldAlias();
+ break;
+ case BROW_FUNCTION_ROW:
+ // we always show the group function at first
+ if ( pEntry->IsGroupBy() )
+ aText = m_aFunctionStrings.copy(m_aFunctionStrings.lastIndexOf(';')+1);
+ else if ( pEntry->isNumericOrAggregateFunction() )
+ aText = pEntry->GetFunction();
+ break;
+ default:
+ aText = pEntry->GetCriteria(sal_uInt16(nRow - BROW_CRIT1_ROW));
+ }
+ return aText;
+}
+
+bool OSelectionBrowseBox::GetFunctionName(sal_uInt32 _nFunctionTokenId, OUString& rFkt)
+{
+ weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
+ switch(_nFunctionTokenId)
+ {
+ case SQL_TOKEN_COUNT:
+ rFkt = (rComboBox.get_count() < 3) ? rComboBox.get_text(1) : rComboBox.get_text(2);
+ break;
+ case SQL_TOKEN_AVG:
+ rFkt = rComboBox.get_text(1);
+ break;
+ case SQL_TOKEN_MAX:
+ rFkt = rComboBox.get_text(3);
+ break;
+ case SQL_TOKEN_MIN:
+ rFkt = rComboBox.get_text(4);
+ break;
+ case SQL_TOKEN_SUM:
+ rFkt = rComboBox.get_text(5);
+ break;
+ case SQL_TOKEN_EVERY:
+ rFkt = rComboBox.get_text(6);
+ break;
+ case SQL_TOKEN_ANY:
+ rFkt = rComboBox.get_text(7);
+ break;
+ case SQL_TOKEN_SOME:
+ rFkt = rComboBox.get_text(8);
+ break;
+ case SQL_TOKEN_STDDEV_POP:
+ rFkt = rComboBox.get_text(9);
+ break;
+ case SQL_TOKEN_STDDEV_SAMP:
+ rFkt = rComboBox.get_text(10);
+ break;
+ case SQL_TOKEN_VAR_SAMP:
+ rFkt = rComboBox.get_text(11);
+ break;
+ case SQL_TOKEN_VAR_POP:
+ rFkt = rComboBox.get_text(12);
+ break;
+ case SQL_TOKEN_COLLECT:
+ rFkt = rComboBox.get_text(13);
+ break;
+ case SQL_TOKEN_FUSION:
+ rFkt = rComboBox.get_text(14);
+ break;
+ case SQL_TOKEN_INTERSECTION:
+ rFkt = rComboBox.get_text(15);
+ break;
+ default:
+ {
+ const sal_Int32 nStopIdx = m_aFunctionStrings.lastIndexOf(';'); // grouping is not counted
+ for (sal_Int32 nIdx {0}; nIdx<nStopIdx;)
+ {
+ const OUString sFunc {m_aFunctionStrings.getToken(0, ';', nIdx)};
+ if (rFkt.equalsIgnoreAsciiCase(sFunc))
+ {
+ rFkt = sFunc;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+OUString OSelectionBrowseBox::GetCellContents(sal_Int32 nCellIndex, sal_uInt16 nColId)
+{
+ if ( GetCurColumnId() == nColId && !m_bInUndoMode )
+ SaveModified();
+
+ sal_uInt16 nPos = GetColumnPos(nColId);
+ OTableFieldDescRef pEntry = getFields()[nPos - 1];
+ OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::GetCellContents : invalid column id, prepare for GPF ... ");
+
+ switch (nCellIndex)
+ {
+ case BROW_VIS_ROW :
+ return OUString(pEntry->IsVisible() ? std::u16string_view(u"1") : std::u16string_view(u"0"));
+ case BROW_ORDER_ROW:
+ {
+ sal_Int32 nIdx = m_pOrderCell->get_widget().get_active();
+ if (nIdx == -1)
+ nIdx = 0;
+ return OUString::number(nIdx);
+ }
+ default:
+ return GetCellText(nCellIndex, nColId);
+ }
+}
+
+void OSelectionBrowseBox::SetCellContents(sal_Int32 nRow, sal_uInt16 nColId, const OUString& strNewText)
+{
+ bool bWasEditing = IsEditing() && (GetCurColumnId() == nColId) && IsRowVisible(static_cast<sal_uInt16>(nRow)) && (GetCurRow() == static_cast<sal_uInt16>(GetBrowseRow(nRow)));
+ if (bWasEditing)
+ DeactivateCell();
+
+ sal_uInt16 nPos = GetColumnPos(nColId);
+ OTableFieldDescRef pEntry = getEntry(nPos - 1);
+ OSL_ENSURE(pEntry != nullptr, "OSelectionBrowseBox::SetCellContents : invalid column id, prepare for GPF ... ");
+
+ switch (nRow)
+ {
+ case BROW_VIS_ROW:
+ pEntry->SetVisible(strNewText == "1");
+ break;
+ case BROW_FIELD_ROW:
+ pEntry->SetField(strNewText);
+ break;
+ case BROW_TABLE_ROW:
+ pEntry->SetAlias(strNewText);
+ break;
+ case BROW_ORDER_ROW:
+ {
+ sal_uInt16 nIdx = static_cast<sal_uInt16>(strNewText.toInt32());
+ pEntry->SetOrderDir(EOrderDir(nIdx));
+ } break;
+ case BROW_COLUMNALIAS_ROW:
+ pEntry->SetFieldAlias(strNewText);
+ break;
+ case BROW_FUNCTION_ROW:
+ {
+ std::u16string_view sGroupFunctionName = m_aFunctionStrings.subView(m_aFunctionStrings.lastIndexOf(';')+1);
+ pEntry->SetFunction(strNewText);
+ // first reset this two member
+ sal_Int32 nFunctionType = pEntry->GetFunctionType();
+ nFunctionType &= ~FKT_AGGREGATE;
+ pEntry->SetFunctionType(nFunctionType);
+ if ( pEntry->IsGroupBy() && !o3tl::equalsIgnoreAsciiCase(sGroupFunctionName, strNewText) )
+ pEntry->SetGroupBy(false);
+
+ if ( o3tl::equalsIgnoreAsciiCase(sGroupFunctionName, strNewText) )
+ pEntry->SetGroupBy(true);
+ else if ( !strNewText.isEmpty() )
+ {
+ nFunctionType |= FKT_AGGREGATE;
+ pEntry->SetFunctionType(nFunctionType);
+ }
+ } break;
+ default:
+ pEntry->SetCriteria(sal_uInt16(nRow - BROW_CRIT1_ROW), strNewText);
+ }
+
+ tools::Long nCellIndex = GetRealRow(nRow);
+ if(IsRowVisible(static_cast<sal_uInt16>(nRow)))
+ RowModified(nCellIndex, nColId);
+
+ // the appropriate field-description is now empty -> set Visible to sal_False (now it is consistent to normal empty rows)
+ if (pEntry->IsEmpty())
+ pEntry->SetVisible(false);
+
+ if (bWasEditing)
+ ActivateCell(nCellIndex, nColId);
+
+ static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
+}
+
+void OSelectionBrowseBox::ColumnResized(sal_uInt16 nColId)
+{
+ if (static_cast<OQueryController&>(getDesignView()->getController()).isReadOnly())
+ return;
+ // The resizing of columns can't be suppressed (BrowseBox doesn't support that) so we have to do this
+ // fake. It's not _that_ bad : the user may change column widths while in read-only mode to see all details
+ // but the changes aren't permanent ...
+
+ sal_uInt16 nPos = GetColumnPos(nColId);
+ OSL_ENSURE(nPos <= getFields().size(),"ColumnResized:: nColId should not be greater than List::count!");
+ OTableFieldDescRef pEntry = getEntry(nPos-1);
+ OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::ColumnResized : invalid FieldDescription !");
+ static_cast<OQueryController&>(getDesignView()->getController()).setModified( true );
+ EditBrowseBox::ColumnResized(nColId);
+
+ if ( pEntry.is())
+ {
+ if ( !m_bInUndoMode )
+ {
+ // create the undo action
+ std::unique_ptr<OTabFieldSizedUndoAct> pUndo(new OTabFieldSizedUndoAct(this));
+ pUndo->SetColumnPosition( nPos );
+ pUndo->SetOriginalWidth(pEntry->GetColWidth());
+ getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndo));
+ }
+ pEntry->SetColWidth(sal_uInt16(GetColumnWidth(nColId)));
+ }
+}
+
+sal_uInt32 OSelectionBrowseBox::GetTotalCellWidth(sal_Int32 nRowId, sal_uInt16 nColId)
+{
+ sal_uInt16 nPos = GetColumnPos(nColId);
+ OSL_ENSURE((nPos == 0) || (nPos <= getFields().size()), "OSelectionBrowseBox::GetTotalCellWidth : invalid parameter nColId");
+
+ OTableFieldDescRef pEntry = getFields()[nPos-1];
+ OSL_ENSURE(pEntry.is(), "OSelectionBrowseBox::GetTotalCellWidth : invalid FieldDescription !");
+
+ sal_Int32 nRow = GetRealRow(nRowId);
+ OUString strText(GetCellText(nRow, nColId));
+ return GetDataWindow().LogicToPixel(Size(GetDataWindow().GetTextWidth(strText),0)).Width();
+}
+
+bool OSelectionBrowseBox::isCutAllowed() const
+{
+ bool bCutAllowed = false;
+ sal_Int32 nRow = GetRealRow(GetCurRow());
+ switch (nRow)
+ {
+ case BROW_VIS_ROW:
+ case BROW_ORDER_ROW:
+ case BROW_TABLE_ROW:
+ case BROW_FUNCTION_ROW:
+ break;
+ case BROW_FIELD_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
+ int nStartPos, nEndPos;
+ bCutAllowed = rComboBox.get_entry_selection_bounds(nStartPos, nEndPos);
+ break;
+ }
+ default:
+ {
+ weld::Entry& rEntry = m_pTextCell->get_widget();
+ int nStartPos, nEndPos;
+ bCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
+ break;
+ }
+ }
+ return bCutAllowed;
+}
+
+void OSelectionBrowseBox::cut()
+{
+ sal_Int32 nRow = GetRealRow(GetCurRow());
+ switch (nRow)
+ {
+ case BROW_FIELD_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
+ rComboBox.cut_entry_clipboard();
+ break;
+ }
+ default:
+ {
+ weld::Entry& rEntry = m_pTextCell->get_widget();
+ rEntry.cut_clipboard();
+ }
+ }
+ SaveModified();
+ RowModified(GetBrowseRow(nRow), GetCurColumnId());
+
+ invalidateUndoRedo();
+}
+
+void OSelectionBrowseBox::paste()
+{
+ sal_Int32 nRow = GetRealRow(GetCurRow());
+ switch (nRow)
+ {
+ case BROW_FIELD_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
+ rComboBox.paste_entry_clipboard();
+ break;
+ }
+ default:
+ {
+ weld::Entry& rEntry = m_pTextCell->get_widget();
+ rEntry.paste_clipboard();
+ break;
+ }
+ }
+ RowModified(GetBrowseRow(nRow), GetCurColumnId());
+ invalidateUndoRedo();
+}
+
+bool OSelectionBrowseBox::isPasteAllowed() const
+{
+ bool bPasteAllowed = true;
+ sal_Int32 nRow = GetRealRow(GetCurRow());
+ switch (nRow)
+ {
+ case BROW_VIS_ROW:
+ case BROW_ORDER_ROW:
+ case BROW_TABLE_ROW:
+ case BROW_FUNCTION_ROW:
+ bPasteAllowed = false;
+ break;
+ }
+ return bPasteAllowed;
+}
+
+bool OSelectionBrowseBox::isCopyAllowed() const
+{
+ return isCutAllowed();
+}
+
+void OSelectionBrowseBox::copy()
+{
+ sal_Int32 nRow = GetRealRow(GetCurRow());
+ switch (nRow)
+ {
+ case BROW_FIELD_ROW:
+ {
+ weld::ComboBox& rComboBox = m_pFieldCell->get_widget();
+ rComboBox.copy_entry_clipboard();
+ break;
+ }
+ default:
+ {
+ weld::Entry& rEntry = m_pTextCell->get_widget();
+ rEntry.copy_clipboard();
+ break;
+ }
+ }
+}
+
+void OSelectionBrowseBox::appendUndoAction(const OUString& _rOldValue, std::u16string_view _rNewValue, sal_Int32 _nRow, bool& _bListAction)
+{
+ if ( !m_bInUndoMode && _rNewValue != _rOldValue )
+ {
+ if ( !_bListAction )
+ {
+ _bListAction = true;
+ static_cast<OQueryController&>(getDesignView()->getController()).GetUndoManager().EnterListAction(OUString(),OUString(),0,ViewShellId(-1));
+ }
+ appendUndoAction(_rOldValue,_rNewValue,_nRow);
+ }
+}
+
+void OSelectionBrowseBox::appendUndoAction(const OUString& _rOldValue,std::u16string_view _rNewValue,sal_Int32 _nRow)
+{
+ if ( !m_bInUndoMode && _rNewValue != _rOldValue )
+ {
+ std::unique_ptr<OTabFieldCellModifiedUndoAct> pUndoAct(new OTabFieldCellModifiedUndoAct(this));
+ pUndoAct->SetCellIndex(_nRow);
+ OSL_ENSURE(GetColumnPos(GetCurColumnId()) != BROWSER_INVALIDID,"Current position isn't valid!");
+ pUndoAct->SetColumnPosition( GetColumnPos(GetCurColumnId()) );
+ pUndoAct->SetCellContents(_rOldValue);
+ getDesignView()->getController().addUndoActionAndInvalidate(std::move(pUndoAct));
+ }
+}
+
+IMPL_LINK_NOARG(OSelectionBrowseBox, OnInvalidateTimer, Timer *, void)
+{
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_CUT);
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_COPY);
+ static_cast<OQueryController&>(getDesignView()->getController()).InvalidateFeature(SID_PASTE);
+ if(!m_bStopTimer)
+ m_timerInvalidate.Start();
+}
+
+void OSelectionBrowseBox::stopTimer()
+{
+ m_bStopTimer = true;
+ if (m_timerInvalidate.IsActive())
+ m_timerInvalidate.Stop();
+}
+
+void OSelectionBrowseBox::startTimer()
+{
+ m_bStopTimer = false;
+ if (!m_timerInvalidate.IsActive())
+ m_timerInvalidate.Start();
+}
+
+OTableFields& OSelectionBrowseBox::getFields() const
+{
+ OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
+ return rController.getTableFieldDesc();
+}
+
+void OSelectionBrowseBox::enableControl(const OTableFieldDescRef& _rEntry,Window* _pControl)
+{
+ bool bEnable = !_rEntry->isCondition();
+ _pControl->Enable(bEnable);
+ _pControl->EnableInput(bEnable);
+}
+
+void OSelectionBrowseBox::setTextCellContext(const OTableFieldDescRef& _rEntry,const OUString& _sText,const OString& _sHelpId)
+{
+ weld::Entry& rEntry = m_pTextCell->get_widget();
+ rEntry.set_text(_sText);
+ rEntry.save_value();
+ if (!m_pTextCell->HasFocus())
+ m_pTextCell->GrabFocus();
+
+ enableControl(_rEntry,m_pTextCell);
+
+ if (m_pTextCell->GetHelpId() != _sHelpId)
+ // as TextCell is used in various contexts I will delete the cached HelpText
+ m_pTextCell->SetHelpText(OUString());
+ m_pTextCell->SetHelpId(_sHelpId);
+}
+
+void OSelectionBrowseBox::invalidateUndoRedo()
+{
+ OQueryController& rController = static_cast<OQueryController&>(getDesignView()->getController());
+ rController.InvalidateFeature( ID_BROWSER_UNDO );
+ rController.InvalidateFeature( ID_BROWSER_REDO );
+ rController.InvalidateFeature( ID_BROWSER_QUERY_EXECUTE );
+}
+
+OTableFieldDescRef OSelectionBrowseBox::getEntry(OTableFields::size_type _nPos)
+{
+ // we have to check if we need a new entry at this position
+ OTableFields& aFields = getFields();
+ OSL_ENSURE(aFields.size() > _nPos,"ColID is to great!");
+
+ OTableFieldDescRef pEntry = aFields[_nPos];
+ OSL_ENSURE(pEntry.is(),"Invalid entry!");
+ if ( !pEntry.is() )
+ {
+ pEntry = new OTableFieldDesc();
+ pEntry->SetColumnId(
+ GetColumnId(sal::static_int_cast< sal_uInt16 >(_nPos+1)));
+ aFields[_nPos] = pEntry;
+ }
+ return pEntry;
+}
+
+void OSelectionBrowseBox::GetFocus()
+{
+ if(!IsEditing() && !m_bWasEditing)
+ ActivateCell();
+ EditBrowseBox::GetFocus();
+}
+
+void OSelectionBrowseBox::DeactivateCell(bool _bUpdate)
+{
+ m_bWasEditing = true;
+ EditBrowseBox::DeactivateCell(_bUpdate);
+ m_bWasEditing = false;
+}
+
+OUString OSelectionBrowseBox::GetRowDescription( sal_Int32 _nRow ) const
+{
+ OUString aLabel(DBA_RES(STR_QUERY_HANDLETEXT));
+
+ // from BROW_CRIT2_ROW onwards all rows are shown as "or"
+ sal_Int32 nToken = (_nRow >= GetBrowseRow(BROW_CRIT2_ROW))
+ ? BROW_CRIT2_ROW : GetRealRow(_nRow);
+ return aLabel.getToken(nToken, ';');
+}
+
+OUString OSelectionBrowseBox::GetAccessibleObjectName( AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition) const
+{
+ OUString sRetText;
+ switch( _eObjType )
+ {
+ case AccessibleBrowseBoxObjType::RowHeaderCell:
+ sRetText = GetRowDescription(_nPosition);
+ break;
+ default:
+ sRetText = EditBrowseBox::GetAccessibleObjectDescription(_eObjType,_nPosition);
+ }
+ return sRetText;
+}
+
+bool OSelectionBrowseBox::fillEntryTable(OTableFieldDescRef const & _pEntry,const OUString& _sTableName)
+{
+ bool bRet = false;
+ OJoinTableView::OTableWindowMap& rTabWinList = getDesignView()->getTableView()->GetTabWinMap();
+ OJoinTableView::OTableWindowMap::const_iterator aIter = rTabWinList.find(_sTableName);
+ if(aIter != rTabWinList.end())
+ {
+ OQueryTableWindow* pEntryTab = static_cast<OQueryTableWindow*>(aIter->second.get());
+ if (pEntryTab)
+ {
+ _pEntry->SetTable(pEntryTab->GetTableName());
+ _pEntry->SetTabWindow(pEntryTab);
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+void OSelectionBrowseBox::setFunctionCell(OTableFieldDescRef const & _pEntry)
+{
+ Reference< XConnection> xConnection = static_cast<OQueryController&>(getDesignView()->getController()).getConnection();
+ if ( !xConnection.is() )
+ return;
+
+ // Aggregate functions in general only available with Core SQL
+ if ( lcl_SupportsCoreSQLGrammar(xConnection) )
+ {
+ sal_Int32 nIdx {0};
+ // if we have an asterisk, no other function than count is allowed
+ weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
+ rComboBox.clear();
+ rComboBox.append_text(m_aFunctionStrings.getToken(0, ';', nIdx));
+ if ( isFieldNameAsterisk(_pEntry->GetField()) )
+ rComboBox.append_text(m_aFunctionStrings.getToken(1, ';', nIdx)); // 2nd token: COUNT
+ else
+ {
+ const bool bSkipLastToken {_pEntry->isNumeric()};
+ while (nIdx>0)
+ {
+ const OUString sTok {m_aFunctionStrings.getToken(0, ';', nIdx)};
+ if (bSkipLastToken && nIdx<0)
+ break;
+ rComboBox.append_text(sTok);
+ }
+ }
+
+ if ( _pEntry->IsGroupBy() )
+ {
+ OSL_ENSURE(!_pEntry->isNumeric(),"Not allowed to combine group by and numeric values!");
+ rComboBox.set_active_text(rComboBox.get_text(rComboBox.get_count() - 1));
+ }
+ else if (rComboBox.find_text(_pEntry->GetFunction()) != -1)
+ rComboBox.set_active_text(_pEntry->GetFunction());
+ else
+ rComboBox.set_active(0);
+
+ enableControl(_pEntry, m_pFunctionCell);
+ }
+ else
+ {
+ // only COUNT(*) and COUNT("table".*) allowed
+ bool bCountRemoved = !isFieldNameAsterisk(_pEntry->GetField());
+ weld::ComboBox& rComboBox = m_pFunctionCell->get_widget();
+ if ( bCountRemoved )
+ rComboBox.remove(1);
+
+ if ( !bCountRemoved && rComboBox.get_count() < 2)
+ rComboBox.append_text(m_aFunctionStrings.getToken(2, ';')); // 2 -> COUNT
+
+ if (rComboBox.find_text(_pEntry->GetFunction()) != -1)
+ rComboBox.set_active_text(_pEntry->GetFunction());
+ else
+ rComboBox.set_active(0);
+ }
+}
+
+Reference< XAccessible > OSelectionBrowseBox::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
+{
+ OTableFieldDescRef pEntry;
+ if ( _nColumnPos != 0 && _nColumnPos != BROWSER_INVALIDID && _nColumnPos <= getFields().size() )
+ pEntry = getFields()[_nColumnPos - 1];
+
+ if ( _nRow == BROW_VIS_ROW && pEntry.is() )
+ return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,pEntry->IsVisible() ? TRISTATE_TRUE : TRISTATE_FALSE );
+
+ return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos );
+}
+
+bool OSelectionBrowseBox::HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const
+{
+ for (auto const& field : getFields())
+ {
+ if ( field->GetFieldAlias() == rFieldName )
+ {
+ *rInfo = *field;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx b/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx
new file mode 100644
index 000000000..761870fb8
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx
@@ -0,0 +1,324 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <svtools/editbrowsebox.hxx>
+#include <TableFieldDescription.hxx>
+#include <TableWindowListBox.hxx>
+#include <QEnumTypes.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace connectivity
+{
+ class OSQLParseNode;
+}
+
+namespace dbaui
+{
+#define BROW_FIELD_ROW 0
+#define BROW_COLUMNALIAS_ROW 1
+#define BROW_TABLE_ROW 2
+#define BROW_ORDER_ROW 3
+#define BROW_VIS_ROW 4
+#define BROW_FUNCTION_ROW 5
+#define BROW_CRIT1_ROW 6
+#define BROW_CRIT2_ROW 7
+#define BROW_CRIT3_ROW 8
+#define BROW_CRIT4_ROW 9
+#define BROW_CRIT5_ROW 10
+#define BROW_CRIT6_ROW 11
+#define BROW_ROW_CNT 12
+
+ class OQueryDesignView;
+ class OSelectionBrowseBox final : public ::svt::EditBrowseBox
+ {
+ friend class OQueryDesignView;
+ std::vector<bool> m_bVisibleRow; // at pos we find the RowId
+ Timer m_timerInvalidate;
+
+ sal_Int32 m_nSeekRow;
+ BrowserMode m_nMode; // remember the BrowseModes
+ VclPtr< ::svt::EditControl> m_pTextCell;
+ VclPtr< ::svt::CheckBoxControl> m_pVisibleCell;
+ VclPtr< ::svt::ComboBoxControl> m_pFieldCell;
+ VclPtr< ::svt::ListBoxControl> m_pFunctionCell;
+ VclPtr< ::svt::ListBoxControl> m_pTableCell;
+ VclPtr< ::svt::ListBoxControl> m_pOrderCell;
+
+ sal_Int32 m_nMaxColumns; // maximum number of columns in a Select-Statement
+
+ OUString m_aFunctionStrings;
+ sal_uInt16 m_nVisibleCount; // maximum number of visible rows
+ sal_uInt32 m_nLastSortColumn; // index of last (highest) sort column
+ bool m_bOrderByUnRelated;
+ bool m_bGroupByUnRelated;
+ bool m_bStopTimer;
+ bool m_bWasEditing;
+ bool m_bDisableErrorBox;
+ bool m_bInUndoMode;
+
+ DECL_LINK(OnInvalidateTimer, Timer*, void);
+ public:
+ explicit OSelectionBrowseBox( vcl::Window* pParent );
+ virtual ~OSelectionBrowseBox() override;
+ virtual void dispose() override;
+
+ void initialize();
+ OTableFieldDescRef InsertField( const OJoinExchangeData& jxdSource );
+ OTableFieldDescRef InsertField( const OTableFieldDescRef& rInfo, sal_uInt16 _nColumnPosition = BROWSER_INVALIDID, bool bVis=true, bool bActivate=true );
+ void InsertColumn( const OTableFieldDescRef& pEntry, sal_uInt16& _nColumnPosition );
+ void RemoveColumn( sal_uInt16 _nColumnId );
+ void DeleteFields( const OUString& rAliasName );
+
+ bool HasFieldByAliasName(std::u16string_view rFieldName, OTableFieldDescRef const & rInfo) const;
+
+ // AddGroupBy:: inserts a field with function == grouping. If the fields already exists and uses an aggregate function,
+ // the flag is not set
+ void AddGroupBy( const OTableFieldDescRef& rInfo );
+ void AddCondition( const OTableFieldDescRef& rInfo,
+ const OUString& rValue,
+ const sal_uInt16 nLevel,
+ bool _bAddOrOnOneLine );
+ void DuplicateConditionLevel( const sal_uInt16 nLevel);
+ void AddOrder(const OTableFieldDescRef& rInfo, const EOrderDir eDir, sal_uInt32 _nCurrentPos);
+ void ClearAll();
+ OTableFieldDescRef const & AppendNewCol( sal_uInt16 nCnt=1 );
+ bool Save();
+ OQueryDesignView* getDesignView();
+ OQueryDesignView* getDesignView() const;
+ sal_uInt16 FieldsCount();
+
+ void SetColWidth(sal_uInt16 nColId, tools::Long lNewWidth);
+ // unlike SetColumnWidth of the base class it checks an active cell in this column
+
+ OUString GetCellContents(sal_Int32 nCellIndex, sal_uInt16 nColId);
+ void SetCellContents(sal_Int32 nCellIndex, sal_uInt16 nColId, const OUString& strNewText);
+ // cell content (formatted as string) set/return
+ sal_Int32 GetNoneVisibleRows() const;
+ void SetNoneVisibleRow(sal_Int32 nRows);
+ bool IsRowVisible(sal_uInt16 _nWhich) const;
+ void SetRowVisible(sal_uInt16 _nWhich, bool _bVis);
+
+ void SetReadOnly(bool bRO);
+ // calculate an optimal size. Basically, this takes into account the number of visible rows.
+ Size CalcOptimalSize( const Size& _rAvailable );
+
+ // can the current content be cut
+ bool isPasteAllowed() const;
+ bool isCutAllowed() const;
+ bool isCopyAllowed() const;
+ void cut();
+ void paste();
+ void copy();
+
+ virtual void GetFocus() override;
+ virtual void DeactivateCell(bool bUpdate = true) override;
+ virtual void ColumnMoved( sal_uInt16 nColId ) override { ColumnMoved(nColId,true); }
+ void ColumnMoved( sal_uInt16 nColId, bool _bCreateUndo);
+
+ void Fill();
+ void PreFill();
+
+ /** Disables the generation of undo actions
+ */
+ void EnterUndoMode() { m_bInUndoMode = true; }
+ /** Enables the generation of undo actions
+ */
+ void LeaveUndoMode() { m_bInUndoMode = false; }
+
+ /** GetCellText returns the text at the given position
+ @param _nRow
+ the number of the row
+ @param _nColId
+ the ID of the column
+ @return
+ the text out of the cell
+ */
+ virtual OUString GetCellText(sal_Int32 _nRow, sal_uInt16 _nColId) const override;
+
+ /** returns the description of the row.
+ @param _nRow
+ The row number.
+ @return
+ The header text of the specified row.
+ */
+ virtual OUString GetRowDescription( sal_Int32 _nRow ) const override;
+
+ /** return the name of the specified object.
+ @param eObjType
+ The type to ask for
+ @param _nPosition
+ The position of a tablecell (index position), header bar column/row cell
+ @return
+ The name of the specified object.
+ */
+ virtual OUString GetAccessibleObjectName( AccessibleBrowseBoxObjType eObjType,sal_Int32 _nPosition = -1) const override;
+
+ // IAccessibleTableProvider
+ /** Creates the accessible object of a data table cell.
+ @param nRow The row index of the cell.
+ @param nColumnId The column ID of the cell.
+ @return The XAccessible interface of the specified cell. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessibleCell( sal_Int32 nRow, sal_uInt16 nColumnId ) override;
+
+ private:
+ virtual bool SeekRow( sal_Int32 nRow ) override;
+
+ virtual void PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const override;
+ virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect,
+ sal_uInt16 nColumnId ) const override;
+
+ virtual sal_Int8 AcceptDrop( const BrowserAcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) override;
+ virtual void MouseButtonDown( const BrowserMouseEvent& rEvt ) override;
+ virtual void MouseButtonUp( const BrowserMouseEvent& rEvt ) override;
+ virtual void KeyInput( const KeyEvent& rEvt ) override;
+ virtual void Command(const CommandEvent& rEvt) override;
+
+ virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override;
+ virtual void InitController(::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol) override;
+ virtual void CellModified() override;
+ virtual bool SaveModified() override;
+ virtual void Init() override;
+ virtual void ColumnResized( sal_uInt16 nColId ) override;
+
+ virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override;
+
+ // if you want to have an own header ...
+ virtual VclPtr<BrowserHeader> imp_CreateHeaderBar(BrowseBox* pParent) override;
+
+ void stopTimer();
+ void startTimer();
+
+ OTableFieldDescRef FindFirstFreeCol(sal_uInt16& _rColumnPosition);
+
+ // rCol contains the number (in pOTableFieldDescList) of the first column, which itself tells it is empty
+ // if there are none, rCol is undefined and the returnvalue NULL
+ void CheckFreeColumns(sal_uInt16& _rColumnPosition);
+ // checks if empty columns are available, if not, a new pack is appended
+ // rCol contains the number of the first empty column (in pOTableFieldDescList)
+
+ void RemoveField( sal_uInt16 nId );
+ tools::Rectangle GetInvalidRect( sal_uInt16 nColId );
+ sal_Int32 GetRealRow(sal_Int32 nRow) const;
+ sal_Int32 GetBrowseRow(sal_Int32 nRowId) const;
+ bool GetFunctionName(sal_uInt32 _nFunctionTokenId, OUString& rFkt);
+ void appendUndoAction(const OUString& _rOldValue,std::u16string_view _rNewValue,sal_Int32 _nRow, bool& _bListAction);
+ void appendUndoAction(const OUString& _rOldValue,std::u16string_view _rNewValue,sal_Int32 _nRow);
+ OTableFields& getFields() const;
+ static void enableControl(const OTableFieldDescRef& _rEntry,Window* _pControl);
+ void setTextCellContext(const OTableFieldDescRef& _rEntry,const OUString& _sText,const OString& _sHelpId);
+ void invalidateUndoRedo();
+ OTableFieldDescRef getEntry(OTableFields::size_type _nPos);
+
+ void adjustSelectionMode( bool _bClickedOntoHeader, bool _bClickedOntoHandleCol );
+
+ /** save the field change in save modified
+ @param _sFieldName
+ The field name inserted by the user.
+ @param _pEntry
+ The entry which will contain the necessary entries.
+ @param _bListAction
+ Will be set to <TRUE/> when we are in a list action otherwise <FALSE/>
+ @return
+ <TRUE/> if an error occurred otherwise <FALSE/>
+ */
+ bool saveField(OUString& _sFieldName, OTableFieldDescRef const & _pEntry, bool& _bListAction);
+
+ /** sets the table window at the _pEntry
+ @param _pEntry
+ The entry where the window should be set.
+ @param _sTableName
+ The table name to search for.
+ @return
+ <TRUE/> if the table name was set otherwise <FALSE/>
+ */
+ bool fillEntryTable(OTableFieldDescRef const & _pEntry,const OUString& _sTableName);
+
+ /** uses the parse node to fill all information into the field
+ @param _pColumnRef
+ The parse node used to fill the info into the field.
+ @param _xMetaData
+ Use to parse the node to a string.
+ @param _pEntry
+ The entry which will contain the necessary entries.
+ @param _bListAction
+ Will be set to <TRUE/> when we are in a list action otherwise <FALSE/>
+ @return
+ <TRUE/> if an error occurred otherwise <FALSE/>
+ */
+ bool fillColumnRef( const ::connectivity::OSQLParseNode* _pColumnRef,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ OTableFieldDescRef const & _pEntry,
+ bool& _bListAction);
+ bool fillColumnRef( const OUString& _sColumnName,
+ std::u16string_view _sTableRange,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _xMetaData,
+ OTableFieldDescRef const & _pEntry,
+ bool& _bListAction);
+
+ /** append an undo action for the table field
+ @param _sOldAlias
+ The old table alias.
+ @param _sAlias
+ The new alias name.
+ @param _bListAction
+ Will be set to <TRUE/> when we are in a list action otherwise <FALSE/>
+ */
+ void notifyTableFieldChanged(const OUString& _sOldAlias,std::u16string_view _sAlias, bool& _bListAction,sal_uInt16 _nColumnId);
+
+ /** append an undo action for the function field
+ @param _sOldFunctionName
+ The old value.
+ @param _sFunctionName
+ The new function name.
+ @param _bListAction
+ Will be set to <TRUE/> when we are in a list action otherwise <FALSE/>
+ */
+ void notifyFunctionFieldChanged(const OUString& _sOldFunctionName,std::u16string_view _sFunctionName, bool& _bListAction,sal_uInt16 _nColumnId);
+
+ /** clears the function fields of the submitted entry if it doesn't match the SQL standard and append an undo action.
+ E.q. AGGREGATE functions are only valid when the field name isn't an asterisk
+ @param _sFieldName
+ The field name.
+ @param _pEntry
+ The entry to be cleared
+ @param _bListAction
+ When <TRUE/> a list action will be created.
+ */
+ void clearEntryFunctionField(const OUString& _sFieldName,OTableFieldDescRef const & _pEntry, bool& _bListAction,sal_uInt16 _nColumnId);
+
+ /** remove or insert the necessary function types
+ @param _pEntry
+ The currently edited entry.
+ */
+ void setFunctionCell(OTableFieldDescRef const & _pEntry);
+
+ using ::svt::EditBrowseBox::AcceptDrop;
+ using ::svt::EditBrowseBox::ExecuteDrop;
+ using ::svt::EditBrowseBox::MouseButtonDown;
+ using ::svt::EditBrowseBox::MouseButtonUp;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableConnection.cxx b/dbaccess/source/ui/querydesign/TableConnection.cxx
new file mode 100644
index 000000000..ada4b5990
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableConnection.cxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableConnection.hxx>
+#include <ConnectionLine.hxx>
+#include <TableConnectionData.hxx>
+#include <JoinTableView.hxx>
+
+using namespace dbaui;
+using namespace comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+namespace dbaui
+{
+ OTableConnection::OTableConnection( OJoinTableView* _pContainer,const TTableConnectionData::value_type& _pTabConnData )
+ :Window(_pContainer)
+ ,m_pData( _pTabConnData )
+ ,m_pParent( _pContainer )
+ ,m_bSelected( false )
+ {
+ Init();
+ Show();
+ }
+
+ OTableConnection::OTableConnection( const OTableConnection& _rConn )
+ : VclReferenceBase()
+ ,Window(_rConn.m_pParent.get())
+ ,m_pData(_rConn.GetData()->NewInstance())
+ ,m_pParent(nullptr)
+ {
+ *this = _rConn;
+ }
+
+ void OTableConnection::Init()
+ {
+ // initialise linelist with defaults
+ OConnectionLineDataVec& rLineData = GetData()->GetConnLineDataList();
+ m_vConnLine.reserve(rLineData.size());
+ for (auto const& elem : rLineData)
+ m_vConnLine.emplace_back( new OConnectionLine(this, elem) );
+ }
+
+ void OTableConnection::clearLineData()
+ {
+ m_vConnLine.clear();
+ }
+ void OTableConnection::UpdateLineList()
+ {
+ // delete linelist
+ clearLineData();
+
+ Init();
+ }
+
+ OTableConnection& OTableConnection::operator=( const OTableConnection& rConn )
+ {
+ if( &rConn == this )
+ return *this;
+
+ // delete linelist
+ clearLineData();
+
+ // copy linelist
+ if(! rConn.GetConnLineList().empty() )
+ {
+ const std::vector<std::unique_ptr<OConnectionLine>>& rLine = rConn.GetConnLineList();
+ m_vConnLine.reserve(rLine.size());
+ for (auto const& elem : rLine)
+ m_vConnLine.emplace_back( new OConnectionLine(*elem));
+ }
+
+ // as the data are not mine, I also do not delete the old
+ m_pData->CopyFrom(*rConn.GetData());
+ // CopyFrom is virtual, therefore it is not a problem if m_pData is a derived type of OTableConnectionData
+
+ m_bSelected = rConn.m_bSelected;
+ m_pParent = rConn.m_pParent;
+
+ return *this;
+ }
+
+ void OTableConnection::RecalcLines()
+ {
+ // call RecalcLines on each line
+ for( const auto& pLine : m_vConnLine )
+ pLine->RecalcLine();
+ }
+ OTableWindow* OTableConnection::GetSourceWin() const
+ {
+ TTableWindowData::value_type pRef = GetData()->getReferencingTable();
+ OTableWindow* pRet = m_pParent->GetTabWindow( pRef->GetWinName() );
+ if ( !pRet )
+ {
+ pRet = m_pParent->GetTabWindow( pRef->GetComposedName() );
+ }
+ return pRet;
+ }
+ OTableWindow* OTableConnection::GetDestWin() const
+ {
+ TTableWindowData::value_type pRef = GetData()->getReferencedTable();
+ OTableWindow* pRet = m_pParent->GetTabWindow( pRef->GetWinName() );
+ if ( !pRet )
+ {
+ pRet = m_pParent->GetTabWindow( pRef->GetComposedName() );
+ }
+ return pRet;
+ }
+
+ void OTableConnection::Select()
+ {
+ m_bSelected = true;
+ m_pParent->Invalidate( GetBoundingRect(), InvalidateFlags::NoChildren);
+ }
+
+ void OTableConnection::Deselect()
+ {
+ m_bSelected = false;
+ InvalidateConnection();
+ }
+
+ bool OTableConnection::CheckHit( const Point& rMousePos ) const
+ {
+ // check if the point hit our line
+ return std::any_of(m_vConnLine.begin(),
+ m_vConnLine.end(),
+ [&rMousePos]
+ ( const std::unique_ptr<OConnectionLine> & pLine )
+ { return pLine->CheckHit( rMousePos ); } );
+ }
+
+ void OTableConnection::InvalidateConnection()
+ {
+ tools::Rectangle rcBounding = GetBoundingRect();
+ rcBounding.AdjustBottom(1 );
+ rcBounding.AdjustRight(1 );
+ // I believe Invalidate and Draw(Rectangle) do not behave consistent: in any case it
+ // could explain, why without the fake here when deleting a connection a dash remains at the lower end:
+ // Invalidate records obviously one pixel line less as Draw.
+ // Or everything works differently... in any case it works...
+ m_pParent->Invalidate( rcBounding, InvalidateFlags::NoChildren );
+ }
+
+ tools::Rectangle OTableConnection::GetBoundingRect() const
+ {
+ // determine all lines of the surrounding rectangle
+ tools::Rectangle aBoundingRect( Point(0,0), Point(0,0) );
+ tools::Rectangle aTempRect;
+ for (auto const& elem : m_vConnLine)
+ {
+ aTempRect = elem->GetBoundingRect();
+
+ // is the BoundingRect of this line valid?
+ if( (aTempRect.GetWidth()!=1) && (aTempRect.GetHeight()!=1) )
+ {
+ if( (aBoundingRect.GetWidth()==1) && (aBoundingRect.GetHeight()==1) )
+ aBoundingRect = aTempRect;
+ else
+ aBoundingRect.Union( aTempRect );
+ }
+ }
+
+ return aBoundingRect;
+ }
+
+ void OTableConnection::Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+ {
+ // Draw line
+ for( const auto& pLine : m_vConnLine )
+ pLine->Draw( &rRenderContext );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableConnectionData.cxx b/dbaccess/source/ui/querydesign/TableConnectionData.cxx
new file mode 100644
index 000000000..107d8a9d1
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableConnectionData.cxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableConnectionData.hxx>
+#include <osl/diagnose.h>
+
+using namespace dbaui;
+
+OTableConnectionData::OTableConnectionData()
+{
+ Init();
+}
+
+OTableConnectionData::OTableConnectionData(const TTableWindowData::value_type& _pReferencingTable
+ ,const TTableWindowData::value_type& _pReferencedTable )
+ :m_pReferencingTable(_pReferencingTable)
+ ,m_pReferencedTable(_pReferencedTable)
+{
+ Init();
+}
+
+void OTableConnectionData::Init()
+{
+ // initialise linedatalist with defaults
+ OSL_ENSURE(m_vConnLineData.empty(), "OTableConnectionData::Init() : call only with empty line list!");
+ ResetConnLines();
+ // this creates the defaults
+}
+
+OTableConnectionData::OTableConnectionData( const OTableConnectionData& rConnData )
+{
+ *this = rConnData;
+}
+
+void OTableConnectionData::CopyFrom(const OTableConnectionData& rSource)
+{
+ *this = rSource;
+ // here I revert to the (non-virtual) operator =, which only copies my members
+}
+
+OTableConnectionData::~OTableConnectionData()
+{
+ // delete LineDataList
+ OConnectionLineDataVec().swap(m_vConnLineData);
+}
+
+OTableConnectionData& OTableConnectionData::operator=( const OTableConnectionData& rConnData )
+{
+ if (&rConnData == this)
+ return *this;
+
+ m_pReferencingTable = rConnData.m_pReferencingTable;
+ m_pReferencedTable = rConnData.m_pReferencedTable;
+ m_aConnName = rConnData.m_aConnName;
+
+ // clear line list
+ ResetConnLines();
+
+ // and copy
+ for (auto const& elem : rConnData.GetConnLineDataList())
+ m_vConnLineData.push_back(new OConnectionLineData(*elem));
+
+ return *this;
+}
+
+void OTableConnectionData::SetConnLine( sal_uInt16 nIndex, const OUString& rSourceFieldName, const OUString& rDestFieldName )
+{
+ if (sal_uInt16(m_vConnLineData.size()) < nIndex)
+ return;
+
+ // == still allowed, this corresponds to an Append
+
+ if (m_vConnLineData.size() == nIndex)
+ {
+ AppendConnLine(rSourceFieldName, rDestFieldName);
+ return;
+ }
+
+ OConnectionLineDataRef pConnLineData = m_vConnLineData[nIndex];
+ OSL_ENSURE(pConnLineData != nullptr, "OTableConnectionData::SetConnLine : have invalid LineData object");
+
+ pConnLineData->SetSourceFieldName( rSourceFieldName );
+ pConnLineData->SetDestFieldName( rDestFieldName );
+}
+
+bool OTableConnectionData::AppendConnLine( const OUString& rSourceFieldName, const OUString& rDestFieldName )
+{
+ for (auto const& elem : m_vConnLineData)
+ {
+ if(elem->GetDestFieldName() == rDestFieldName && elem->GetSourceFieldName() == rSourceFieldName)
+ return true;
+ }
+ OConnectionLineDataRef pNew = new OConnectionLineData(rSourceFieldName, rDestFieldName);
+ if (!pNew.is())
+ return false;
+
+ m_vConnLineData.push_back(pNew);
+ return true;
+}
+
+void OTableConnectionData::ResetConnLines()
+{
+ OConnectionLineDataVec().swap(m_vConnLineData);
+}
+
+std::shared_ptr<OTableConnectionData> OTableConnectionData::NewInstance() const
+{
+ return std::make_shared<OTableConnectionData>();
+}
+
+OConnectionLineDataVec::size_type OTableConnectionData::normalizeLines()
+{
+ // remove empty lines
+ OConnectionLineDataVec::size_type nCount = m_vConnLineData.size();
+ OConnectionLineDataVec::size_type nRet = nCount;
+ for(OConnectionLineDataVec::size_type i = 0; i < nCount;)
+ {
+ if(m_vConnLineData[i]->GetSourceFieldName().isEmpty() && m_vConnLineData[i]->GetDestFieldName().isEmpty())
+ {
+ m_vConnLineData.erase(m_vConnLineData.begin()+i);
+ --nCount;
+ if (i < nRet)
+ nRet=i;
+ }
+ else
+ ++i;
+ }
+ return nRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableFieldDescription.cxx b/dbaccess/source/ui/querydesign/TableFieldDescription.cxx
new file mode 100644
index 000000000..1e8604181
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableFieldDescription.cxx
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableFieldDescription.hxx>
+
+#include <osl/diagnose.h>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace comphelper;
+using namespace dbaui;
+
+OTableFieldDesc::OTableFieldDesc()
+ :m_pTabWindow(nullptr)
+ ,m_eDataType(1000)
+ ,m_eFunctionType( FKT_NONE )
+ ,m_eFieldType(TAB_NORMAL_FIELD)
+ ,m_eOrderDir( ORDER_NONE )
+ ,m_nIndex(0)
+ ,m_nColWidth(0)
+ ,m_nColumnId(sal_uInt16(-1))
+ ,m_bGroupBy(false)
+ ,m_bVisible(false)
+{
+}
+
+OTableFieldDesc::OTableFieldDesc(const OTableFieldDesc& rRS)
+ : ::salhelper::SimpleReferenceObject()
+ , m_pTabWindow(nullptr)
+{
+ *this = rRS;
+}
+
+OTableFieldDesc::OTableFieldDesc(const OUString& rT, const OUString& rF )
+ :m_pTabWindow(nullptr)
+ ,m_eDataType(1000)
+ ,m_eFunctionType( FKT_NONE )
+ ,m_eFieldType(TAB_NORMAL_FIELD)
+ ,m_eOrderDir( ORDER_NONE )
+ ,m_nIndex(0)
+ ,m_nColWidth(0)
+ ,m_nColumnId(sal_uInt16(-1))
+ ,m_bGroupBy(false)
+ ,m_bVisible(false)
+{
+ SetField( rF ); SetTable( rT );
+}
+
+OTableFieldDesc::~OTableFieldDesc()
+{
+}
+
+OTableFieldDesc& OTableFieldDesc::operator=( const OTableFieldDesc& rRS )
+{
+ if (&rRS == this)
+ return *this;
+
+ m_aCriteria = rRS.GetCriteria();
+ m_aTableName = rRS.GetTable();
+ m_aAliasName = rRS.GetAlias(); // table range
+ m_aFieldName = rRS.GetField(); // column
+ m_aFieldAlias = rRS.GetFieldAlias(); // column alias
+ m_aFunctionName = rRS.GetFunction();
+ m_pTabWindow = rRS.GetTabWindow();
+ m_eDataType = rRS.GetDataType();
+ m_eFunctionType = rRS.GetFunctionType();
+ m_eFieldType = rRS.GetFieldType();
+ m_eOrderDir = rRS.GetOrderDir();
+ m_nIndex = rRS.GetFieldIndex();
+ m_nColWidth = rRS.GetColWidth();
+ m_nColumnId = rRS.m_nColumnId;
+ m_bGroupBy = rRS.IsGroupBy();
+ m_bVisible = rRS.IsVisible();
+
+ return *this;
+}
+
+void OTableFieldDesc::SetCriteria( sal_uInt16 nIdx, const OUString& rCrit)
+{
+ if (nIdx < m_aCriteria.size())
+ m_aCriteria[nIdx] = rCrit;
+ else
+ {
+ m_aCriteria.insert(m_aCriteria.end(), nIdx - m_aCriteria.size(), OUString());
+ m_aCriteria.push_back(rCrit);
+ }
+}
+
+OUString OTableFieldDesc::GetCriteria( sal_uInt16 nIdx ) const
+{
+ OUString aRetStr;
+ if( nIdx < m_aCriteria.size())
+ aRetStr = m_aCriteria[nIdx];
+
+ return aRetStr;
+}
+
+namespace
+{
+ struct SelectPropertyValueAsString
+ {
+ OUString operator()( const PropertyValue& i_rPropValue ) const
+ {
+ OUString sValue;
+ OSL_VERIFY( i_rPropValue.Value >>= sValue );
+ return sValue;
+ }
+ };
+}
+
+void OTableFieldDesc::Load( const css::beans::PropertyValue& i_rSettings, const bool i_bIncludingCriteria )
+{
+
+ ::comphelper::NamedValueCollection aFieldDesc( i_rSettings.Value );
+ m_aAliasName = aFieldDesc.getOrDefault( "AliasName", m_aAliasName );
+ m_aTableName = aFieldDesc.getOrDefault( "TableName", m_aTableName );
+ m_aFieldName = aFieldDesc.getOrDefault( "FieldName", m_aFieldName );
+ m_aFieldAlias = aFieldDesc.getOrDefault( "FieldAlias", m_aFieldAlias );
+ m_aFunctionName = aFieldDesc.getOrDefault( "FunctionName", m_aFunctionName );
+ m_eDataType = aFieldDesc.getOrDefault( "DataType", m_eDataType );
+ m_eFunctionType = aFieldDesc.getOrDefault( "FunctionType", m_eFunctionType );
+ m_nColWidth = aFieldDesc.getOrDefault( "ColWidth", m_nColWidth );
+ m_bGroupBy = aFieldDesc.getOrDefault( "GroupBy", m_bGroupBy );
+ m_bVisible = aFieldDesc.getOrDefault( "Visible", m_bVisible );
+
+ m_eFieldType = static_cast< ETableFieldType >( aFieldDesc.getOrDefault( "FieldType", static_cast< sal_Int32 >( m_eFieldType ) ) );
+ m_eOrderDir = static_cast< EOrderDir >( aFieldDesc.getOrDefault( "OrderDir", static_cast< sal_Int32 >( m_eOrderDir ) ) );
+
+ if ( i_bIncludingCriteria )
+ {
+ const Sequence< PropertyValue > aCriteria( aFieldDesc.getOrDefault( "Criteria", Sequence< PropertyValue >() ) );
+ m_aCriteria.resize( aCriteria.getLength() );
+ std::transform(
+ aCriteria.begin(),
+ aCriteria.end(),
+ m_aCriteria.begin(),
+ SelectPropertyValueAsString()
+ );
+ }
+}
+
+void OTableFieldDesc::Save( ::comphelper::NamedValueCollection& o_rSettings, const bool i_bIncludingCriteria )
+{
+
+ o_rSettings.put( "AliasName", m_aAliasName );
+ o_rSettings.put( "TableName", m_aTableName );
+ o_rSettings.put( "FieldName", m_aFieldName );
+ o_rSettings.put( "FieldAlias", m_aFieldAlias );
+ o_rSettings.put( "FunctionName", m_aFunctionName );
+ o_rSettings.put( "DataType", m_eDataType );
+ o_rSettings.put( "FunctionType", m_eFunctionType );
+ o_rSettings.put( "FieldType", static_cast<sal_Int32>(m_eFieldType) );
+ o_rSettings.put( "OrderDir", static_cast<sal_Int32>(m_eOrderDir) );
+ o_rSettings.put( "ColWidth", m_nColWidth );
+ o_rSettings.put( "GroupBy", m_bGroupBy );
+ o_rSettings.put( "Visible", m_bVisible );
+
+ if ( !i_bIncludingCriteria )
+ return;
+
+ if ( m_aCriteria.empty() )
+ return;
+
+ sal_Int32 c = 0;
+ Sequence< PropertyValue > aCriteria( m_aCriteria.size() );
+ auto pCriteria = aCriteria.getArray();
+ for (auto const& criteria : m_aCriteria)
+ {
+ pCriteria[c].Name = "Criterion_" + OUString::number( c );
+ pCriteria[c].Value <<= criteria;
+ ++c;
+ }
+
+ o_rSettings.put( "Criteria", aCriteria );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableFieldInfo.cxx b/dbaccess/source/ui/querydesign/TableFieldInfo.cxx
new file mode 100644
index 000000000..808862c11
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableFieldInfo.cxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TableFieldInfo.hxx"
+
+using namespace dbaui;
+
+OTableFieldInfo::OTableFieldInfo()
+ : m_eFieldType(TAB_NORMAL_FIELD)
+ , m_eDataType(1000)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableFieldInfo.hxx b/dbaccess/source/ui/querydesign/TableFieldInfo.hxx
new file mode 100644
index 000000000..e7d2c9b72
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableFieldInfo.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <QEnumTypes.hxx>
+#include <sal/types.h>
+
+namespace dbaui
+{
+ class OTableFieldInfo
+ {
+ private:
+ ETableFieldType m_eFieldType;
+ sal_Int32 m_eDataType;
+
+ public:
+ OTableFieldInfo();
+
+ ETableFieldType GetKeyType() const { return m_eFieldType; }
+ void SetKey(ETableFieldType bKey) { m_eFieldType = bKey; }
+ sal_Int32 GetDataType() const { return m_eDataType; }
+ void SetDataType(sal_Int32 eTyp) { m_eDataType = eTyp; }
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableWindow.cxx b/dbaccess/source/ui/querydesign/TableWindow.cxx
new file mode 100644
index 000000000..b8afc951d
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableWindow.cxx
@@ -0,0 +1,716 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableWindow.hxx>
+#include <TableWindowListBox.hxx>
+#include <TableWindowData.hxx>
+#include <imageprovider.hxx>
+#include <JoinController.hxx>
+#include <JoinTableView.hxx>
+#include <JoinDesignView.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/wall.hxx>
+#include <vcl/weldutils.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <bitmaps.hlst>
+#include <TableWindowAccess.hxx>
+#include <connectivity/dbtools.hxx>
+
+using namespace dbaui;
+using namespace ::utl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::accessibility;
+
+namespace DatabaseObject = css::sdb::application::DatabaseObject;
+
+#define TABWIN_SIZING_AREA 4
+#define TABWIN_WIDTH_MIN 90
+#define TABWIN_HEIGHT_MIN 80
+
+namespace {
+
+void Draw3DBorder(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ // Use the System Style-Settings for my colours
+ const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings();
+
+ // Black lines for bottom and right
+ rRenderContext.SetLineColor(aSystemStyle.GetDarkShadowColor());
+ rRenderContext.DrawLine(rRect.BottomLeft(), rRect.BottomRight());
+ rRenderContext.DrawLine(rRect.BottomRight(), rRect.TopRight());
+
+ // Dark grey lines over the black lines
+ rRenderContext.SetLineColor(aSystemStyle.GetShadowColor());
+ Point aEHvector(1, 1);
+ rRenderContext.DrawLine(rRect.BottomLeft() + Point(1, -1), rRect.BottomRight() - aEHvector);
+ rRenderContext.DrawLine(rRect.BottomRight() - aEHvector, rRect.TopRight() + Point(-1, 1));
+
+ // Light grey lines for top and left
+ rRenderContext.SetLineColor(aSystemStyle.GetLightColor());
+ rRenderContext.DrawLine(rRect.BottomLeft() + Point(1, -2), rRect.TopLeft() + aEHvector);
+ rRenderContext.DrawLine(rRect.TopLeft() + aEHvector, rRect.TopRight() + Point(-2, 1));
+}
+
+}
+
+OTableWindow::OTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData )
+ : ::comphelper::OContainerListener(m_aMutex)
+ , Window( pParent, WB_3DLOOK|WB_MOVEABLE )
+ , m_xTitle( VclPtr<OTableWindowTitle>::Create(this) )
+ , m_pData( pTabWinData )
+ , m_nMoveCount(0)
+ , m_nMoveIncrement(1)
+ , m_nSizingFlags( SizingFlags::NONE )
+{
+ // Set position and size
+ if( GetData()->HasPosition() )
+ SetPosPixel( GetData()->GetPosition() );
+
+ if( GetData()->HasSize() )
+ SetSizePixel( GetData()->GetSize() );
+
+ // Set background
+ const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings();
+ SetBackground(Wallpaper(aSystemStyle.GetFaceColor()));
+ // Set the text colour even though there is no text,
+ // because derived classes might need it
+ SetTextColor(aSystemStyle.GetButtonTextColor());
+
+ EnableClipSiblings();
+}
+
+OTableWindow::~OTableWindow()
+{
+ disposeOnce();
+}
+
+void OTableWindow::dispose()
+{
+ if (m_xListBox)
+ {
+ OSL_ENSURE(m_xListBox->get_widget().n_children()==0,"Forgot to call EmptyListbox()!");
+ }
+ m_xListBox.disposeAndClear();
+ if ( m_pContainerListener.is() )
+ m_pContainerListener->dispose();
+
+ m_xTitle.disposeAndClear();
+ vcl::Window::dispose();
+}
+
+const OJoinTableView* OTableWindow::getTableView() const
+{
+ OSL_ENSURE(static_cast<OJoinTableView*>(GetParent()),"No OJoinTableView!");
+ return static_cast<OJoinTableView*>(GetParent());
+}
+
+OJoinTableView* OTableWindow::getTableView()
+{
+ OSL_ENSURE(static_cast<OJoinTableView*>(GetParent()),"No OJoinTableView!");
+ return static_cast<OJoinTableView*>(GetParent());
+}
+
+OJoinDesignView* OTableWindow::getDesignView()
+{
+ OSL_ENSURE(static_cast<OJoinDesignView*>(GetParent()->GetParent()->GetParent()),"No OJoinDesignView!");
+ return static_cast<OJoinDesignView*>(GetParent()->GetParent()->GetParent());
+}
+
+void OTableWindow::SetPosPixel( const Point& rNewPos )
+{
+ Point aNewPosData = rNewPos + getTableView()->GetScrollOffset();
+ GetData()->SetPosition( aNewPosData );
+ Window::SetPosPixel( rNewPos );
+}
+
+void OTableWindow::SetSizePixel( const Size& rNewSize )
+{
+ Size aOutSize(rNewSize);
+ if( aOutSize.Width() < TABWIN_WIDTH_MIN )
+ aOutSize.setWidth( TABWIN_WIDTH_MIN );
+ if( aOutSize.Height() < TABWIN_HEIGHT_MIN )
+ aOutSize.setHeight( TABWIN_HEIGHT_MIN );
+
+ GetData()->SetSize( aOutSize );
+ Window::SetSizePixel( aOutSize );
+}
+
+void OTableWindow::SetPosSizePixel( const Point& rNewPos, const Size& rNewSize )
+{
+ SetPosPixel( rNewPos );
+ SetSizePixel( rNewSize );
+}
+
+void OTableWindow::FillListBox()
+{
+ clearListBox();
+ weld::TreeView& rTreeView = m_xListBox->get_widget();
+ assert(!rTreeView.n_children());
+
+ if ( !m_pContainerListener.is() )
+ {
+ Reference< XContainer> xContainer(m_pData->getColumns(),UNO_QUERY);
+ if ( xContainer.is() )
+ m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
+ }
+
+ // mark all primary keys with special image
+ OUString aPrimKeyImage(BMP_PRIMARY_KEY);
+
+ if (GetData()->IsShowAll())
+ {
+ rTreeView.append(weld::toId(createUserData(nullptr,false)), OUString("*"));
+ }
+
+ Reference<XNameAccess> xPKeyColumns;
+ try
+ {
+ xPKeyColumns = dbtools::getPrimaryKeyColumns_throw(m_pData->getTable());
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "");
+ }
+ try
+ {
+ Reference< XNameAccess > xColumns = m_pData->getColumns();
+ if( xColumns.is() )
+ {
+ Sequence< OUString> aColumns = xColumns->getElementNames();
+ const OUString* pIter = aColumns.getConstArray();
+ const OUString* pEnd = pIter + aColumns.getLength();
+
+ for (; pIter != pEnd; ++pIter)
+ {
+ bool bPrimaryKeyColumn = xPKeyColumns.is() && xPKeyColumns->hasByName( *pIter );
+
+ OUString sId;
+ Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY);
+ if (xColumn.is())
+ sId = weld::toId(createUserData(xColumn, bPrimaryKeyColumn));
+
+ rTreeView.append(sId, *pIter);
+
+ // is this column in the primary key
+ if ( bPrimaryKeyColumn )
+ rTreeView.set_image(rTreeView.n_children() - 1, aPrimKeyImage);
+ }
+
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "");
+ }
+}
+
+void* OTableWindow::createUserData(const Reference< XPropertySet>& /*_xColumn*/,bool /*_bPrimaryKey*/)
+{
+ return nullptr;
+}
+
+void OTableWindow::deleteUserData(void*& _pUserData)
+{
+ OSL_ENSURE(!_pUserData,"INVALID call. Need to delete the userclass!");
+ _pUserData = nullptr;
+}
+
+void OTableWindow::clearListBox()
+{
+ if ( !m_xListBox )
+ return;
+
+ weld::TreeView& rTreeView = m_xListBox->get_widget();
+ rTreeView.all_foreach([this, &rTreeView](weld::TreeIter& rEntry){
+ void* pUserData = weld::fromId<void*>(rTreeView.get_id(rEntry));
+ deleteUserData(pUserData);
+ return false;
+ });
+
+ rTreeView.clear();
+}
+
+void OTableWindow::impl_updateImage()
+{
+ weld::Image& rImage = m_xTitle->GetImage();
+ ImageProvider aImageProvider( getDesignView()->getController().getConnection() );
+ rImage.set_from_icon_name(aImageProvider.getImageId(GetComposedName(), m_pData->isQuery() ? DatabaseObject::QUERY : DatabaseObject::TABLE));
+ rImage.show();
+}
+
+bool OTableWindow::Init()
+{
+ // create list box if necessary
+ if ( !m_xListBox )
+ {
+ m_xListBox = VclPtr<OTableWindowListBox>::Create(this);
+ assert(m_xListBox && "OTableWindow::Init() : CreateListBox returned NULL !");
+ m_xListBox->get_widget().set_selection_mode(SelectionMode::Multiple);
+ }
+
+ // Set the title
+ weld::Label& rLabel = m_xTitle->GetLabel();
+ rLabel.set_label(m_pData->GetWinName());
+ rLabel.set_tooltip_text(GetComposedName());
+ m_xTitle->Show();
+
+ m_xListBox->Show();
+
+ // add the fields to the ListBox
+ FillListBox();
+ m_xListBox->get_widget().unselect_all();
+
+ impl_updateImage();
+
+ return true;
+}
+
+void OTableWindow::DataChanged(const DataChangedEvent& rDCEvt)
+{
+ if (rDCEvt.GetType() == DataChangedEventType::SETTINGS)
+ {
+ // In the worst-case the colours have changed so
+ // adapt myself to the new colours
+ const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings();
+ SetBackground(Wallpaper(aSystemStyle.GetFaceColor()));
+ SetTextColor(aSystemStyle.GetButtonTextColor());
+ }
+}
+
+void OTableWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ tools::Rectangle aRect(Point(0,0), GetOutputSizePixel());
+ Window::Paint(rRenderContext, rRect);
+ Draw3DBorder(rRenderContext, aRect);
+}
+
+tools::Rectangle OTableWindow::getSizingRect(const Point& _rPos,const Size& _rOutputSize) const
+{
+ tools::Rectangle aSizingRect( GetPosPixel(), GetSizePixel() );
+
+ if( m_nSizingFlags & SizingFlags::Top )
+ {
+ if( _rPos.Y() < 0 )
+ aSizingRect.SetTop( 0 );
+ else
+ aSizingRect.SetTop( _rPos.Y() );
+ }
+
+ if( m_nSizingFlags & SizingFlags::Bottom )
+ {
+ if( _rPos.Y() > _rOutputSize.Height() )
+ aSizingRect.SetBottom( _rOutputSize.Height() );
+ else
+ aSizingRect.SetBottom( _rPos.Y() );
+ }
+
+ if( m_nSizingFlags & SizingFlags::Right )
+ {
+ if( _rPos.X() > _rOutputSize.Width() )
+ aSizingRect.SetRight( _rOutputSize.Width() );
+ else
+ aSizingRect.SetRight( _rPos.X() );
+ }
+
+ if( m_nSizingFlags & SizingFlags::Left )
+ {
+ if( _rPos.X() < 0 )
+ aSizingRect.SetLeft( 0 );
+ else
+ aSizingRect.SetLeft( _rPos.X() );
+ }
+ return aSizingRect;
+}
+
+void OTableWindow::setSizingFlag(const Point& _rPos)
+{
+ Size aOutSize = GetOutputSizePixel();
+ // Set the flags when the mouse cursor is in the sizing area
+ m_nSizingFlags = SizingFlags::NONE;
+
+ if( _rPos.X() < TABWIN_SIZING_AREA )
+ m_nSizingFlags |= SizingFlags::Left;
+
+ if( _rPos.Y() < TABWIN_SIZING_AREA )
+ m_nSizingFlags |= SizingFlags::Top;
+
+ if( _rPos.X() > aOutSize.Width()-TABWIN_SIZING_AREA )
+ m_nSizingFlags |= SizingFlags::Right;
+
+ if( _rPos.Y() > aOutSize.Height()-TABWIN_SIZING_AREA )
+ m_nSizingFlags |= SizingFlags::Bottom;
+}
+
+void OTableWindow::MouseMove( const MouseEvent& rEvt )
+{
+ Window::MouseMove(rEvt);
+
+ OJoinTableView* pCont = getTableView();
+ if (pCont->getDesignView()->getController().isReadOnly())
+ return;
+
+ Point aPos = rEvt.GetPosPixel();
+ setSizingFlag(aPos);
+ PointerStyle aPointer = PointerStyle::Arrow;
+
+ // Set the mouse cursor when it is in the sizing area
+ if ( m_nSizingFlags == SizingFlags::Top ||
+ m_nSizingFlags == SizingFlags::Bottom )
+ aPointer = PointerStyle::SSize;
+ else if ( m_nSizingFlags == SizingFlags::Left ||
+ m_nSizingFlags ==SizingFlags::Right )
+ aPointer = PointerStyle::ESize;
+ else if ( m_nSizingFlags == (SizingFlags::Left | SizingFlags::Top) ||
+ m_nSizingFlags == (SizingFlags::Right | SizingFlags::Bottom) )
+ aPointer = PointerStyle::SESize;
+ else if ( m_nSizingFlags == (SizingFlags::Right | SizingFlags::Top) ||
+ m_nSizingFlags == (SizingFlags::Left | SizingFlags::Bottom) )
+ aPointer = PointerStyle::NESize;
+
+ SetPointer( aPointer );
+}
+
+void OTableWindow::MouseButtonDown( const MouseEvent& rEvt )
+{
+ // When resizing, the parent must be informed that
+ // the window size of its child has changed
+ if( m_nSizingFlags != SizingFlags::NONE )
+ getTableView()->BeginChildSizing( this, GetPointer() );
+
+ Window::MouseButtonDown( rEvt );
+}
+
+void OTableWindow::Resize()
+{
+ // The window must not disappear so we enforce a minimum size
+ Size aOutSize = GetOutputSizePixel();
+ aOutSize = Size(CalcZoom(aOutSize.Width()),CalcZoom(aOutSize.Height()));
+
+ tools::Long nTitleHeight = CalcZoom( GetTextHeight() )+ CalcZoom( 4 );
+
+ // Set the title and ListBox
+ tools::Long n5Pos = CalcZoom(5);
+ tools::Long nPositionX = n5Pos;
+ tools::Long nPositionY = n5Pos;
+
+ Size aPreferredSize = m_xTitle->get_preferred_size();
+ if (nTitleHeight < aPreferredSize.Height())
+ nTitleHeight = aPreferredSize.Height();
+
+ m_xTitle->SetPosSizePixel( Point( nPositionX, nPositionY ), Size( aOutSize.Width() - nPositionX - n5Pos, nTitleHeight ) );
+
+ tools::Long nTitleToList = CalcZoom( 3 );
+
+ m_xListBox->SetPosSizePixel(
+ Point( n5Pos, nPositionY + nTitleHeight + nTitleToList ),
+ Size( aOutSize.Width() - 2 * n5Pos, aOutSize.Height() - ( nPositionY + nTitleHeight + nTitleToList ) - n5Pos )
+ );
+
+ Window::Invalidate();
+}
+
+void OTableWindow::SetBoldTitle( bool bBold )
+{
+ weld::Label& rLabel = m_xTitle->GetLabel();
+ vcl::Font aFont = rLabel.get_font();
+ aFont.SetWeight(bBold ? WEIGHT_BOLD : WEIGHT_NORMAL);
+ rLabel.set_font(aFont);
+}
+
+void OTableWindow::GetFocus()
+{
+ Window::GetFocus();
+ // we have to forward the focus to our listbox to enable keystrokes
+ if(m_xListBox)
+ m_xListBox->GrabFocus();
+}
+
+void OTableWindow::setActive(bool _bActive)
+{
+ SetBoldTitle( _bActive );
+ if (_bActive || !m_xListBox)
+ return;
+
+ weld::TreeView& rTreeView = m_xListBox->get_widget();
+ if (rTreeView.get_selected_index() != -1)
+ rTreeView.unselect_all();
+}
+
+void OTableWindow::Remove()
+{
+ // Delete the window
+ OJoinTableView* pTabWinCont = getTableView();
+ VclPtr<OTableWindow> aHoldSelf(this); // keep ourselves alive during the RemoveTabWin process
+ pTabWinCont->RemoveTabWin( this );
+ pTabWinCont->Invalidate();
+}
+
+bool OTableWindow::ExistsAConn() const
+{
+ return getTableView()->ExistsAConn(this);
+}
+
+void OTableWindow::EnumValidFields(std::vector< OUString>& arrstrFields)
+{
+ arrstrFields.clear();
+ weld::TreeView& rTreeView = m_xListBox->get_widget();
+
+ // This default implementation counts every item in the ListBox ... for any other behaviour it must be over-written
+ rTreeView.all_foreach([&rTreeView, &arrstrFields](weld::TreeIter& rEntry){
+ arrstrFields.push_back(rTreeView.get_text(rEntry));
+ return false;
+ });
+}
+
+void OTableWindow::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ // FIXME RenderContext
+
+ if ( nType != StateChangedType::Zoom )
+ return;
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ vcl::Font aFont = rStyleSettings.GetGroupFont();
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ SetZoomedPointFont(*GetOutDev(), aFont);
+
+ m_xTitle->SetZoom(GetZoom());
+ m_xListBox->SetZoom(GetZoom());
+ Resize();
+ Invalidate();
+}
+
+Reference< XAccessible > OTableWindow::CreateAccessible()
+{
+ return new OTableWindowAccess(this);
+}
+
+void OTableWindow::Command(const CommandEvent& rEvt)
+{
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ OJoinController& rController = getDesignView()->getController();
+ if(!rController.isReadOnly() && rController.isConnected())
+ {
+ Point ptWhere;
+ if ( rEvt.IsMouseEvent() )
+ ptWhere = rEvt.GetMousePosPixel();
+ else
+ {
+ weld::TreeView& rTreeView = m_xListBox->get_widget();
+ std::unique_ptr<weld::TreeIter> xCurrent = rTreeView.make_iterator();
+ if (rTreeView.get_cursor(xCurrent.get()))
+ ptWhere = rTreeView.get_row_area(*xCurrent).Center();
+ else
+ ptWhere = m_xTitle->GetPosPixel();
+ }
+
+ ::tools::Rectangle aRect(ptWhere, Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/jointablemenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ if (!xContextMenu->popup_at_rect(pPopupParent, aRect).isEmpty())
+ Remove();
+ }
+ break;
+ }
+ default:
+ Window::Command(rEvt);
+ }
+}
+
+bool OTableWindow::PreNotify(NotifyEvent& rNEvt)
+{
+ bool bHandled = false;
+ switch (rNEvt.GetType())
+ {
+ case MouseNotifyEvent::KEYINPUT:
+ {
+ if ( getDesignView()->getController().isReadOnly() )
+ break;
+
+ const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent();
+ const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode();
+ if ( rCode.IsMod1() )
+ {
+ Point aStartPoint = GetPosPixel();
+ if ( rCode.IsShift() )
+ {
+ aStartPoint.setX( GetSizePixel().Width() );
+ aStartPoint.setY( GetSizePixel().Height() );
+ }
+
+ switch( rCode.GetCode() )
+ {
+ case KEY_DOWN:
+ bHandled = true;
+ aStartPoint.AdjustY(m_nMoveIncrement );
+ break;
+ case KEY_UP:
+ bHandled = true;
+ aStartPoint.AdjustY(-m_nMoveIncrement );
+ break;
+ case KEY_LEFT:
+ bHandled = true;
+ aStartPoint.AdjustX(-m_nMoveIncrement );
+ break;
+ case KEY_RIGHT:
+ bHandled = true;
+ aStartPoint.AdjustX(m_nMoveIncrement );
+ break;
+ }
+ if ( bHandled )
+ {
+ if ( rCode.IsShift() )
+ {
+ OJoinTableView* pView = getTableView();
+ Point ptOld = GetPosPixel();
+ Size aSize = pView->getRealOutputSize();
+ Size aNewSize(aStartPoint.X(),aStartPoint.Y());
+ if ( ((ptOld.X() + aNewSize.Width()) <= aSize.Width())
+ && ((ptOld.Y() + aNewSize.Height()) <= aSize.Height()) )
+ {
+ if ( aNewSize.Width() < TABWIN_WIDTH_MIN )
+ aNewSize.setWidth( TABWIN_WIDTH_MIN );
+ if ( aNewSize.Height() < TABWIN_HEIGHT_MIN )
+ aNewSize.setHeight( TABWIN_HEIGHT_MIN );
+
+ Size szOld = GetSizePixel();
+
+ aNewSize = Size(pView->CalcZoom(aNewSize.Width()),pView->CalcZoom(aNewSize.Height()));
+ SetPosSizePixel( ptOld, aNewSize );
+ pView->TabWinSized(this, ptOld, szOld);
+ Invalidate( InvalidateFlags::NoChildren );
+ }
+ }
+ else
+ {
+ // remember how often the user moved our window
+ ++m_nMoveCount;
+ if( m_nMoveCount == 5 )
+ m_nMoveIncrement = 10;
+ else if( m_nMoveCount > 15 )
+ m_nMoveCount = m_nMoveIncrement = 20;
+
+ Point aOldDataPoint = GetData()->GetPosition();
+ Point aNewDataPoint = aStartPoint + getTableView()->GetScrollOffset();
+ if ( aNewDataPoint.X() > -1 && aNewDataPoint.Y() > -1 )
+ {
+ OJoinTableView* pView = getTableView();
+ if ( pView->isMovementAllowed(aNewDataPoint, GetData()->GetSize()) )
+ {
+ SetPosPixel(aStartPoint);
+
+ // aNewDataPoint can not be used here because SetPosPixel reset it
+ pView->EnsureVisible(GetData()->GetPosition(), GetData()->GetSize());
+ pView->TabWinMoved(this,aOldDataPoint);
+ Invalidate(InvalidateFlags::NoChildren);
+ getDesignView()->getController().setModified( true );
+ }
+ else
+ {
+ m_nMoveCount = 0; // reset our movement count
+ m_nMoveIncrement = 1;
+ }
+ }
+ else
+ {
+ m_nMoveCount = 0; // reset our movement count
+ m_nMoveIncrement = 1;
+ }
+ }
+ m_nSizingFlags = SizingFlags::NONE;
+ }
+ else
+ {
+ m_nMoveCount = 0; // reset our movement count
+ m_nMoveIncrement = 1;
+ }
+ }
+ else
+ {
+ m_nMoveCount = 0; // reset our movement count
+ m_nMoveIncrement = 1;
+ }
+ break;
+ }
+ case MouseNotifyEvent::KEYUP:
+ {
+ const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent();
+ const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode();
+ sal_uInt16 nKeyCode = rCode.GetCode();
+ if ( rCode.IsMod2() && nKeyCode != KEY_UP && nKeyCode != KEY_DOWN && nKeyCode != KEY_LEFT && nKeyCode != KEY_RIGHT )
+ {
+ m_nMoveCount = 0; // reset our movement count
+ m_nMoveIncrement = 1;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (!bHandled)
+ return Window::PreNotify(rNEvt);
+ return true;
+}
+
+OUString OTableWindow::getTitle() const
+{
+ return m_xTitle->GetLabel().get_label();
+}
+
+void OTableWindow::_elementInserted( const container::ContainerEvent& /*_rEvent*/ )
+{
+ FillListBox();
+}
+
+void OTableWindow::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ )
+{
+ FillListBox();
+}
+
+void OTableWindow::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ )
+{
+ FillListBox();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableWindowAccess.cxx b/dbaccess/source/ui/querydesign/TableWindowAccess.cxx
new file mode 100644
index 000000000..787d257b5
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableWindowAccess.cxx
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableWindowAccess.hxx>
+#include <TableWindow.hxx>
+#include <TableWindowListBox.hxx>
+#include <JoinTableView.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/sequence.hxx>
+#include <vcl/vclevent.hxx>
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::accessibility;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star;
+
+ OTableWindowAccess::OTableWindowAccess(OTableWindow* _pTable)
+ :VCLXAccessibleComponent(_pTable->GetComponentInterface().is() ? _pTable->GetWindowPeer() : nullptr)
+ ,m_pTable(_pTable)
+ {
+ }
+ void SAL_CALL OTableWindowAccess::disposing()
+ {
+ m_pTable = nullptr;
+ VCLXAccessibleComponent::disposing();
+ }
+ void OTableWindowAccess::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
+ {
+ if ( rVclWindowEvent.GetId() == VclEventId::ObjectDying )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_pTable = nullptr;
+ }
+
+ VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
+ }
+ Any SAL_CALL OTableWindowAccess::queryInterface( const Type& aType )
+ {
+ Any aRet(VCLXAccessibleComponent::queryInterface( aType ));
+ return aRet.hasValue() ? aRet : OTableWindowAccess_BASE::queryInterface( aType );
+ }
+ Sequence< Type > SAL_CALL OTableWindowAccess::getTypes( )
+ {
+ return ::comphelper::concatSequences(VCLXAccessibleComponent::getTypes(),OTableWindowAccess_BASE::getTypes());
+ }
+ OUString SAL_CALL OTableWindowAccess::getImplementationName()
+ {
+ return "org.openoffice.comp.dbu.TableWindowAccessibility";
+ }
+ Sequence< OUString > SAL_CALL OTableWindowAccess::getSupportedServiceNames()
+ {
+ return { "com.sun.star.accessibility.Accessible",
+ "com.sun.star.accessibility.AccessibleContext" };
+ }
+ // XAccessibleContext
+ sal_Int32 SAL_CALL OTableWindowAccess::getAccessibleChildCount( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ sal_Int32 nCount = 0;
+ if(m_pTable)
+ {
+ ++nCount;
+ if(m_pTable->GetListBox())
+ ++nCount;
+ }
+ return nCount;
+ }
+ Reference< XAccessible > SAL_CALL OTableWindowAccess::getAccessibleChild( sal_Int32 i )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XAccessible > aRet;
+ if (m_pTable && !m_pTable->isDisposed())
+ {
+ switch(i)
+ {
+ case 0:
+ {
+ VclPtr<OTableWindowTitle> xCtrl(m_pTable->GetTitleCtrl());
+ if (xCtrl)
+ aRet = xCtrl->GetAccessible();
+ break;
+ }
+ case 1:
+ {
+ VclPtr<OTableWindowListBox> xCtrl(m_pTable->GetListBox());
+ if (xCtrl)
+ aRet = xCtrl->GetAccessible();
+ break;
+ }
+ default:
+ throw IndexOutOfBoundsException();
+ }
+ }
+ return aRet;
+ }
+ sal_Int32 SAL_CALL OTableWindowAccess::getAccessibleIndexInParent( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ sal_Int32 nIndex = -1;
+ if( m_pTable )
+ {
+ // search the position of our table window in the table window map
+ bool bFoundElem = false;
+ for (auto const& tabWin : m_pTable->getTableView()->GetTabWinMap())
+ {
+ if (tabWin.second == m_pTable)
+ {
+ bFoundElem = true;
+ break;
+ }
+ ++nIndex;
+ }
+ nIndex = bFoundElem? nIndex : -1;
+ }
+ return nIndex;
+ }
+ sal_Int16 SAL_CALL OTableWindowAccess::getAccessibleRole( )
+ {
+ return AccessibleRole::PANEL; // ? or may be an AccessibleRole::WINDOW
+ }
+ Reference< XAccessibleRelationSet > SAL_CALL OTableWindowAccess::getAccessibleRelationSet( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return this;
+ }
+ // XAccessibleComponent
+ Reference< XAccessible > SAL_CALL OTableWindowAccess::getAccessibleAtPoint( const awt::Point& _aPoint )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XAccessible > aRet;
+ if(m_pTable && !m_pTable->isDisposed())
+ {
+ Point aPoint(_aPoint.X,_aPoint.Y);
+ tools::Rectangle aRect(m_pTable->GetDesktopRectPixel());
+ if( aRect.Contains(aPoint) )
+ aRet = this;
+ else if( m_pTable->GetListBox()->GetDesktopRectPixel().Contains(aPoint))
+ aRet = m_pTable->GetListBox()->GetAccessible();
+ }
+ return aRet;
+ }
+ Reference< XAccessible > OTableWindowAccess::getParentChild(sal_Int32 _nIndex)
+ {
+ Reference< XAccessible > xReturn;
+ Reference< XAccessible > xParent = getAccessibleParent();
+ if ( xParent.is() )
+ {
+ Reference< XAccessibleContext > xParentContext = xParent->getAccessibleContext();
+ if ( xParentContext.is() )
+ {
+ xReturn = xParentContext->getAccessibleChild(_nIndex);
+ }
+ }
+ return xReturn;
+ }
+
+ sal_Int32 SAL_CALL OTableWindowAccess::getRelationCount( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return m_pTable ? m_pTable->getTableView()->getConnectionCount(m_pTable) : sal_Int32(0);
+ }
+ AccessibleRelation SAL_CALL OTableWindowAccess::getRelation( sal_Int32 nIndex )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( nIndex < 0 || nIndex >= getRelationCount() )
+ throw IndexOutOfBoundsException();
+
+ AccessibleRelation aRet;
+ if( m_pTable )
+ {
+ OJoinTableView* pView = m_pTable->getTableView();
+ auto aIter = pView->getTableConnections(m_pTable) + nIndex;
+ aRet.TargetSet = { getParentChild(aIter - pView->getTableConnections().begin()) };
+ aRet.RelationType = AccessibleRelationType::CONTROLLER_FOR;
+ }
+ return aRet;
+ }
+ sal_Bool SAL_CALL OTableWindowAccess::containsRelation( sal_Int16 aRelationType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return AccessibleRelationType::CONTROLLER_FOR == aRelationType
+ && m_pTable && m_pTable->getTableView()->ExistsAConn(m_pTable);
+ }
+ AccessibleRelation SAL_CALL OTableWindowAccess::getRelationByType( sal_Int16 aRelationType )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( AccessibleRelationType::CONTROLLER_FOR == aRelationType && m_pTable)
+ {
+ OJoinTableView* pView = m_pTable->getTableView();
+ const auto& rConnectionList = pView->getTableConnections();
+
+ auto aIter = pView->getTableConnections(m_pTable);
+ auto aEnd = rConnectionList.end();
+ std::vector< Reference<XInterface> > aRelations;
+ aRelations.reserve(5); // just guessing
+ // TODO JNA aIter comes from pView->getTableConnections(m_pTable)
+ // and aEnd comes from pView->getTableConnections().end()
+ for (; aIter != aEnd ; ++aIter )
+ {
+ uno::Reference<uno::XInterface> xInterface(
+ getParentChild(aIter - rConnectionList.begin()));
+ aRelations.push_back(xInterface);
+ }
+
+ Sequence< Reference<XInterface> > aSeq(aRelations.data(), aRelations.size());
+ return AccessibleRelation(AccessibleRelationType::CONTROLLER_FOR,aSeq);
+ }
+ return AccessibleRelation();
+ }
+ OUString SAL_CALL OTableWindowAccess::getTitledBorderText( )
+ {
+ return getAccessibleName( );
+ }
+ OUString SAL_CALL OTableWindowAccess::getAccessibleName( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OUString sAccessibleName;
+ if ( m_pTable )
+ sAccessibleName = m_pTable->getTitle();
+ return sAccessibleName;
+ }
+ Reference< XAccessibleContext > SAL_CALL OTableWindowAccess::getAccessibleContext( )
+ {
+ return this;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableWindowData.cxx b/dbaccess/source/ui/querydesign/TableWindowData.cxx
new file mode 100644
index 000000000..d07c8214a
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableWindowData.cxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableWindowData.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+
+using namespace dbaui;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+OTableWindowData::OTableWindowData( const Reference< XPropertySet>& _xTable
+ ,const OUString& _rComposedName
+ ,const OUString& rTableName
+ ,const OUString& rWinName )
+ :m_xTable(_xTable)
+ ,m_aTableName( rTableName )
+ ,m_aWinName( rWinName )
+ ,m_sComposedName(_rComposedName)
+ ,m_aPosition( Point(-1,-1) )
+ ,m_aSize( Size(-1,-1) )
+ ,m_bShowAll( true )
+ ,m_bIsQuery(false)
+ ,m_bIsValid(true)
+{
+ if( m_aWinName.isEmpty() )
+ m_aWinName = m_aTableName;
+
+ listen();
+}
+
+OTableWindowData::~OTableWindowData()
+{
+ Reference<XComponent> xComponent( m_xTable, UNO_QUERY );
+ if ( xComponent.is() )
+ stopComponentListening( xComponent );
+}
+
+bool OTableWindowData::HasPosition() const
+{
+ return ( (m_aPosition.X() != -1) && (m_aPosition.Y() != -1) );
+}
+
+bool OTableWindowData::HasSize() const
+{
+ return ( (m_aSize.Width() != -1) && (m_aSize.Height() !=-1) );
+}
+
+void OTableWindowData::_disposing( const css::lang::EventObject& /*_rSource*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // it doesn't matter which one was disposed
+ m_xColumns.clear();
+ m_xKeys.clear();
+ m_xTable.clear();
+}
+
+bool OTableWindowData::init(const Reference< XConnection >& _xConnection,bool _bAllowQueries)
+{
+ OSL_ENSURE(!m_xTable.is(),"We are already connected to a table!");
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XQueriesSupplier > xSupQueries( _xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSupQueries->getQueries(), UNO_SET_THROW );
+ bool bIsKnownQuery = _bAllowQueries && xQueries->hasByName( m_sComposedName );
+
+ Reference< XTablesSupplier > xSupTables( _xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xTables( xSupTables->getTables(), UNO_SET_THROW );
+ bool bIsKnownTable = xTables->hasByName( m_sComposedName );
+
+ if ( bIsKnownQuery )
+ m_xTable.set( xQueries->getByName( m_sComposedName ), UNO_QUERY );
+ else if ( bIsKnownTable )
+ m_xTable.set( xTables->getByName( m_sComposedName ), UNO_QUERY );
+ else
+ m_bIsValid = false;
+
+ // if we survived so far, we know whether it's a query
+ m_bIsQuery = bIsKnownQuery;
+
+ listen();
+
+ Reference< XIndexAccess > xColumnsAsIndex( m_xColumns,UNO_QUERY );
+ return xColumnsAsIndex.is() && ( xColumnsAsIndex->getCount() > 0 );
+}
+
+void OTableWindowData::listen()
+{
+ if ( !m_xTable.is() )
+ return;
+
+ // listen for the object being disposed
+ Reference<XComponent> xComponent( m_xTable, UNO_QUERY );
+ if ( xComponent.is() )
+ startComponentListening( xComponent );
+
+ // obtain the columns
+ Reference< XColumnsSupplier > xColumnsSups( m_xTable, UNO_QUERY);
+ if ( xColumnsSups.is() )
+ m_xColumns = xColumnsSups->getColumns();
+
+ Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY);
+ if ( xKeySup.is() )
+ m_xKeys = xKeySup->getKeys();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableWindowListBox.cxx b/dbaccess/source/ui/querydesign/TableWindowListBox.cxx
new file mode 100644
index 000000000..3066f8429
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableWindowListBox.cxx
@@ -0,0 +1,292 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableWindowListBox.hxx>
+#include <TableWindow.hxx>
+#include <JoinController.hxx>
+#include <JoinExchange.hxx>
+#include <JoinTableView.hxx>
+#include <JoinDesignView.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <vcl/svapp.hxx>
+#include <vcl/commandevent.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::datatransfer;
+
+OJoinExchangeData::OJoinExchangeData(OTableWindowListBox* pBox)
+ : pListBox(pBox)
+ , nEntry(pBox->get_widget().get_selected_index())
+{
+}
+
+OTableWindowListBox::OTableWindowListBox(OTableWindow* pParent)
+ : InterimItemWindow(pParent, "dbaccess/ui/tablelistbox.ui", "TableListBox")
+ , m_xTreeView(m_xBuilder->weld_tree_view("treeview"))
+ , m_xDragDropTargetHelper(new TableWindowListBoxHelper(*this, m_xTreeView->get_drop_target()))
+ , m_pTabWin(pParent)
+ , m_nDropEvent(nullptr)
+ , m_nUiEvent(nullptr)
+{
+ m_xTreeView->connect_row_activated(LINK(this, OTableWindowListBox, OnDoubleClick));
+ m_xTreeView->connect_visible_range_changed(LINK(this, OTableWindowListBox, ScrollHdl));
+ m_xTreeView->connect_popup_menu(LINK(this, OTableWindowListBox, CommandHdl));
+
+ m_xHelper.set(new OJoinExchObj);
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ m_xTreeView->enable_drag_source(xHelper, DND_ACTION_LINK);
+ m_xTreeView->connect_drag_begin(LINK(this, OTableWindowListBox, DragBeginHdl));
+}
+
+IMPL_LINK(OTableWindowListBox, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+ m_pTabWin->Command(rCEvt);
+ return true;
+}
+
+void OTableWindowListBox::dragFinished()
+{
+ // first show the error msg when existing
+ m_pTabWin->getDesignView()->getController().showError(
+ m_pTabWin->getDesignView()->getController().clearOccurredError());
+ // second look for ui activities which should happen after d&d
+ if (m_nUiEvent)
+ Application::RemoveUserEvent(m_nUiEvent);
+ m_nUiEvent
+ = Application::PostUserEvent(LINK(this, OTableWindowListBox, LookForUiHdl), nullptr, true);
+}
+
+OTableWindowListBox::~OTableWindowListBox() { disposeOnce(); }
+
+void OTableWindowListBox::dispose()
+{
+ if (m_nDropEvent)
+ Application::RemoveUserEvent(m_nDropEvent);
+ if (m_nUiEvent)
+ Application::RemoveUserEvent(m_nUiEvent);
+ m_pTabWin.clear();
+ m_xDragDropTargetHelper.reset();
+ m_xTreeView.reset();
+ InterimItemWindow::dispose();
+}
+
+int OTableWindowListBox::GetEntryFromText(std::u16string_view rEntryText)
+{
+ // iterate through the list
+ OJoinDesignView* pView = m_pTabWin->getDesignView();
+ OJoinController& rController = pView->getController();
+
+ try
+ {
+ bool bCase = false;
+ const Reference<XConnection>& xConnection = rController.getConnection();
+ if (xConnection.is())
+ {
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ if (xMeta.is())
+ bCase = xMeta->supportsMixedCaseQuotedIdentifiers();
+ }
+ for (int nEntry = 0, nCount = m_xTreeView->n_children(); nEntry < nCount; ++nEntry)
+ {
+ if (bCase ? rEntryText == m_xTreeView->get_text(nEntry)
+ : o3tl::equalsIgnoreAsciiCase(rEntryText, m_xTreeView->get_text(nEntry)))
+ return nEntry;
+ }
+ }
+ catch (SQLException&)
+ {
+ }
+
+ return -1;
+}
+
+IMPL_LINK_NOARG(OTableWindowListBox, ScrollHdl, weld::TreeView&, void)
+{
+ // connections of this table, if any, should be redrawn
+ m_pTabWin->getTableView()->Invalidate(InvalidateFlags::NoChildren);
+}
+
+IMPL_LINK(OTableWindowListBox, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+ if (m_xTreeView->get_selected_index() == -1)
+ {
+ // no drag without a field
+ return true;
+ }
+
+ OJoinTableView* pCont = m_pTabWin->getTableView();
+ if (!pCont->getDesignView()->getController().isReadOnly()
+ && pCont->getDesignView()->getController().isConnected())
+ {
+ // asterisk was not allowed to be copied to selection browsebox
+ bool bFirstNotAllowed = m_xTreeView->is_selected(0) && m_pTabWin->GetData()->IsShowAll();
+ // create a description of the source
+ OJoinExchangeData jxdSource(this);
+ // update the exchange object
+ m_xHelper->setDescriptors(jxdSource, bFirstNotAllowed);
+
+ return false;
+ }
+
+ return true;
+}
+
+sal_Int8 OTableWindowListBox::AcceptDrop(const AcceptDropEvent& _rEvt)
+{
+ // to enable the autoscroll when we're close to the edges
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ bool bHasDestRow = m_xTreeView->get_dest_row_at_pos(_rEvt.maPosPixel, xEntry.get(), true);
+
+ sal_Int8 nDND_Action = DND_ACTION_NONE;
+ // check the format
+ if (!OJoinExchObj::isFormatAvailable(
+ m_xDragDropTargetHelper->GetDataFlavorExVector(),
+ SotClipboardFormatId::SBA_TABID) // this means that the first entry is to be dragged
+ && OJoinExchObj::isFormatAvailable(m_xDragDropTargetHelper->GetDataFlavorExVector()))
+ { // don't drop into the window if it's the drag source itself
+
+ // remove the selection if the dragging operation is leaving the window
+ if (_rEvt.mbLeaving)
+ m_xTreeView->unselect_all();
+ else
+ {
+ if (!bHasDestRow)
+ return DND_ACTION_NONE;
+
+ // automatically select right entry when dragging
+ m_xTreeView->unselect_all();
+ m_xTreeView->select(*xEntry);
+
+ // one cannot drop on the first (*) entry
+ if (!(m_pTabWin->GetData()->IsShowAll()
+ && (m_xTreeView->get_iter_index_in_parent(*xEntry) == 0)))
+ nDND_Action = DND_ACTION_LINK;
+ }
+ }
+ return nDND_Action;
+}
+
+IMPL_LINK_NOARG(OTableWindowListBox, LookForUiHdl, void*, void)
+{
+ m_nUiEvent = nullptr;
+ m_pTabWin->getTableView()->lookForUiActivities();
+}
+
+IMPL_LINK_NOARG(OTableWindowListBox, DropHdl, void*, void)
+{
+ // create the connection
+ m_nDropEvent = nullptr;
+ OSL_ENSURE(m_pTabWin, "No TableWindow!");
+ try
+ {
+ OJoinTableView* pCont = m_pTabWin->getTableView();
+ OSL_ENSURE(pCont, "No QueryTableView!");
+ pCont->AddConnection(m_aDropInfo.aSource, m_aDropInfo.aDest);
+ }
+ catch (const SQLException& e)
+ {
+ // remember the exception so that we can show them later when d&d is finished
+ m_pTabWin->getDesignView()->getController().setErrorOccurred(
+ ::dbtools::SQLExceptionInfo(e));
+ }
+}
+
+sal_Int8 OTableWindowListBox::ExecuteDrop(const ExecuteDropEvent& _rEvt)
+{
+ TransferableDataHelper aDropped(_rEvt.maDropEvent.Transferable);
+ if (OJoinExchObj::isFormatAvailable(aDropped.GetDataFlavorExVector()))
+ { // don't drop into the window if it's the drag source itself
+ m_aDropInfo.aSource = OJoinExchangeData(this);
+ m_aDropInfo.aDest = OJoinExchObj::GetSourceDescription(_rEvt.maDropEvent.Transferable);
+
+ if (m_nDropEvent)
+ Application::RemoveUserEvent(m_nDropEvent);
+ m_nDropEvent
+ = Application::PostUserEvent(LINK(this, OTableWindowListBox, DropHdl), nullptr, true);
+
+ dragFinished();
+
+ return DND_ACTION_NONE;
+ }
+ return DND_ACTION_NONE;
+}
+
+void OTableWindowListBox::LoseFocus()
+{
+ if (m_pTabWin)
+ m_pTabWin->setActive(false);
+ InterimItemWindow::LoseFocus();
+}
+
+void OTableWindowListBox::GetFocus()
+{
+ if (m_pTabWin)
+ m_pTabWin->setActive();
+
+ if (m_xTreeView)
+ {
+ std::unique_ptr<weld::TreeIter> xCurrent = m_xTreeView->make_iterator();
+ if (m_xTreeView->get_cursor(xCurrent.get()))
+ {
+ m_xTreeView->unselect_all();
+ m_xTreeView->select(*xCurrent);
+ }
+ }
+
+ InterimItemWindow::GetFocus();
+}
+
+IMPL_LINK_NOARG(OTableWindowListBox, OnDoubleClick, weld::TreeView&, bool)
+{
+ // tell my parent
+ vcl::Window* pParent = Window::GetParent();
+ OSL_ENSURE(pParent != nullptr, "OTableWindowListBox::OnDoubleClick : have no Parent !");
+
+ std::unique_ptr<weld::TreeIter> xCurrent = m_xTreeView->make_iterator();
+ if (!m_xTreeView->get_cursor(xCurrent.get()))
+ return false;
+
+ static_cast<OTableWindow*>(pParent)->OnEntryDoubleClicked(*xCurrent);
+
+ return false;
+}
+
+void OTableWindowListBox::Command(const CommandEvent& rEvt)
+{
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ static_cast<OTableWindow*>(Window::GetParent())->Command(rEvt);
+ break;
+ }
+ default:
+ InterimItemWindow::Command(rEvt);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/TableWindowTitle.cxx b/dbaccess/source/ui/querydesign/TableWindowTitle.cxx
new file mode 100644
index 000000000..50eb19c28
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/TableWindowTitle.cxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableWindowTitle.hxx>
+#include <TableWindow.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <TableWindowListBox.hxx>
+#include <TableConnection.hxx>
+#include <JoinController.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+OTableWindowTitle::OTableWindowTitle(OTableWindow* pParent)
+ : InterimItemWindow(pParent, "dbaccess/ui/tabletitle.ui", "TableTitle")
+ , m_pTabWin( pParent )
+ , m_xLabel(m_xBuilder->weld_label("label"))
+ , m_xImage(m_xBuilder->weld_image("image"))
+{
+ m_xLabel->connect_mouse_press(LINK(this, OTableWindowTitle, MousePressHdl));
+}
+
+OTableWindowTitle::~OTableWindowTitle()
+{
+ disposeOnce();
+}
+
+void OTableWindowTitle::dispose()
+{
+ m_xImage.reset();
+ m_xLabel.reset();
+ m_pTabWin.clear();
+ InterimItemWindow::dispose();
+}
+
+IMPL_LINK(OTableWindowTitle, MousePressHdl, const MouseEvent&, rEvt, bool)
+{
+ if (rEvt.IsLeft())
+ {
+ if( rEvt.GetClicks() == 2)
+ {
+ Size aSize(GetTextWidth(GetText()) + 20,
+ m_pTabWin->GetSizePixel().Height() - m_pTabWin->GetListBox()->GetSizePixel().Height());
+
+ weld::TreeView& rTreeView = m_pTabWin->GetListBox()->get_widget();
+ aSize.AdjustHeight(rTreeView.get_height_rows(rTreeView.n_children() + 2));
+ if (m_pTabWin->GetSizePixel() != aSize)
+ {
+ m_pTabWin->SetSizePixel(aSize);
+
+ OJoinTableView* pView = m_pTabWin->getTableView();
+ OSL_ENSURE(pView,"No OJoinTableView!");
+ for (auto& conn : pView->getTableConnections())
+ conn->RecalcLines();
+
+ pView->InvalidateConnections();
+ pView->getDesignView()->getController().setModified(true);
+ pView->Invalidate(InvalidateFlags::NoChildren);
+ }
+ }
+ else
+ {
+ Point aPos = rEvt.GetPosPixel();
+ aPos = OutputToScreenPixel( aPos );
+ OJoinTableView* pView = m_pTabWin->getTableView();
+ OSL_ENSURE(pView,"No OJoinTableView!");
+ pView->NotifyTitleClicked( static_cast<OTableWindow*>(GetParent()), aPos );
+ }
+ }
+ else if (rEvt.IsRight())
+ {
+ CommandEvent aCEvt(rEvt.GetPosPixel(), CommandEventId::ContextMenu, true);
+ // tdf#94709 - protect shutdown code-path.
+ VclPtr<OTableWindow> xTabWin(m_pTabWin);
+ xTabWin->Command(aCEvt);
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/class.jpg b/dbaccess/source/ui/querydesign/class.jpg
new file mode 100644
index 000000000..b1a3b6d27
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/class.jpg
Binary files differ
diff --git a/dbaccess/source/ui/querydesign/limitboxcontroller.cxx b/dbaccess/source/ui/querydesign/limitboxcontroller.cxx
new file mode 100644
index 000000000..8b6884338
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/limitboxcontroller.cxx
@@ -0,0 +1,322 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "limitboxcontroller.hxx"
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include <core_resource.hxx>
+#include <strings.hrc>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+
+/// Default values
+sal_Int64 const aDefLimitAry[] =
+{
+ 5,
+ 10,
+ 20,
+ 50
+};
+
+}
+
+namespace dbaui
+{
+
+/**
+ * Input box to add limit to an SQL query (maximum number of result's rows)
+ * This box is reachable on the Query Design Toolbar
+ */
+class LimitBox final : public InterimItemWindow
+{
+public:
+ LimitBox(vcl::Window* pParent, LimitBoxController* pCtrl)
+ : InterimItemWindow(pParent, "dbaccess/ui/limitbox.ui", "LimitBox")
+ , m_pControl( pCtrl )
+ , m_xWidget(m_xBuilder->weld_combo_box("limit"))
+ {
+ InitControlBase(m_xWidget.get());
+
+ LoadDefaultLimits();
+
+ m_xWidget->connect_key_press(LINK(this, LimitBox, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, LimitBox, ActivateHdl));
+ m_xWidget->connect_changed(LINK(this, LimitBox, ChangeHdl));
+ m_xWidget->connect_focus_out(LINK(this, LimitBox, FocusOutHdl));
+ m_xWidget->set_entry_width_chars(6);
+ SetSizePixel(m_xContainer->get_preferred_size());
+ }
+
+ virtual void dispose() override
+ {
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+ }
+
+ virtual ~LimitBox() override
+ {
+ disposeOnce();
+ }
+
+ void set_sensitive(bool bSensitive)
+ {
+ m_xWidget->set_sensitive(bSensitive);
+ }
+
+ void set_value(int nLimit)
+ {
+ if (nLimit < 0)
+ m_xWidget->set_active(0);
+ else
+ m_xWidget->set_entry_text(OUString::number(nLimit));
+ m_xWidget->save_value();
+ }
+
+private:
+ LimitBoxController* m_pControl;
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(ChangeHdl, weld::ComboBox&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+
+ void Apply()
+ {
+ if (!m_xWidget->get_value_changed_from_saved())
+ return;
+ sal_Int64 nLimit;
+ OUString sActiveText = m_xWidget->get_active_text();
+ if (sActiveText == DBA_RES(STR_QUERY_LIMIT_ALL))
+ nLimit = -1;
+ else
+ {
+ nLimit = m_xWidget->get_active_text().toInt64();
+ if (nLimit < 0)
+ nLimit = -1;
+ }
+ set_value(nLimit);
+ m_pControl->dispatchCommand({ comphelper::makePropertyValue("DBLimit.Value", nLimit) });
+ }
+
+ ///Initialize entries
+ void LoadDefaultLimits()
+ {
+ m_xWidget->freeze();
+ m_xWidget->append_text(DBA_RES(STR_QUERY_LIMIT_ALL));
+ for (auto nIndex : aDefLimitAry)
+ {
+ m_xWidget->append_text(OUString::number(nIndex));
+ }
+ m_xWidget->thaw();
+ }
+};
+
+IMPL_LINK(LimitBox, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+ const sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ switch (nCode)
+ {
+ case KEY_ESCAPE:
+ m_xWidget->set_entry_text(m_xWidget->get_saved_value());
+ bHandled = true;
+ break;
+ case KEY_RETURN:
+ {
+ bHandled = ActivateHdl(*m_xWidget);
+ break;
+ }
+ }
+ return bHandled || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(LimitBox, FocusOutHdl, weld::Widget&, void)
+{
+ if (!m_xWidget || m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus
+ return;
+ Apply();
+}
+
+IMPL_LINK(LimitBox, ChangeHdl, weld::ComboBox&, rComboBox, void)
+{
+ if (rComboBox.changed_by_direct_pick())
+ ActivateHdl(rComboBox);
+}
+
+IMPL_LINK_NOARG(LimitBox, ActivateHdl, weld::ComboBox&, bool)
+{
+ GrabFocusToDocument();
+ Apply();
+ return true;
+}
+
+LimitBoxController::LimitBoxController(
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ svt::ToolboxController( rxContext,
+ uno::Reference< frame::XFrame >(),
+ ".uno:DBLimit" ),
+ m_xLimitBox( nullptr )
+{
+}
+
+LimitBoxController::~LimitBoxController()
+{
+}
+
+/// XInterface
+uno::Any SAL_CALL LimitBoxController::queryInterface( const uno::Type& aType )
+{
+ uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< lang::XServiceInfo* >( this ));
+}
+
+void SAL_CALL LimitBoxController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL LimitBoxController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+
+/// XServiceInfo
+OUString SAL_CALL LimitBoxController::getImplementationName()
+{
+ return "org.libreoffice.comp.dbu.LimitBoxController";
+}
+
+sal_Bool SAL_CALL LimitBoxController::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+
+css::uno::Sequence< OUString > SAL_CALL LimitBoxController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+/// XComponent
+void SAL_CALL LimitBoxController::dispose()
+{
+ svt::ToolboxController::dispose();
+
+ SolarMutexGuard aSolarMutexGuard;
+ m_xLimitBox.disposeAndClear();
+}
+
+/// XStatusListener
+void SAL_CALL LimitBoxController::statusChanged(
+ const frame::FeatureStateEvent& rEvent )
+{
+ if ( !m_xLimitBox )
+ return;
+
+ SolarMutexGuard aSolarMutexGuard;
+ if ( rEvent.FeatureURL.Path == "DBLimit" )
+ {
+ if ( rEvent.IsEnabled )
+ {
+ m_xLimitBox->set_sensitive(true);
+ sal_Int64 nLimit = 0;
+ if (rEvent.State >>= nLimit)
+ m_xLimitBox->set_value(nLimit);
+ }
+ else
+ m_xLimitBox->set_sensitive(false);
+ }
+}
+
+/// XToolbarController
+void SAL_CALL LimitBoxController::execute( sal_Int16 /*KeyModifier*/ )
+{
+}
+
+void SAL_CALL LimitBoxController::click()
+{
+}
+
+void SAL_CALL LimitBoxController::doubleClick()
+{
+}
+
+uno::Reference< awt::XWindow > SAL_CALL LimitBoxController::createPopupWindow()
+{
+ return uno::Reference< awt::XWindow >();
+}
+
+uno::Reference< awt::XWindow > SAL_CALL LimitBoxController::createItemWindow(
+ const uno::Reference< awt::XWindow >& xParent )
+{
+ uno::Reference< awt::XWindow > xItemWindow;
+
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent );
+ if ( pParent )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ m_xLimitBox = VclPtr<LimitBox>::Create(pParent, this);
+ xItemWindow = VCLUnoHelper::GetInterface(m_xLimitBox);
+ }
+
+ return xItemWindow;
+}
+
+void LimitBoxController::dispatchCommand(
+ const uno::Sequence< beans::PropertyValue >& rArgs )
+{
+ uno::Reference< frame::XDispatchProvider > xDispatchProvider( m_xFrame, uno::UNO_QUERY );
+ if ( xDispatchProvider.is() )
+ {
+ util::URL aURL;
+ uno::Reference< frame::XDispatch > xDispatch;
+ uno::Reference< util::XURLTransformer > xURLTransformer = getURLTransformer();
+
+ aURL.Complete = ".uno:DBLimit";
+ xURLTransformer->parseStrict( aURL );
+ xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 );
+ if ( xDispatch.is() )
+ xDispatch->dispatch( aURL, rArgs );
+ }
+}
+
+} // dbaui namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_libreoffice_comp_dbu_LimitBoxController_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::LimitBoxController(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/limitboxcontroller.hxx b/dbaccess/source/ui/querydesign/limitboxcontroller.hxx
new file mode 100644
index 000000000..af1e5a666
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/limitboxcontroller.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <svtools/toolboxcontroller.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace dbaui
+{
+
+class LimitBox;
+
+/**
+ * A ToolboxController to paste LimitBox onto the Query Design Toolbar
+ * It is communicating with querycontroller and this channel make enable
+ * to set\get the value of limitbox when switching between views
+ */
+class LimitBoxController: public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+ public:
+ explicit LimitBoxController(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~LimitBoxController() override;
+
+ /// XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ /// XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ /// XComponent
+ virtual void SAL_CALL dispose() override;
+
+ /// XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+
+ /// XToolbarController
+ virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override;
+ virtual void SAL_CALL click() override;
+ virtual void SAL_CALL doubleClick() override;
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createPopupWindow() override;
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override;
+
+ void dispatchCommand( const css::uno::Sequence< css::beans::PropertyValue >& rArgs );
+ using svt::ToolboxController::dispatchCommand;
+
+ private:
+ VclPtr<LimitBox> m_xLimitBox;
+};
+
+} ///dbaui namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/querycontainerwindow.cxx b/dbaccess/source/ui/querydesign/querycontainerwindow.cxx
new file mode 100644
index 000000000..68b4c5c86
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/querycontainerwindow.cxx
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <querycontainerwindow.hxx>
+#include <QueryDesignView.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <JoinController.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <strings.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <vcl/event.hxx>
+#include <UITools.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/Frame.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::beans;
+
+ // OQueryContainerWindow
+ OQueryContainerWindow::OQueryContainerWindow(vcl::Window* pParent, OQueryController& _rController,const Reference< XComponentContext >& _rxContext)
+ :ODataView( pParent, _rController, _rxContext )
+ ,m_pViewSwitch(nullptr)
+ ,m_pBeamer(nullptr)
+ {
+ m_pViewSwitch = new OQueryViewSwitch( this, _rController, _rxContext );
+
+ m_pSplitter = VclPtr<Splitter>::Create(this,WB_VSCROLL);
+ m_pSplitter->Hide();
+ m_pSplitter->SetSplitHdl( LINK( this, OQueryContainerWindow, SplitHdl ) );
+ m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) );
+ }
+ OQueryContainerWindow::~OQueryContainerWindow()
+ {
+ disposeOnce();
+ }
+ void OQueryContainerWindow::dispose()
+ {
+ {
+ OQueryViewSwitch* pTemp = m_pViewSwitch;
+ m_pViewSwitch = nullptr;
+ delete pTemp;
+ }
+ if ( m_pBeamer )
+ ::dbaui::notifySystemWindow(this,m_pBeamer,::comphelper::mem_fun(&TaskPaneList::RemoveWindow));
+ m_pBeamer.clear();
+ if ( m_xBeamer.is() )
+ {
+ Reference< css::util::XCloseable > xCloseable(m_xBeamer,UNO_QUERY);
+ m_xBeamer = nullptr;
+ if(xCloseable.is())
+ xCloseable->close(false); // false - holds the ownership of this frame
+ }
+
+ m_pSplitter.disposeAndClear();
+ ODataView::dispose();
+ }
+ bool OQueryContainerWindow::switchView( ::dbtools::SQLExceptionInfo* _pErrorInfo )
+ {
+ return m_pViewSwitch->switchView( _pErrorInfo );
+ }
+
+ void OQueryContainerWindow::forceInitialView()
+ {
+ return m_pViewSwitch->forceInitialView();
+ }
+
+ void OQueryContainerWindow::resizeAll( const tools::Rectangle& _rPlayground )
+ {
+ tools::Rectangle aPlayground( _rPlayground );
+
+ if ( m_pBeamer && m_pBeamer->IsVisible() )
+ {
+ // calc pos and size of the splitter
+ Point aSplitPos = m_pSplitter->GetPosPixel();
+ Size aSplitSize = m_pSplitter->GetOutputSizePixel();
+ aSplitSize.setWidth( aPlayground.GetWidth() );
+
+ if ( aSplitPos.Y() <= aPlayground.Top() )
+ aSplitPos.setY( aPlayground.Top() + sal_Int32( aPlayground.GetHeight() * 0.2 ) );
+
+ if ( aSplitPos.Y() + aSplitSize.Height() > aPlayground.GetHeight() )
+ aSplitPos.setY( aPlayground.GetHeight() - aSplitSize.Height() );
+
+ // set pos and size of the splitter
+ m_pSplitter->SetPosSizePixel( aSplitPos, aSplitSize );
+ m_pSplitter->SetDragRectPixel( aPlayground );
+
+ // set pos and size of the beamer
+ Size aBeamerSize( aPlayground.GetWidth(), aSplitPos.Y() );
+ m_pBeamer->SetPosSizePixel( aPlayground.TopLeft(), aBeamerSize );
+
+ // shrink the playground by the size which is occupied by the beamer
+ aPlayground.SetTop( aSplitPos.Y() + aSplitSize.Height() );
+ }
+
+ ODataView::resizeAll( aPlayground );
+ }
+
+ void OQueryContainerWindow::resizeDocumentView( tools::Rectangle& _rPlayground )
+ {
+ m_pViewSwitch->SetPosSizePixel( _rPlayground.TopLeft(), Size( _rPlayground.GetWidth(), _rPlayground.GetHeight() ) );
+
+ ODataView::resizeDocumentView( _rPlayground );
+ }
+
+ void OQueryContainerWindow::GetFocus()
+ {
+ ODataView::GetFocus();
+ if(m_pViewSwitch)
+ m_pViewSwitch->GrabFocus();
+ }
+ IMPL_LINK_NOARG( OQueryContainerWindow, SplitHdl, Splitter*, void )
+ {
+ m_pSplitter->SetPosPixel( Point( m_pSplitter->GetPosPixel().X(),m_pSplitter->GetSplitPosPixel() ) );
+ Resize();
+ }
+
+ void OQueryContainerWindow::Construct()
+ {
+ m_pViewSwitch->Construct();
+ }
+
+ void OQueryContainerWindow::disposingPreview()
+ {
+ if ( m_pBeamer )
+ {
+ // here I know that we will be destroyed from the frame
+ ::dbaui::notifySystemWindow(this,m_pBeamer,::comphelper::mem_fun(&TaskPaneList::RemoveWindow));
+ m_pBeamer = nullptr;
+ m_xBeamer = nullptr;
+ m_pSplitter->Hide();
+ Resize();
+ }
+ }
+ bool OQueryContainerWindow::PreNotify( NotifyEvent& rNEvt )
+ {
+ if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS && m_pViewSwitch)
+ {
+ OJoinController& rController = m_pViewSwitch->getDesignView()->getController();
+ rController.InvalidateFeature(SID_CUT);
+ rController.InvalidateFeature(SID_COPY);
+ rController.InvalidateFeature(SID_PASTE);
+ }
+ return ODataView::PreNotify(rNEvt);
+ }
+ void OQueryContainerWindow::showPreview(const Reference<XFrame>& _xFrame)
+ {
+ if(m_pBeamer)
+ return;
+
+ m_pBeamer = VclPtr<OBeamer>::Create(this);
+
+ ::dbaui::notifySystemWindow(this,m_pBeamer,::comphelper::mem_fun(&TaskPaneList::AddWindow));
+
+ m_xBeamer = Frame::create( m_pViewSwitch->getORB() );
+ m_xBeamer->initialize( VCLUnoHelper::GetInterface ( m_pBeamer ) );
+
+ // notify layout manager to not create internal toolbars
+ try
+ {
+ Reference < XPropertySet > xLMPropSet(m_xBeamer->getLayoutManager(), UNO_QUERY);
+ if ( xLMPropSet.is() )
+ {
+ xLMPropSet->setPropertyValue( "AutomaticToolbars", Any( false ));
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ m_xBeamer->setName(FRAME_NAME_QUERY_PREVIEW);
+
+ // append our frame
+ Reference < XFramesSupplier > xSup(_xFrame,UNO_QUERY);
+ Reference < XFrames > xFrames = xSup->getFrames();
+ xFrames->append( Reference<XFrame>(m_xBeamer,UNO_QUERY_THROW) );
+
+ Size aSize = GetOutputSizePixel();
+ Size aBeamer(aSize.Width(),sal_Int32(aSize.Height()*0.33));
+
+ const tools::Long nFrameHeight = LogicToPixel(Size(0, 3), MapMode(MapUnit::MapAppFont)).Height();
+ Point aPos(0,aBeamer.Height()+nFrameHeight);
+
+ m_pBeamer->SetPosSizePixel(Point(0,0),aBeamer);
+ m_pBeamer->Show();
+
+ m_pSplitter->SetPosSizePixel( Point(0,aBeamer.Height()), Size(aSize.Width(),nFrameHeight) );
+ // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide
+ m_pSplitter->SetSplitPosPixel( aBeamer.Height() );
+ m_pViewSwitch->SetPosSizePixel(aPos,Size(aBeamer.Width(),aSize.Height() - aBeamer.Height()-nFrameHeight));
+
+ m_pSplitter->Show();
+
+ Resize();
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/querycontroller.cxx b/dbaccess/source/ui/querydesign/querycontroller.cxx
new file mode 100644
index 000000000..230cb7f6e
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/querycontroller.cxx
@@ -0,0 +1,1790 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <browserids.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <query.hrc>
+#include <stringconstants.hxx>
+#include <defaultobjectnamecheck.hxx>
+#include <dlgsave.hxx>
+#include <querycontainerwindow.hxx>
+#include <querycontroller.hxx>
+#include <QueryDesignView.hxx>
+#include <QueryTableView.hxx>
+#include <sqlmessage.hxx>
+#include <TableConnectionData.hxx>
+#include <TableFieldDescription.hxx>
+#include <UITools.hxx>
+#include <QueryPropertiesDialog.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <com/sun/star/ui/XUIElement.hpp>
+
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <svl/undo.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/mutex.hxx>
+#include <o3tl/string_view.hxx>
+#include <memory>
+#include <vector>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OQueryDesign_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OQueryController(context));
+}
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::lang;
+
+ namespace {
+
+ class OViewController : public OQueryController
+ {
+ virtual OUString SAL_CALL getImplementationName() override
+ {
+ return "org.openoffice.comp.dbu.OViewDesign";
+ }
+ virtual Sequence< OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return { "com.sun.star.sdb.ViewDesign" };
+ }
+
+ public:
+ explicit OViewController(const Reference< XComponentContext >& _rM) : OQueryController(_rM){}
+ };
+
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OViewDesign_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OViewController(context));
+}
+
+namespace dbaui
+{
+ using namespace ::connectivity;
+
+ namespace
+ {
+ OUString lcl_getObjectResourceString(TranslateId pResId, sal_Int32 _nCommandType)
+ {
+ OUString sMessageText = DBA_RES(pResId);
+ OUString sObjectType = DBA_RES(RSC_QUERY_OBJECT_TYPE[_nCommandType]);
+ sMessageText = sMessageText.replaceFirst( "$object$", sObjectType );
+ return sMessageText;
+ }
+ }
+
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::awt;
+using namespace ::dbtools;
+
+using namespace ::comphelper;
+
+namespace
+{
+ void ensureToolbars( OQueryController& _rController, bool _bDesign )
+ {
+ Reference< css::frame::XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() );
+ if ( !xLayoutManager.is() )
+ return;
+
+ xLayoutManager->lock();
+ static constexpr OUStringLiteral s_sDesignToolbar = u"private:resource/toolbar/designobjectbar";
+ static constexpr OUStringLiteral s_sSqlToolbar = u"private:resource/toolbar/sqlobjectbar";
+ if ( _bDesign )
+ {
+ xLayoutManager->destroyElement( s_sSqlToolbar );
+ xLayoutManager->createElement( s_sDesignToolbar );
+ }
+ else
+ {
+ xLayoutManager->destroyElement( s_sDesignToolbar );
+ xLayoutManager->createElement( s_sSqlToolbar );
+ }
+ xLayoutManager->unlock();
+ xLayoutManager->doLayout();
+ }
+
+ /**
+ * The value of m_nLimit is updated when LimitBox loses its focus
+ * So in those case when execution needs recent data, grab the focus
+ * (e.g. execute SQL statement, change views)
+ */
+ void grabFocusFromLimitBox( OQueryController& _rController )
+ {
+ Reference< XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() );
+ Reference< XUIElement > xUIElement = xLayoutManager->getElement("private:resource/toolbar/designobjectbar");
+ if (xUIElement.is())
+ {
+ Reference< XWindow > xWindow(xUIElement->getRealInterface(), css::uno::UNO_QUERY);
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ if( pWindow && pWindow->HasChildPathFocus() )
+ {
+ pWindow->GrabFocusToDocument();
+ }
+ }
+ }
+}
+
+OUString SAL_CALL OQueryController::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.OQueryDesign";
+}
+
+Sequence< OUString> SAL_CALL OQueryController::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.QueryDesign" };
+}
+
+OQueryController::OQueryController(const Reference< XComponentContext >& _rM)
+ :OJoinController(_rM)
+ ,OQueryController_PBase( getBroadcastHelper() )
+ ,m_pParseContext( new svxform::OSystemParseContext )
+ ,m_aSqlParser( _rM, m_pParseContext.get() )
+ ,m_nLimit(-1)
+ ,m_nVisibleRows(0x400)
+ ,m_nSplitPos(-1)
+ ,m_nCommandType( CommandType::QUERY )
+ ,m_bGraphicalDesign(false)
+ ,m_bDistinct(false)
+ ,m_bEscapeProcessing(true)
+{
+ InvalidateAll();
+
+ registerProperty( PROPERTY_ACTIVECOMMAND, PROPERTY_ID_ACTIVECOMMAND, PropertyAttribute::READONLY | PropertyAttribute::BOUND,
+ &m_sStatement, cppu::UnoType<decltype(m_sStatement)>::get() );
+ registerProperty( PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::READONLY | PropertyAttribute::BOUND,
+ &m_bEscapeProcessing, cppu::UnoType<decltype(m_bEscapeProcessing)>::get() );
+}
+
+OQueryController::~OQueryController()
+{
+ if ( !getBroadcastHelper().bDisposed && !getBroadcastHelper().bInDispose )
+ {
+ OSL_FAIL("Please check who doesn't dispose this component!");
+ // increment ref count to prevent double call of Dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( OQueryController, OJoinController, OQueryController_PBase )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryController, OJoinController, OQueryController_PBase )
+
+Reference< XPropertySetInfo > SAL_CALL OQueryController::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+void SAL_CALL OQueryController::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const
+{
+ switch ( i_nHandle )
+ {
+ case PROPERTY_ID_CURRENT_QUERY_DESIGN:
+ {
+ ::comphelper::NamedValueCollection aCurrentDesign;
+ aCurrentDesign.put( "GraphicalDesign", isGraphicalDesign() );
+ aCurrentDesign.put( PROPERTY_ESCAPE_PROCESSING, m_bEscapeProcessing );
+
+ if ( isGraphicalDesign() )
+ {
+ getContainer()->SaveUIConfig();
+ saveViewSettings( aCurrentDesign, true );
+ aCurrentDesign.put( "Statement", m_sStatement );
+ }
+ else
+ {
+ aCurrentDesign.put( "Statement", getContainer()->getStatement() );
+ }
+
+ o_rValue <<= aCurrentDesign.getPropertyValues();
+ }
+ break;
+
+ default:
+ OPropertyContainer::getFastPropertyValue( o_rValue, i_nHandle );
+ break;
+ }
+}
+
+::cppu::IPropertyArrayHelper& OQueryController::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OQueryController::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+
+ // one additional property:
+ const sal_Int32 nLength = aProps.getLength();
+ aProps.realloc( nLength + 1 );
+ auto pProps = aProps.getArray();
+ pProps[ nLength ] = Property(
+ "CurrentQueryDesign",
+ PROPERTY_ID_CURRENT_QUERY_DESIGN,
+ ::cppu::UnoType< Sequence< PropertyValue > >::get(),
+ PropertyAttribute::READONLY
+ );
+
+ std::sort(
+ pProps,
+ pProps + aProps.getLength(),
+ ::comphelper::PropertyCompareByName()
+ );
+
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+void OQueryController::deleteIterator()
+{
+ if(m_pSqlIterator)
+ {
+ delete m_pSqlIterator->getParseTree();
+ m_pSqlIterator->dispose();
+ m_pSqlIterator.reset();
+ }
+}
+
+void OQueryController::disposing()
+{
+ OQueryController_PBase::disposing();
+
+ deleteIterator();
+
+ m_pParseContext.reset();
+
+ clearFields();
+ OTableFields().swap(m_vUnUsedFieldsDesc);
+
+ ::comphelper::disposeComponent(m_xComposer);
+ OJoinController::disposing();
+ OQueryController_PBase::disposing();
+}
+
+void OQueryController::clearFields()
+{
+ OTableFields().swap(m_vTableFieldDesc);
+}
+
+FeatureState OQueryController::GetState(sal_uInt16 _nId) const
+{
+ FeatureState aReturn;
+ aReturn.bEnabled = true;
+ // (disabled automatically)
+
+ switch (_nId)
+ {
+ case ID_BROWSER_EDITDOC:
+ if ( editingCommand() )
+ aReturn.bEnabled = false;
+ else if ( editingView() && !m_xAlterView.is() )
+ aReturn.bEnabled = false;
+ else
+ aReturn = OJoinController::GetState( _nId );
+ break;
+
+ case ID_BROWSER_ESCAPEPROCESSING:
+ aReturn.bChecked = !m_bEscapeProcessing;
+ aReturn.bEnabled = ( m_pSqlIterator != nullptr ) && !m_bGraphicalDesign;
+ break;
+ case SID_RELATION_ADD_RELATION:
+ aReturn.bEnabled = isEditable() && m_bGraphicalDesign && m_vTableData.size() > 1;
+ break;
+ case ID_BROWSER_SAVEASDOC:
+ aReturn.bEnabled = !editingCommand() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
+ break;
+ case ID_BROWSER_SAVEDOC:
+ aReturn.bEnabled = isEditable() && (!m_bGraphicalDesign || !(m_vTableFieldDesc.empty() || m_vTableData.empty()));
+ break;
+ case SID_PRINTDOCDIRECT:
+ break;
+ case ID_BROWSER_CUT:
+ aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isCutAllowed();
+ break;
+ case ID_BROWSER_COPY:
+ aReturn.bEnabled = getContainer() && getContainer()->isCopyAllowed();
+ break;
+ case ID_BROWSER_PASTE:
+ aReturn.bEnabled = isEditable() && getContainer() && getContainer()->isPasteAllowed();
+ break;
+ case ID_BROWSER_SQL:
+ aReturn.bEnabled = m_bEscapeProcessing && m_pSqlIterator;
+ aReturn.bChecked = m_bGraphicalDesign;
+ break;
+ case SID_BROWSER_CLEAR_QUERY:
+ aReturn.bEnabled = isEditable() && (!m_sStatement.isEmpty() || !m_vTableData.empty());
+ break;
+ case SID_QUERY_VIEW_FUNCTIONS:
+ case SID_QUERY_VIEW_TABLES:
+ case SID_QUERY_VIEW_ALIASES:
+ aReturn.bChecked = getContainer() && getContainer()->isSlotEnabled(_nId);
+ aReturn.bEnabled = m_bGraphicalDesign;
+ break;
+ case SID_QUERY_DISTINCT_VALUES:
+ aReturn.bEnabled = m_bGraphicalDesign && isEditable();
+ aReturn.bChecked = m_bDistinct;
+ break;
+ case SID_QUERY_LIMIT:
+ aReturn.bEnabled = m_bGraphicalDesign;
+ if( aReturn.bEnabled )
+ aReturn.aValue <<= m_nLimit;
+ break;
+ case SID_QUERY_PROP_DLG:
+ aReturn.bEnabled = m_bGraphicalDesign;
+ break;
+ case ID_BROWSER_QUERY_EXECUTE:
+ aReturn.bEnabled = true;
+ break;
+ case SID_DB_QUERY_PREVIEW:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer() && getContainer()->getPreviewFrame().is();
+ break;
+#if OSL_DEBUG_LEVEL > 0
+ case ID_EDIT_QUERY_SQL:
+ break;
+ case ID_EDIT_QUERY_DESIGN:
+ break;
+#endif
+ case ID_BROWSER_ADDTABLE:
+ if ( !m_bGraphicalDesign )
+ {
+ aReturn.bEnabled = false;
+ break;
+ }
+ [[fallthrough]];
+ default:
+ aReturn = OJoinController::GetState(_nId);
+ break;
+ }
+ return aReturn;
+}
+
+void OQueryController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
+{
+ switch(_nId)
+ {
+ case ID_BROWSER_ESCAPEPROCESSING:
+ setEscapeProcessing_fireEvent( !m_bEscapeProcessing );
+ if ( !editingView() )
+ setModified(true);
+ InvalidateFeature(ID_BROWSER_SQL);
+ break;
+ case ID_BROWSER_SAVEASDOC:
+ case ID_BROWSER_SAVEDOC:
+ grabFocusFromLimitBox(*this);
+ doSaveAsDoc(ID_BROWSER_SAVEASDOC == _nId);
+ break;
+ case SID_RELATION_ADD_RELATION:
+ {
+ OJoinDesignView* pView = getJoinView();
+ if( pView )
+ static_cast<OQueryTableView*>(pView->getTableView())->createNewConnection();
+ }
+ break;
+ case SID_PRINTDOCDIRECT:
+ break;
+ case ID_BROWSER_CUT:
+ getContainer()->cut();
+ break;
+ case ID_BROWSER_COPY:
+ getContainer()->copy();
+ break;
+ case ID_BROWSER_PASTE:
+ getContainer()->paste();
+ break;
+ case ID_BROWSER_SQL:
+ {
+ grabFocusFromLimitBox(*this);
+ if ( !getContainer()->checkStatement() )
+ break;
+ SQLExceptionInfo aError;
+ try
+ {
+ setStatement_fireEvent( getContainer()->getStatement() );
+ if(m_sStatement.isEmpty() && m_pSqlIterator)
+ {
+ // change the view of the data
+ delete m_pSqlIterator->getParseTree();
+ m_pSqlIterator->setParseTree(nullptr);
+ m_bGraphicalDesign = !m_bGraphicalDesign;
+ impl_setViewMode( &aError );
+ }
+ else
+ {
+ OUString aErrorMsg;
+ std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree(aErrorMsg,m_sStatement,m_bGraphicalDesign);
+ if ( pNode )
+ {
+ delete m_pSqlIterator->getParseTree();
+ m_pSqlIterator->setParseTree(pNode.release());
+ m_pSqlIterator->traverseAll();
+
+ if ( m_pSqlIterator->hasErrors() )
+ {
+ aError = m_pSqlIterator->getErrors();
+ }
+ else
+ {
+ const OSQLTables& rTabs = m_pSqlIterator->getTables();
+ if ( m_pSqlIterator->getStatementType() != OSQLStatementType::Select || rTabs.empty() )
+ {
+ aError = SQLException(
+ DBA_RES(STR_QRY_NOSELECT),
+ nullptr,
+ "S1000",
+ 1000,
+ Any()
+ );
+ }
+ else
+ {
+ // change the view of the data
+ m_bGraphicalDesign = !m_bGraphicalDesign;
+ OUString sNewStatement;
+ m_pSqlIterator->getParseTree()->parseNodeToStr( sNewStatement, getConnection() );
+ setStatement_fireEvent( sNewStatement );
+ getContainer()->SaveUIConfig();
+ m_vTableConnectionData.clear();
+ impl_setViewMode( &aError );
+ }
+ }
+ }
+ else
+ {
+ aError = SQLException(
+ DBA_RES(STR_QRY_SYNTAX),
+ nullptr,
+ "S1000",
+ 1000,
+ Any()
+ );
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ aError = ::cppu::getCaughtException();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( aError.isValid() )
+ showError( aError );
+
+ if(m_bGraphicalDesign)
+ {
+ InvalidateFeature(ID_BROWSER_ADDTABLE);
+ InvalidateFeature(SID_RELATION_ADD_RELATION);
+ }
+ }
+ break;
+ case SID_BROWSER_CLEAR_QUERY:
+ {
+ GetUndoManager().EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE), OUString(), 0, ViewShellId(-1) );
+ getContainer()->clear();
+ GetUndoManager().LeaveListAction();
+
+ setStatement_fireEvent( OUString() );
+ if(m_bGraphicalDesign)
+ InvalidateFeature(ID_BROWSER_ADDTABLE);
+ }
+ break;
+ case SID_QUERY_VIEW_FUNCTIONS:
+ case SID_QUERY_VIEW_TABLES:
+ case SID_QUERY_VIEW_ALIASES:
+ getContainer()->setSlotEnabled(_nId,!getContainer()->isSlotEnabled(_nId));
+ setModified(true);
+ break;
+ case SID_QUERY_DISTINCT_VALUES:
+ m_bDistinct = !m_bDistinct;
+ setModified(true);
+ break;
+ case SID_QUERY_LIMIT:
+ if ( aArgs.hasElements() && aArgs[0].Name == "DBLimit.Value" )
+ {
+ aArgs[0].Value >>= m_nLimit;
+ setModified(true);
+ }
+ break;
+ case SID_QUERY_PROP_DLG:
+ grabFocusFromLimitBox(*this);
+ execute_QueryPropDlg();
+ break;
+ case ID_BROWSER_QUERY_EXECUTE:
+ grabFocusFromLimitBox(*this);
+ if ( getContainer()->checkStatement() )
+ executeQuery();
+ break;
+ case SID_DB_QUERY_PREVIEW:
+ try
+ {
+ Reference< css::util::XCloseable > xCloseFrame( getContainer()->getPreviewFrame(), UNO_QUERY );
+ if ( xCloseFrame.is() )
+ {
+ try
+ {
+ xCloseFrame->close( true );
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL( "OQueryController::Execute(SID_DB_QUERY_PREVIEW): *nobody* is expected to veto closing the preview frame!" );
+ }
+ }
+ else
+ Execute(ID_BROWSER_QUERY_EXECUTE,Sequence< PropertyValue >());
+ }
+ catch(const Exception&)
+ {
+ }
+ break;
+ default:
+ OJoinController::Execute(_nId,aArgs);
+ return; // else we would invalidate twice
+ }
+ InvalidateFeature(_nId);
+}
+
+void OQueryController::impl_showAutoSQLViewError( const css::uno::Any& _rErrorDetails )
+{
+ SQLContext aErrorContext;
+ aErrorContext.Message = lcl_getObjectResourceString( STR_ERROR_PARSING_STATEMENT, m_nCommandType );
+ aErrorContext.Context = *this;
+ aErrorContext.Details = lcl_getObjectResourceString( STR_INFO_OPENING_IN_SQL_VIEW, m_nCommandType );
+ aErrorContext.NextException = _rErrorDetails;
+ showError( aErrorContext );
+}
+
+void OQueryController::impl_setViewMode( ::dbtools::SQLExceptionInfo* _pErrorInfo )
+{
+ OSL_PRECOND( getContainer(), "OQueryController::impl_setViewMode: illegal call!" );
+
+ bool wasModified = isModified();
+
+ SQLExceptionInfo aError;
+ bool bSuccess = getContainer()->switchView( &aError );
+ if ( !bSuccess )
+ {
+ m_bGraphicalDesign = !m_bGraphicalDesign;
+ // restore old state
+ getContainer()->switchView( nullptr );
+ // don't pass &aError here, this would overwrite the error which the first switchView call
+ // returned in this location.
+ if ( _pErrorInfo )
+ *_pErrorInfo = aError;
+ else
+ showError( aError );
+ }
+ else
+ {
+ ensureToolbars( *this, m_bGraphicalDesign );
+ }
+
+ setModified( wasModified );
+}
+
+void OQueryController::impl_initialize()
+{
+ OJoinController::impl_initialize();
+
+ const NamedValueCollection& rArguments( getInitParams() );
+
+ OUString sCommand;
+ m_nCommandType = CommandType::QUERY;
+
+ // reading parameters:
+
+ // legacy parameters first (later overwritten by regular parameters)
+ OUString sIndependentSQLCommand;
+ if ( rArguments.get_ensureType( "IndependentSQLCommand", sIndependentSQLCommand ) )
+ {
+ OSL_FAIL( "OQueryController::impl_initialize: IndependentSQLCommand is regognized for compatibility only!" );
+ sCommand = sIndependentSQLCommand;
+ m_nCommandType = CommandType::COMMAND;
+ }
+
+ OUString sCurrentQuery;
+ if ( rArguments.get_ensureType( "CurrentQuery", sCurrentQuery ) )
+ {
+ OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
+ sCommand = sCurrentQuery;
+ m_nCommandType = CommandType::QUERY;
+ }
+
+ bool bCreateView( false );
+ if ( rArguments.get_ensureType( "CreateView", bCreateView ) && bCreateView )
+ {
+ OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" );
+ m_nCommandType = CommandType::TABLE;
+ }
+
+ // non-legacy parameters which overwrite the legacy parameters
+ rArguments.get_ensureType( PROPERTY_COMMAND, sCommand );
+ rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, m_nCommandType );
+
+ // translate Command/Type into proper members
+ // TODO/Later: all this (including those members) should be hidden behind some abstract interface,
+ // which is implemented for all the three commands
+ switch ( m_nCommandType )
+ {
+ case CommandType::QUERY:
+ m_sName = sCommand;
+ break;
+ case CommandType::TABLE:
+ m_sName = sCommand;
+ break;
+ case CommandType::COMMAND:
+ setStatement_fireEvent( sCommand );
+ m_sName.clear();
+ break;
+ default:
+ OSL_FAIL( "OQueryController::impl_initialize: logic error in code!" );
+ throw RuntimeException();
+ }
+
+ // more legacy parameters
+ bool bGraphicalDesign( true );
+ if ( rArguments.get_ensureType( PROPERTY_QUERYDESIGNVIEW, bGraphicalDesign ) )
+ {
+ OSL_FAIL( "OQueryController::impl_initialize: QueryDesignView is regognized for compatibility only!" );
+ m_bGraphicalDesign = bGraphicalDesign;
+ }
+
+ // more non-legacy
+ rArguments.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign );
+
+ bool bEscapeProcessing( true );
+ if ( rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing ) )
+ {
+ setEscapeProcessing_fireEvent( bEscapeProcessing );
+
+ OSL_ENSURE( m_bEscapeProcessing || !m_bGraphicalDesign, "OQueryController::impl_initialize: can't do the graphical design without escape processing!" );
+ if ( !m_bEscapeProcessing )
+ m_bGraphicalDesign = false;
+ }
+
+ // initial design
+ bool bForceInitialDesign = false;
+ Sequence< PropertyValue > aCurrentQueryDesignProps;
+ aCurrentQueryDesignProps = rArguments.getOrDefault( "CurrentQueryDesign", aCurrentQueryDesignProps );
+
+ if ( aCurrentQueryDesignProps.hasElements() )
+ {
+ ::comphelper::NamedValueCollection aCurrentQueryDesign( aCurrentQueryDesignProps );
+ if ( aCurrentQueryDesign.has( PROPERTY_GRAPHICAL_DESIGN ) )
+ {
+ aCurrentQueryDesign.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign );
+ }
+ if ( aCurrentQueryDesign.has( PROPERTY_ESCAPE_PROCESSING ) )
+ {
+ aCurrentQueryDesign.get_ensureType( PROPERTY_ESCAPE_PROCESSING, m_bEscapeProcessing );
+ }
+ if ( aCurrentQueryDesign.has( "Statement" ) )
+ {
+ OUString sStatement;
+ aCurrentQueryDesign.get_ensureType( "Statement", sStatement );
+ aCurrentQueryDesign.remove( "Statement" );
+ setStatement_fireEvent( sStatement );
+ }
+
+ loadViewSettings( aCurrentQueryDesign );
+
+ bForceInitialDesign = true;
+ }
+
+ if ( !ensureConnected() )
+ { // we have no connection so what else should we do
+ m_bGraphicalDesign = false;
+ if ( editingView() )
+ {
+ connectionLostMessage();
+ throw SQLException();
+ }
+ }
+
+ // check the view capabilities
+ if ( isConnected() && editingView() )
+ {
+ Reference< XViewsSupplier > xViewsSup( getConnection(), UNO_QUERY );
+ Reference< XNameAccess > xViews;
+ if ( xViewsSup.is() )
+ xViews = xViewsSup->getViews();
+
+ if ( !xViews.is() )
+ { // we can't create views so we ask if the user wants to create a query instead
+ m_nCommandType = CommandType::QUERY;
+ bool bClose = false;
+ {
+ OUString aTitle(DBA_RES(STR_QUERYDESIGN_NO_VIEW_SUPPORT));
+ OUString aMessage(DBA_RES(STR_QUERYDESIGN_NO_VIEW_ASK));
+ OSQLMessageBox aDlg(getFrameWeld(), aTitle, aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, MessageType::Query);
+ bClose = aDlg.run() == RET_NO;
+ }
+ if ( bClose )
+ throw VetoException();
+ }
+
+ // now if we are to edit an existing view, check whether this is possible
+ if ( !m_sName.isEmpty() )
+ {
+ Any aView( xViews->getByName( m_sName ) );
+ // will throw if there is no such view
+ if ( !( aView >>= m_xAlterView ) )
+ {
+ throw IllegalArgumentException(
+ DBA_RES(STR_NO_ALTER_VIEW_SUPPORT),
+ *this,
+ 1
+ );
+ }
+ }
+ }
+
+ OSL_ENSURE(getDataSource().is(),"OQueryController::impl_initialize: need a datasource!");
+
+ try
+ {
+ getContainer()->initialize();
+ impl_reset( bForceInitialDesign );
+
+ SQLExceptionInfo aError;
+ const bool bAttemptedGraphicalDesign = m_bGraphicalDesign;
+
+ if ( bForceInitialDesign )
+ {
+ getContainer()->forceInitialView();
+ }
+ else
+ {
+ impl_setViewMode( &aError );
+ }
+
+ if ( aError.isValid() && bAttemptedGraphicalDesign && !m_bGraphicalDesign )
+ {
+ // we tried initializing the graphical view, this failed, and we were automatically switched to SQL
+ // view => tell this to the user
+ if ( !editingView() )
+ {
+ impl_showAutoSQLViewError( aError.get() );
+ }
+ }
+
+ ClearUndoManager();
+
+ if ( m_bGraphicalDesign
+ && ( ( m_sName.isEmpty() && !editingCommand() )
+ || ( m_sStatement.isEmpty() && editingCommand() )
+ )
+ )
+ {
+ Application::PostUserEvent( LINK( this, OQueryController, OnExecuteAddTable ) );
+ }
+
+ setModified(false);
+ }
+ catch(const SQLException& e)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ // we caught an exception so we switch to text only mode
+ {
+ m_bGraphicalDesign = false;
+ getContainer()->initialize();
+ OSQLMessageBox aBox(getFrameWeld(), e);
+ aBox.run();
+ }
+ throw;
+ }
+}
+
+void OQueryController::onLoadedMenu(const Reference< css::frame::XLayoutManager >& /*_xLayoutManager*/)
+{
+ ensureToolbars( *this, m_bGraphicalDesign );
+}
+
+OUString OQueryController::getPrivateTitle( ) const
+{
+ if ( m_sName.isEmpty() )
+ {
+ if ( !editingCommand() )
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ OUString aDefaultName = DBA_RES(editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE);
+ return o3tl::getToken(aDefaultName, 0, ' ') + OUString::number(getCurrentStartNumber());
+ }
+ }
+ return m_sName;
+}
+
+void OQueryController::setQueryComposer()
+{
+ if(!isConnected())
+ return;
+
+ Reference< XSQLQueryComposerFactory > xFactory(getConnection(), UNO_QUERY);
+ OSL_ENSURE(xFactory.is(),"Connection doesn't support a querycomposer");
+ if ( !(xFactory.is() && getContainer()) )
+ return;
+
+ try
+ {
+ m_xComposer = xFactory->createQueryComposer();
+ getContainer()->setStatement(m_sStatement);
+ }
+ catch(const Exception&)
+ {
+ m_xComposer = nullptr;
+ }
+ OSL_ENSURE(m_xComposer.is(),"No querycomposer available!");
+ Reference<XTablesSupplier> xTablesSup(getConnection(), UNO_QUERY);
+ deleteIterator();
+ m_pSqlIterator.reset(new ::connectivity::OSQLParseTreeIterator( getConnection(), xTablesSup->getTables(), m_aSqlParser ));
+}
+
+bool OQueryController::Construct(vcl::Window* pParent)
+{
+ // TODO: we have to check if we should create the text view or the design view
+
+ setView( VclPtr<OQueryContainerWindow>::Create( pParent, *this, getORB() ) );
+
+ return OJoinController::Construct(pParent);
+}
+
+OJoinDesignView* OQueryController::getJoinView()
+{
+ return getContainer()->getDesignView();
+}
+
+void OQueryController::describeSupportedFeatures()
+{
+ OJoinController::describeSupportedFeatures();
+ implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:SbaNativeSql", ID_BROWSER_ESCAPEPROCESSING,CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:DBViewFunctions", SID_QUERY_VIEW_FUNCTIONS, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewTableNames", SID_QUERY_VIEW_TABLES, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewAliases", SID_QUERY_VIEW_ALIASES, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBDistinctValues", SID_QUERY_DISTINCT_VALUES, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:DBChangeDesignMode",ID_BROWSER_SQL, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBClearQuery", SID_BROWSER_CLEAR_QUERY, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:SbaExecuteSql", ID_BROWSER_QUERY_EXECUTE, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBQueryPreview", SID_DB_QUERY_PREVIEW, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBLimit", SID_QUERY_LIMIT, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:DBQueryPropertiesDialog", SID_QUERY_PROP_DLG, CommandGroup::FORMAT );
+
+#if OSL_DEBUG_LEVEL > 0
+ implDescribeSupportedFeature( ".uno:DBShowParseTree", ID_EDIT_QUERY_SQL );
+ implDescribeSupportedFeature( ".uno:DBMakeDisjunct", ID_EDIT_QUERY_DESIGN );
+#endif
+}
+
+void OQueryController::impl_onModifyChanged()
+{
+ OJoinController::impl_onModifyChanged();
+ InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
+ InvalidateFeature(ID_BROWSER_SAVEASDOC);
+ InvalidateFeature(ID_BROWSER_QUERY_EXECUTE);
+}
+
+void SAL_CALL OQueryController::disposing( const EventObject& Source )
+{
+ SolarMutexGuard aGuard;
+
+ if ( getContainer() && Source.Source.is() )
+ {
+ if ( Source.Source == m_aCurrentFrame.getFrame() )
+ { // our frame is being disposed -> close the preview window (if we have one)
+ Reference< XFrame2 > xPreviewFrame( getContainer()->getPreviewFrame() );
+ ::comphelper::disposeComponent( xPreviewFrame );
+ }
+ else if ( Source.Source == getContainer()->getPreviewFrame() )
+ {
+ getContainer()->disposingPreview();
+ }
+ }
+
+ OJoinController_BASE::disposing(Source);
+}
+
+void OQueryController::reconnect(bool _bUI)
+{
+ deleteIterator();
+ ::comphelper::disposeComponent(m_xComposer);
+
+ OJoinController::reconnect( _bUI );
+
+ if (isConnected())
+ {
+ setQueryComposer();
+ }
+ else
+ {
+ if(m_bGraphicalDesign)
+ {
+ m_bGraphicalDesign = false;
+ // don't call Execute(SQL) because this changes the sql statement
+ impl_setViewMode( nullptr );
+ }
+ InvalidateAll();
+ }
+}
+
+void OQueryController::saveViewSettings( ::comphelper::NamedValueCollection& o_rViewSettings, const bool i_includingCriteria ) const
+{
+ saveTableWindows( o_rViewSettings );
+
+ ::comphelper::NamedValueCollection aAllFieldsData;
+ ::comphelper::NamedValueCollection aFieldData;
+ sal_Int32 i = 1;
+ for (auto const& fieldDesc : m_vTableFieldDesc)
+ {
+ if ( !fieldDesc->IsEmpty() )
+ {
+ aFieldData.clear();
+ fieldDesc->Save( aFieldData, i_includingCriteria );
+
+ const OUString sFieldSettingName = "Field" + OUString::number( i );
+ aAllFieldsData.put( sFieldSettingName, aFieldData.getPropertyValues() );
+ }
+ ++i;
+ }
+
+ o_rViewSettings.put( "Fields", aAllFieldsData.getPropertyValues() );
+ o_rViewSettings.put( "SplitterPosition", m_nSplitPos );
+ o_rViewSettings.put( "VisibleRows", m_nVisibleRows );
+}
+
+void OQueryController::loadViewSettings( const ::comphelper::NamedValueCollection& o_rViewSettings )
+{
+ loadTableWindows( o_rViewSettings );
+
+ m_nSplitPos = o_rViewSettings.getOrDefault( "SplitterPosition", m_nSplitPos );
+ m_nVisibleRows = o_rViewSettings.getOrDefault( "VisibleRows", m_nVisibleRows );
+ m_aFieldInformation = o_rViewSettings.getOrDefault( "Fields", m_aFieldInformation );
+}
+
+void OQueryController::execute_QueryPropDlg()
+{
+ QueryPropertiesDialog aQueryPropDlg(getContainer()->GetFrameWeld(), m_bDistinct, m_nLimit);
+
+ if (aQueryPropDlg.run() == RET_OK)
+ {
+ m_bDistinct = aQueryPropDlg.getDistinct();
+ m_nLimit = aQueryPropDlg.getLimit();
+ InvalidateFeature( SID_QUERY_DISTINCT_VALUES );
+ InvalidateFeature( SID_QUERY_LIMIT, nullptr, true );
+ }
+}
+
+sal_Int32 OQueryController::getColWidth(sal_uInt16 _nColPos) const
+{
+ if ( _nColPos < m_aFieldInformation.getLength() )
+ {
+ rtl::Reference<OTableFieldDesc> pField( new OTableFieldDesc());
+ pField->Load( m_aFieldInformation[ _nColPos ], false );
+ return pField->GetColWidth();
+ }
+ return 0;
+}
+
+Reference<XNameAccess> OQueryController::getObjectContainer() const
+{
+ Reference< XNameAccess > xElements;
+ if ( editingView() )
+ {
+ Reference< XViewsSupplier > xViewsSupp( getConnection(), UNO_QUERY );
+ if ( xViewsSupp.is() )
+ xElements = xViewsSupp->getViews();
+ }
+ else
+ {
+ Reference< XQueriesSupplier > xQueriesSupp( getConnection(), UNO_QUERY );
+ if ( xQueriesSupp.is() )
+ xElements = xQueriesSupp->getQueries();
+ else
+ {
+ Reference< XQueryDefinitionsSupplier > xQueryDefsSupp( getDataSource(), UNO_QUERY );
+ if ( xQueryDefsSupp.is() )
+ xElements = xQueryDefsSupp->getQueryDefinitions();
+ }
+ }
+
+ OSL_ENSURE( xElements.is(), "OQueryController::getObjectContainer: unable to obtain the container!" );
+ return xElements;
+}
+
+void OQueryController::executeQuery()
+{
+ // we don't need to check the connection here because we already check the composer
+ // which can't live without his connection
+ OUString sTranslatedStmt = translateStatement( false );
+
+ OUString sDataSourceName = getDataSourceName();
+ if ( sDataSourceName.isEmpty() || sTranslatedStmt.isEmpty() )
+ return;
+
+ try
+ {
+ getContainer()->showPreview( getFrame() );
+ InvalidateFeature(SID_DB_QUERY_PREVIEW);
+
+ URL aWantToDispatch;
+ aWantToDispatch.Complete = ".component:DB/DataSourceBrowser";
+
+ OUString sFrameName( FRAME_NAME_QUERY_PREVIEW );
+ sal_Int32 nSearchFlags = FrameSearchFlag::CHILDREN;
+
+ Reference< XDispatch> xDisp;
+ Reference< XDispatchProvider> xProv( getFrame()->findFrame( sFrameName, nSearchFlags ), UNO_QUERY );
+ if(!xProv.is())
+ {
+ xProv.set( getFrame(), UNO_QUERY );
+ if (xProv.is())
+ xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags);
+ }
+ else
+ {
+ xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, FrameSearchFlag::SELF);
+ }
+ if (xDisp.is())
+ {
+ auto aProps(::comphelper::InitPropertySequence(
+ {
+ { PROPERTY_DATASOURCENAME, Any(sDataSourceName) },
+ { PROPERTY_COMMAND_TYPE, Any(CommandType::COMMAND) },
+ { PROPERTY_COMMAND, Any(sTranslatedStmt) },
+ { PROPERTY_ENABLE_BROWSER, Any(false) },
+ { PROPERTY_ACTIVE_CONNECTION, Any(getConnection()) },
+ { PROPERTY_UPDATE_CATALOGNAME, Any(m_sUpdateCatalogName) },
+ { PROPERTY_UPDATE_SCHEMANAME, Any(m_sUpdateSchemaName) },
+ { PROPERTY_UPDATE_TABLENAME, Any(OUString()) },
+ { PROPERTY_ESCAPE_PROCESSING, Any(m_bEscapeProcessing) }
+ }));
+
+ xDisp->dispatch(aWantToDispatch, aProps);
+ // check the state of the beamer
+ // be notified when the beamer frame is closed
+ Reference< XComponent > xComponent = getFrame()->findFrame( sFrameName, nSearchFlags );
+ if (xComponent.is())
+ {
+ OSL_ENSURE(Reference< XFrame >(xComponent, UNO_QUERY).get() == getContainer()->getPreviewFrame().get(),
+ "OQueryController::executeQuery: oops ... which window do I have here?");
+ Reference< XEventListener> xEvtL(static_cast<cppu::OWeakObject*>(this),UNO_QUERY);
+ xComponent->addEventListener(xEvtL);
+ }
+ }
+ else
+ {
+ OSL_FAIL("Couldn't create a beamer window!");
+ }
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Couldn't create a beamer window!");
+ }
+}
+
+bool OQueryController::askForNewName(const Reference<XNameAccess>& _xElements, bool _bSaveAs)
+{
+ OSL_ENSURE( !editingCommand(), "OQueryController::askForNewName: not to be called when designing an independent statement!" );
+ if ( editingCommand() )
+ return false;
+
+ OSL_PRECOND( _xElements.is(), "OQueryController::askForNewName: invalid container!" );
+ if ( !_xElements.is() )
+ return false;
+
+ bool bRet = true;
+ bool bNew = _bSaveAs || !_xElements->hasByName( m_sName );
+ if(bNew)
+ {
+ OUString aDefaultName;
+ if (!m_sName.isEmpty())
+ aDefaultName = m_sName;
+ else
+ {
+ OUString sName = DBA_RES(editingView() ? STR_VIEW_TITLE : STR_QRY_TITLE);
+ aDefaultName = ::dbtools::createUniqueName(_xElements, sName.getToken(0, ' '));
+ }
+
+ DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::QUERY );
+ OSaveAsDlg aDlg(
+ getFrameWeld(),
+ m_nCommandType,
+ getORB(),
+ getConnection(),
+ aDefaultName,
+ aNameChecker,
+ SADFlags::NONE );
+
+ bRet = ( aDlg.run() == RET_OK );
+ if ( bRet )
+ {
+ m_sName = aDlg.getName();
+ if ( editingView() )
+ {
+ m_sUpdateCatalogName = aDlg.getCatalog();
+ m_sUpdateSchemaName = aDlg.getSchema();
+ }
+ }
+ }
+ return bRet;
+}
+
+bool OQueryController::doSaveAsDoc(bool _bSaveAs)
+{
+ OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
+ if ( !editingCommand() && !haveDataSource() )
+ {
+ OUString aMessage(DBA_RES(STR_DATASOURCE_DELETED));
+ OSQLWarningBox aBox(getFrameWeld(), aMessage);
+ aBox.run();
+ return false;
+ }
+
+ Reference< XNameAccess > xElements = getObjectContainer();
+ if ( !xElements.is() )
+ return false;
+
+ if ( !getContainer()->checkStatement() )
+ return false;
+
+ OUString sTranslatedStmt = translateStatement();
+ if ( editingCommand() )
+ {
+ setModified( false );
+ // this is all we need to do here. translateStatement implicitly set our m_sStatement, and
+ // notified it, and that's all
+ return true;
+ }
+
+ if ( sTranslatedStmt.isEmpty() )
+ return false;
+
+ // first we need a name for our query so ask the user
+ // did we get a name
+ OUString sOriginalName( m_sName );
+ if ( !askForNewName( xElements, _bSaveAs ) || m_sName.isEmpty() )
+ return false;
+
+ SQLExceptionInfo aInfo;
+ bool bSuccess = false;
+ bool bNew = false;
+ try
+ {
+ bNew = _bSaveAs
+ || ( !xElements->hasByName( m_sName ) );
+
+ Reference<XPropertySet> xQuery;
+ if ( bNew ) // just to make sure the query already exists
+ {
+ // drop the query, in case it already exists
+ if ( xElements->hasByName( m_sName ) )
+ {
+ Reference< XDrop > xNameCont( xElements, UNO_QUERY );
+ if ( xNameCont.is() )
+ xNameCont->dropByName( m_sName );
+ else
+ {
+ Reference< XNameContainer > xCont( xElements, UNO_QUERY );
+ if ( xCont.is() )
+ xCont->removeByName( m_sName );
+ }
+ }
+
+ // create a new (empty, uninitialized) query resp. view
+ Reference< XDataDescriptorFactory > xFact( xElements, UNO_QUERY );
+ if ( xFact.is() )
+ {
+ xQuery = xFact->createDataDescriptor();
+ // to set the name is only allowed when the query is new
+ xQuery->setPropertyValue( PROPERTY_NAME, Any( m_sName ) );
+ }
+ else
+ {
+ Reference< XSingleServiceFactory > xSingleFac( xElements, UNO_QUERY );
+ if ( xSingleFac.is() )
+ xQuery.set(xSingleFac->createInstance(), css::uno::UNO_QUERY);
+ }
+ }
+ else
+ {
+ xElements->getByName( m_sName ) >>= xQuery;
+ }
+ if ( !xQuery.is() )
+ throw RuntimeException();
+
+ // the new commands
+ if ( editingView() && !bNew )
+ {
+ OSL_ENSURE( xQuery == m_xAlterView, "OQueryController::doSaveAsDoc: already have another alterable view ...!?" );
+ m_xAlterView.set( xQuery, UNO_QUERY_THROW );
+ m_xAlterView->alterCommand( sTranslatedStmt );
+ }
+ else
+ { // we're creating a query, or a *new* view
+ xQuery->setPropertyValue( PROPERTY_COMMAND, Any( sTranslatedStmt ) );
+
+ if ( editingView() )
+ {
+ xQuery->setPropertyValue( PROPERTY_CATALOGNAME, Any( m_sUpdateCatalogName ) );
+ xQuery->setPropertyValue( PROPERTY_SCHEMANAME, Any( m_sUpdateSchemaName ) );
+ }
+
+ if ( editingQuery() )
+ {
+ xQuery->setPropertyValue( PROPERTY_UPDATE_TABLENAME, Any( OUString() ) );
+ xQuery->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, css::uno::Any( m_bEscapeProcessing ) );
+
+ xQuery->setPropertyValue( PROPERTY_LAYOUTINFORMATION, getViewData() );
+ }
+ }
+
+ if ( bNew )
+ {
+ Reference< XAppend > xAppend( xElements, UNO_QUERY );
+ if ( xAppend.is() )
+ {
+ xAppend->appendByDescriptor( xQuery );
+ }
+ else
+ {
+ Reference< XNameContainer > xCont( xElements, UNO_QUERY );
+ if ( xCont.is() )
+ xCont->insertByName( m_sName, Any( xQuery ) );
+ }
+
+ if ( editingView() )
+ {
+ Reference< XPropertySet > xViewProps;
+ if ( xElements->hasByName( m_sName ) )
+ xViewProps.set( xElements->getByName( m_sName ), UNO_QUERY );
+
+ if ( !xViewProps.is() ) // correct name and try again
+ m_sName = ::dbtools::composeTableName( getMetaData(), xQuery, ::dbtools::EComposeRule::InDataManipulation, false );
+
+ OSL_ENSURE( xElements->hasByName( m_sName ), "OQueryController::doSaveAsDoc: newly created view does not exist!" );
+
+ if ( xElements->hasByName( m_sName ) )
+ m_xAlterView.set( xElements->getByName( m_sName ), UNO_QUERY );
+
+ // now check if our datasource has set a tablefilter and if so, append the new table name to it
+ ::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld());
+ }
+ Reference< XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
+ if ( xEventListener.is() )
+ {
+ TitleChangedEvent aEvent;
+ xEventListener->titleChanged(aEvent);
+ }
+ releaseNumberForComponent();
+ }
+
+ setModified( false );
+ bSuccess = true;
+
+ }
+ catch(const SQLException&)
+ {
+ if ( !bNew )
+ m_sName = sOriginalName;
+ aInfo = SQLExceptionInfo( ::cppu::getCaughtException() );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ if ( !bNew )
+ m_sName = sOriginalName;
+ }
+
+ showError( aInfo );
+
+ // if we successfully saved a view we were creating, then close the designer
+ if ( bSuccess && editingView() && !m_xAlterView.is() )
+ {
+ closeTask();
+ }
+
+ if ( bSuccess && editingView() )
+ InvalidateFeature( ID_BROWSER_EDITDOC );
+
+ return bSuccess;
+}
+
+namespace {
+struct CommentStrip
+{
+ OUString maComment;
+ bool mbLastOnLine;
+ CommentStrip( const OUString& rComment, bool bLastOnLine )
+ : maComment( rComment), mbLastOnLine( bLastOnLine) {}
+};
+
+}
+
+/** Obtain all comments in a query.
+
+ See also delComment() implementation for OSQLParser::parseTree().
+ */
+static std::vector< CommentStrip > getComment( const OUString& rQuery )
+{
+ std::vector< CommentStrip > aRet;
+ // First a quick search if there is any "--" or "//" or "/*", if not then
+ // the whole copying loop is pointless.
+ if (rQuery.indexOf( "--" ) < 0 && rQuery.indexOf( "//" ) < 0 &&
+ rQuery.indexOf( "/*" ) < 0)
+ return aRet;
+
+ const sal_Unicode* pCopy = rQuery.getStr();
+ const sal_Int32 nQueryLen = rQuery.getLength();
+ bool bIsText1 = false; // "text"
+ bool bIsText2 = false; // 'text'
+ bool bComment2 = false; // /* comment */
+ bool bComment = false; // -- or // comment
+ OUStringBuffer aBuf;
+ for (sal_Int32 i=0; i < nQueryLen; ++i)
+ {
+ if (bComment2)
+ {
+ aBuf.append( &pCopy[i], 1);
+ if ((i+1) < nQueryLen)
+ {
+ if (pCopy[i]=='*' && pCopy[i+1]=='/')
+ {
+ bComment2 = false;
+ aBuf.append( &pCopy[++i], 1);
+ aRet.emplace_back( aBuf.makeStringAndClear(), false);
+ }
+ }
+ else
+ {
+ // comment can't close anymore, actually an error, but...
+ aRet.emplace_back( aBuf.makeStringAndClear(), false);
+ }
+ continue;
+ }
+ if (pCopy[i] == '\n' || i == nQueryLen-1)
+ {
+ if (bComment)
+ {
+ if (i == nQueryLen-1 && pCopy[i] != '\n')
+ aBuf.append( &pCopy[i], 1);
+ aRet.emplace_back( aBuf.makeStringAndClear(), true);
+ bComment = false;
+ }
+ else if (!aRet.empty())
+ aRet.back().mbLastOnLine = true;
+ }
+ else if (!bComment)
+ {
+ if (pCopy[i] == '\"' && !bIsText2)
+ bIsText1 = !bIsText1;
+ else if (pCopy[i] == '\'' && !bIsText1)
+ bIsText2 = !bIsText2;
+ if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
+ {
+ if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
+ bComment = true;
+ else if (pCopy[i]=='/' && pCopy[i+1]=='*')
+ bComment2 = true;
+ }
+ }
+ if (bComment || bComment2)
+ aBuf.append( &pCopy[i], 1);
+ }
+ return aRet;
+}
+
+/** Concat/insert comments that were previously obtained with getComment().
+
+ NOTE: The current parser implementation does not preserve newlines, so all
+ comments are always appended to the entire query, also inline comments
+ that would need positioning anyway that can't be obtained after
+ recomposition. This is ugly but at least allows commented queries while
+ preserving the comments _somehow_.
+ */
+static OUString concatComment( const OUString& rQuery, const std::vector< CommentStrip >& rComments )
+{
+ // No comments => return query.
+ if (rComments.empty())
+ return rQuery;
+
+ const sal_Unicode* pBeg = rQuery.getStr();
+ const sal_Int32 nLen = rQuery.getLength();
+ const size_t nComments = rComments.size();
+ // Obtaining the needed size once should be faster than reallocating.
+ // Also add a blank or linefeed for each comment.
+ sal_Int32 nBufSize = nLen + nComments;
+ for (auto const& comment : rComments)
+ nBufSize += comment.maComment.getLength();
+ OUStringBuffer aBuf( nBufSize );
+ sal_Int32 nIndBeg = 0;
+ sal_Int32 nIndLF = rQuery.indexOf('\n');
+ size_t i = 0;
+ while (nIndLF >= 0 && i < nComments)
+ {
+ aBuf.append( pBeg + nIndBeg, nIndLF - nIndBeg);
+ do
+ {
+ aBuf.append( rComments[i].maComment);
+ } while (!rComments[i++].mbLastOnLine && i < nComments);
+ aBuf.append( pBeg + nIndLF, 1); // the LF
+ nIndBeg = nIndLF + 1;
+ nIndLF = (nIndBeg < nLen ? rQuery.indexOf( '\n', nIndBeg) : -1);
+ }
+ // Append remainder of query.
+ if (nIndBeg < nLen)
+ aBuf.append( pBeg + nIndBeg, nLen - nIndBeg);
+ // Append all remaining comments, preserve lines.
+ bool bNewLine = false;
+ for ( ; i < nComments; ++i)
+ {
+ if (!bNewLine)
+ aBuf.append( ' ');
+ aBuf.append( rComments[i].maComment);
+ if (rComments[i].mbLastOnLine)
+ {
+ aBuf.append( '\n');
+ bNewLine = true;
+ }
+ else
+ bNewLine = false;
+ }
+ return aBuf.makeStringAndClear();
+}
+
+OUString OQueryController::translateStatement( bool _bFireStatementChange )
+{
+ // now set the properties
+ setStatement_fireEvent( getContainer()->getStatement(), _bFireStatementChange );
+ OUString sTranslatedStmt;
+ if(!m_sStatement.isEmpty() && m_xComposer.is() && m_bEscapeProcessing)
+ {
+ try
+ {
+ OUString aErrorMsg;
+
+ std::vector< CommentStrip > aComments = getComment( m_sStatement);
+
+ std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
+ if(pNode)
+ {
+ pNode->parseNodeToStr( sTranslatedStmt, getConnection() );
+ }
+
+ m_xComposer->setQuery(sTranslatedStmt);
+ sTranslatedStmt = m_xComposer->getComposedQuery();
+ sTranslatedStmt = concatComment( sTranslatedStmt, aComments);
+ }
+ catch(const SQLException& e)
+ {
+ ::dbtools::SQLExceptionInfo aInfo(e);
+ showError(aInfo);
+ // an error occurred so we clear the statement
+ sTranslatedStmt.clear();
+ }
+ }
+ else if(m_sStatement.isEmpty())
+ {
+ showError(SQLException(DBA_RES(STR_QRY_NOSELECT), nullptr, "S1000", 1000, Any()));
+ }
+ else
+ sTranslatedStmt = m_sStatement;
+
+ return sTranslatedStmt;
+}
+
+short OQueryController::saveModified()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ short nRet = RET_YES;
+ if ( !isConnected() || !isModified() )
+ return nRet;
+
+ if ( !m_bGraphicalDesign
+ || ( !m_vTableFieldDesc.empty()
+ && !m_vTableData.empty()
+ )
+ )
+ {
+ OUString sMessageText( lcl_getObjectResourceString( STR_QUERY_SAVEMODIFIED, m_nCommandType ) );
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ sMessageText));
+ xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ xQueryBox->set_default_response(RET_YES);
+
+ nRet = xQueryBox->run();
+ if ( ( nRet == RET_YES )
+ && !doSaveAsDoc( false )
+ )
+ {
+ nRet = RET_CANCEL;
+ }
+ }
+ return nRet;
+}
+
+void OQueryController::impl_reset( const bool i_bForceCurrentControllerSettings )
+{
+ bool bValid = false;
+
+ Sequence< PropertyValue > aLayoutInformation;
+ // get command from the query if a query name was supplied
+ if ( !i_bForceCurrentControllerSettings && !editingCommand() )
+ {
+ if ( !m_sName.isEmpty() )
+ {
+ Reference< XNameAccess > xQueries = getObjectContainer();
+ if ( xQueries.is() )
+ {
+ Reference< XPropertySet > xProp;
+ if( xQueries->hasByName( m_sName ) && ( xQueries->getByName( m_sName ) >>= xProp ) && xProp.is() )
+ {
+ OUString sNewStatement;
+ xProp->getPropertyValue( PROPERTY_COMMAND ) >>= sNewStatement;
+ setStatement_fireEvent( sNewStatement );
+
+ if ( editingQuery() )
+ {
+ bool bNewEscapeProcessing( true );
+ xProp->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bNewEscapeProcessing;
+ setEscapeProcessing_fireEvent( bNewEscapeProcessing );
+ }
+
+ m_bGraphicalDesign = m_bGraphicalDesign && m_bEscapeProcessing;
+ bValid = true;
+
+ try
+ {
+ if ( editingQuery() )
+ xProp->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) >>= aLayoutInformation;
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "OQueryController::impl_reset: could not retrieve the layout information from the query!" );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ bValid = true;
+ // assume that we got all necessary information during initialization
+ }
+
+ if ( bValid )
+ {
+ // load the layoutInformation
+ if ( aLayoutInformation.hasElements() )
+ {
+ try
+ {
+ loadViewSettings( aLayoutInformation );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ if ( !m_sStatement.isEmpty() )
+ {
+ setQueryComposer();
+
+ bool bError( false );
+
+ if ( !m_pSqlIterator )
+ {
+ bError = true;
+ }
+ else if ( m_bEscapeProcessing )
+ {
+ OUString aErrorMsg;
+ std::unique_ptr< ::connectivity::OSQLParseNode > pNode(
+ m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign ) );
+
+ if (pNode)
+ {
+ delete m_pSqlIterator->getParseTree();
+ m_pSqlIterator->setParseTree( pNode.release() );
+ m_pSqlIterator->traverseAll();
+ if ( m_pSqlIterator->hasErrors() )
+ {
+ if ( !i_bForceCurrentControllerSettings && m_bGraphicalDesign && !editingView() )
+ {
+ impl_showAutoSQLViewError( Any( m_pSqlIterator->getErrors() ) );
+ }
+ bError = true;
+ }
+ }
+ else
+ {
+ if ( !i_bForceCurrentControllerSettings && !editingView() )
+ {
+ OUString aTitle(DBA_RES(STR_SVT_SQL_SYNTAX_ERROR));
+ OSQLMessageBox aDlg(getFrameWeld(), aTitle, aErrorMsg);
+ aDlg.run();
+ }
+ bError = true;
+ }
+ }
+
+ if ( bError )
+ {
+ m_bGraphicalDesign = false;
+ if ( editingView() )
+ // if we're editing a view whose statement could not be parsed, default to "no escape processing"
+ setEscapeProcessing_fireEvent( false );
+ }
+ }
+ }
+
+ if(!m_pSqlIterator)
+ setQueryComposer();
+ OSL_ENSURE(m_pSqlIterator,"No SQLIterator set!");
+
+ getContainer()->setNoneVisibleRow(m_nVisibleRows);
+}
+
+void OQueryController::reset()
+{
+ impl_reset();
+ getContainer()->reset();
+ ClearUndoManager();
+}
+
+void OQueryController::setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange )
+{
+ Any aOldValue( m_sStatement );
+ m_sStatement = _rNewStatement;
+ Any aNewValue( m_sStatement );
+
+ sal_Int32 nHandle = PROPERTY_ID_ACTIVECOMMAND;
+ if ( _bFireStatementChange )
+ fire( &nHandle, &aNewValue, &aOldValue, 1, false );
+}
+
+void OQueryController::setEscapeProcessing_fireEvent( const bool _bEscapeProcessing )
+{
+ if ( _bEscapeProcessing == m_bEscapeProcessing )
+ return;
+
+ Any aOldValue( m_bEscapeProcessing );
+ m_bEscapeProcessing = _bEscapeProcessing;
+ Any aNewValue( m_bEscapeProcessing );
+
+ sal_Int32 nHandle = PROPERTY_ID_ESCAPE_PROCESSING;
+ fire( &nHandle, &aNewValue, &aOldValue, 1, false );
+}
+
+IMPL_LINK_NOARG( OQueryController, OnExecuteAddTable, void*, void )
+{
+ Execute( ID_BROWSER_ADDTABLE,Sequence<PropertyValue>() );
+}
+
+bool OQueryController::allowViews() const
+{
+ return true;
+}
+
+bool OQueryController::allowQueries() const
+{
+ OSL_ENSURE( getSdbMetaData().isConnected(), "OQueryController::allowQueries: illegal call!" );
+ if ( !getSdbMetaData().supportsSubqueriesInFrom() )
+ return false;
+
+ const NamedValueCollection& rArguments( getInitParams() );
+ sal_Int32 nCommandType = rArguments.getOrDefault( PROPERTY_COMMAND_TYPE, sal_Int32(CommandType::QUERY) );
+ bool bCreatingView = ( nCommandType == CommandType::TABLE );
+ return !bCreatingView;
+}
+
+Any SAL_CALL OQueryController::getViewData()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ getContainer()->SaveUIConfig();
+
+ ::comphelper::NamedValueCollection aViewSettings;
+ saveViewSettings( aViewSettings, false );
+
+ return Any( aViewSettings.getPropertyValues() );
+}
+
+void SAL_CALL OQueryController::restoreViewData(const Any& /*Data*/)
+{
+ // TODO
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/querydlg.cxx b/dbaccess/source/ui/querydesign/querydlg.cxx
new file mode 100644
index 000000000..5a21998d9
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/querydlg.cxx
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "querydlg.hxx"
+#include <JoinController.hxx>
+#include <JoinDesignView.hxx>
+#include <strings.hrc>
+#include <tools/diagnose_ex.h>
+#include "QTableConnectionData.hxx"
+#include <core_resource.hxx>
+#include <QueryTableView.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <RelationControl.hxx>
+
+#define ID_INNER_JOIN 1
+#define ID_LEFT_JOIN 2
+#define ID_RIGHT_JOIN 3
+#define ID_FULL_JOIN 4
+#define ID_CROSS_JOIN 5
+
+using namespace dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbc;
+
+DlgQryJoin::DlgQryJoin(const OQueryTableView* pParent,
+ const TTableConnectionData::value_type& _pData,
+ const OJoinTableView::OTableWindowMap* _pTableMap,
+ const Reference< XConnection >& _xConnection,
+ bool _bAllowTableSelect)
+ : GenericDialogController(pParent->GetFrameWeld(), "dbaccess/ui/joindialog.ui", "JoinDialog")
+ , eJoinType(static_cast<OQueryTableConnectionData*>(_pData.get())->GetJoinType())
+ , m_pOrigConnData(_pData)
+ , m_xConnection(_xConnection)
+ , m_xML_HelpText(m_xBuilder->weld_label("helptext"))
+ , m_xPB_OK(m_xBuilder->weld_button("ok"))
+ , m_xLB_JoinType(m_xBuilder->weld_combo_box("type"))
+ , m_xCBNatural(m_xBuilder->weld_check_button("natural"))
+{
+ Size aSize(m_xML_HelpText->get_approximate_digit_width() * 44,
+ m_xML_HelpText->get_text_height() * 6);
+ //alternatively loop through the STR_QUERY_* strings with their STR_JOIN_TYPE_HINT
+ //suffix to find the longest entry at runtime
+ m_xML_HelpText->set_size_request(aSize.Width(), aSize.Height());
+
+ // Copy connection
+ m_pConnData = _pData->NewInstance();
+ m_pConnData->CopyFrom(*_pData);
+
+ m_xTableControl.reset(new OTableListBoxControl(m_xBuilder.get(), _pTableMap, this));
+
+ m_xCBNatural->set_active(static_cast<OQueryTableConnectionData*>(m_pConnData.get())->isNatural());
+
+ if( _bAllowTableSelect )
+ {
+ m_xTableControl->Init( m_pConnData );
+ m_xTableControl->fillListBoxes();
+ }
+ else
+ {
+ m_xTableControl->fillAndDisable(m_pConnData);
+ m_xTableControl->Init( m_pConnData );
+ }
+
+ m_xTableControl->lateUIInit();
+
+ bool bSupportFullJoin = false;
+ Reference<XDatabaseMetaData> xMeta;
+ try
+ {
+ xMeta = m_xConnection->getMetaData();
+ if ( xMeta.is() )
+ bSupportFullJoin = xMeta->supportsFullOuterJoins();
+ }
+ catch(SQLException&)
+ {
+ }
+ bool bSupportOuterJoin = false;
+ try
+ {
+ if ( xMeta.is() )
+ bSupportOuterJoin= xMeta->supportsOuterJoins();
+ }
+ catch(SQLException&)
+ {
+ }
+
+ setJoinType(eJoinType);
+
+ m_xPB_OK->connect_clicked(LINK(this, DlgQryJoin, OKClickHdl));
+
+ m_xLB_JoinType->connect_changed(LINK(this,DlgQryJoin,LBChangeHdl));
+ m_xCBNatural->connect_toggled(LINK(this,DlgQryJoin,NaturalToggleHdl));
+
+ if ( pParent->getDesignView()->getController().isReadOnly() )
+ {
+ m_xLB_JoinType->set_sensitive(false);
+ m_xCBNatural->set_sensitive(false);
+ m_xTableControl->Disable();
+ }
+ else
+ {
+ for (sal_Int32 i = 0; i < m_xLB_JoinType->get_count();)
+ {
+ const sal_Int32 nJoinTyp = m_xLB_JoinType->get_id(i).toInt32();
+ if ( !bSupportFullJoin && nJoinTyp == ID_FULL_JOIN )
+ m_xLB_JoinType->remove(i);
+ else if ( !bSupportOuterJoin && (nJoinTyp == ID_LEFT_JOIN || nJoinTyp == ID_RIGHT_JOIN) )
+ m_xLB_JoinType->remove(i);
+ else
+ ++i;
+ }
+
+ m_xTableControl->NotifyCellChange();
+ m_xTableControl->enableRelation(!static_cast<OQueryTableConnectionData*>(m_pConnData.get())->isNatural() && eJoinType != CROSS_JOIN );
+ }
+}
+
+DlgQryJoin::~DlgQryJoin()
+{
+}
+
+IMPL_LINK_NOARG( DlgQryJoin, LBChangeHdl, weld::ComboBox&, void )
+{
+ if (!m_xLB_JoinType->get_value_changed_from_saved())
+ return;
+
+ m_xLB_JoinType->save_value();
+ m_xML_HelpText->set_label(OUString());
+
+ m_xTableControl->enableRelation(true);
+
+ OUString sFirstWinName = m_pConnData->getReferencingTable()->GetWinName();
+ OUString sSecondWinName = m_pConnData->getReferencedTable()->GetWinName();
+ const EJoinType eOldJoinType = eJoinType;
+ TranslateId pResId;
+ const sal_Int32 nPos = m_xLB_JoinType->get_active();
+ const sal_Int32 nJoinType = m_xLB_JoinType->get_id(nPos).toInt32();
+ bool bAddHint = true;
+ switch ( nJoinType )
+ {
+ default:
+ case ID_INNER_JOIN:
+ pResId = STR_QUERY_INNER_JOIN;
+ bAddHint = false;
+ eJoinType = INNER_JOIN;
+ break;
+ case ID_LEFT_JOIN:
+ pResId = STR_QUERY_LEFTRIGHT_JOIN;
+ eJoinType = LEFT_JOIN;
+ break;
+ case ID_RIGHT_JOIN:
+ {
+ pResId = STR_QUERY_LEFTRIGHT_JOIN;
+ eJoinType = RIGHT_JOIN;
+ OUString sTemp = sFirstWinName;
+ sFirstWinName = sSecondWinName;
+ sSecondWinName = sTemp;
+ }
+ break;
+ case ID_FULL_JOIN:
+ pResId = STR_QUERY_FULL_JOIN;
+ eJoinType = FULL_JOIN;
+ break;
+ case ID_CROSS_JOIN:
+ {
+ pResId = STR_QUERY_CROSS_JOIN;
+ eJoinType = CROSS_JOIN;
+
+ m_pConnData->ResetConnLines();
+ m_xTableControl->lateInit();
+ m_xCBNatural->set_active(false);
+ m_xTableControl->enableRelation(false);
+ m_pConnData->AppendConnLine("","");
+ m_xPB_OK->set_sensitive(true);
+ }
+ break;
+ }
+
+ m_xCBNatural->set_sensitive(eJoinType != CROSS_JOIN);
+
+ if ( eJoinType != eOldJoinType && eOldJoinType == CROSS_JOIN )
+ {
+ m_pConnData->ResetConnLines();
+ }
+ if ( eJoinType != CROSS_JOIN )
+ {
+ m_xTableControl->NotifyCellChange();
+ NaturalToggleHdl(*m_xCBNatural);
+ }
+
+ m_xTableControl->Invalidate();
+
+ OUString sHelpText = DBA_RES(pResId);
+ if( nPos )
+ {
+ sHelpText = sHelpText.replaceFirst( "%1", sFirstWinName );
+ sHelpText = sHelpText.replaceFirst( "%2", sSecondWinName );
+ }
+ if ( bAddHint )
+ {
+ sHelpText += "\n" + DBA_RES( STR_JOIN_TYPE_HINT );
+ }
+
+ m_xML_HelpText->set_label( sHelpText );
+}
+
+IMPL_LINK_NOARG(DlgQryJoin, OKClickHdl, weld::Button&, void)
+{
+ m_pConnData->Update();
+ m_pOrigConnData->CopyFrom( *m_pConnData );
+
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(DlgQryJoin, NaturalToggleHdl, weld::Toggleable&, void)
+{
+ bool bChecked = m_xCBNatural->get_active();
+ static_cast<OQueryTableConnectionData*>(m_pConnData.get())->setNatural(bChecked);
+ m_xTableControl->enableRelation(!bChecked);
+ if ( !bChecked )
+ return;
+
+ m_pConnData->ResetConnLines();
+ try
+ {
+ Reference<XNameAccess> xReferencedTableColumns(m_pConnData->getReferencedTable()->getColumns());
+ Sequence< OUString> aSeq = m_pConnData->getReferencingTable()->getColumns()->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( xReferencedTableColumns->hasByName(*pIter) )
+ m_pConnData->AppendConnLine(*pIter,*pIter);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xTableControl->NotifyCellChange();
+ m_xTableControl->Invalidate();
+}
+
+void DlgQryJoin::setValid(bool _bValid)
+{
+ m_xPB_OK->set_sensitive(_bValid || eJoinType == CROSS_JOIN );
+}
+
+void DlgQryJoin::notifyConnectionChange( )
+{
+ setJoinType( static_cast<OQueryTableConnectionData*>(m_pConnData.get())->GetJoinType() );
+ m_xCBNatural->set_active(static_cast<OQueryTableConnectionData*>(m_pConnData.get())->isNatural());
+ NaturalToggleHdl(*m_xCBNatural);
+}
+
+void DlgQryJoin::setJoinType(EJoinType _eNewJoinType)
+{
+ eJoinType = _eNewJoinType;
+ m_xCBNatural->set_sensitive(eJoinType != CROSS_JOIN);
+
+ sal_Int32 nJoinType = 0;
+ switch ( eJoinType )
+ {
+ default:
+ case INNER_JOIN:
+ nJoinType = ID_INNER_JOIN;
+ break;
+ case LEFT_JOIN:
+ nJoinType = ID_LEFT_JOIN;
+ break;
+ case RIGHT_JOIN:
+ nJoinType = ID_RIGHT_JOIN;
+ break;
+ case FULL_JOIN:
+ nJoinType = ID_FULL_JOIN;
+ break;
+ case CROSS_JOIN:
+ nJoinType = ID_CROSS_JOIN;
+ break;
+ }
+
+ const sal_Int32 nCount = m_xLB_JoinType->get_count();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ if (nJoinType == m_xLB_JoinType->get_id(i).toInt32())
+ {
+ m_xLB_JoinType->set_active(i);
+ break;
+ }
+ }
+
+ LBChangeHdl(*m_xLB_JoinType);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/querydesign/querydlg.hxx b/dbaccess/source/ui/querydesign/querydlg.hxx
new file mode 100644
index 000000000..3da416c6e
--- /dev/null
+++ b/dbaccess/source/ui/querydesign/querydlg.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+#include <QEnumTypes.hxx>
+
+#include <RelControliFace.hxx>
+#include <JoinTableView.hxx>
+
+
+namespace dbaui
+{
+ class OTableListBoxControl;
+ class OQueryTableView;
+ class DlgQryJoin final : public weld::GenericDialogController
+ , public IRelationControlInterface
+ {
+ EJoinType eJoinType;
+ TTableConnectionData::value_type m_pConnData; // contains left and right table
+ TTableConnectionData::value_type m_pOrigConnData;
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ std::unique_ptr<weld::Label> m_xML_HelpText;
+ std::unique_ptr<weld::Button> m_xPB_OK;
+ std::unique_ptr<weld::ComboBox> m_xLB_JoinType;
+ std::unique_ptr<weld::CheckButton> m_xCBNatural;
+ std::unique_ptr<OTableListBoxControl> m_xTableControl;
+
+ DECL_LINK(OKClickHdl, weld::Button&, void);
+ DECL_LINK(LBChangeHdl, weld::ComboBox&, void);
+ DECL_LINK(NaturalToggleHdl, weld::Toggleable&, void);
+
+ /** setJoinType enables and set the new join type
+ @param _eNewJoinType the new jointype
+ */
+ void setJoinType(EJoinType _eNewJoinType);
+ public:
+ DlgQryJoin( const OQueryTableView * pParent,
+ const TTableConnectionData::value_type& pData,
+ const OJoinTableView::OTableWindowMap* _pTableMap,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ bool _bAllowTableSelect);
+ virtual ~DlgQryJoin() override;
+ EJoinType GetJoinType() const { return eJoinType; };
+
+ /** setValid set the valid inside, can be used for OK buttons
+ @param _bValid true when the using control allows an update
+ */
+ virtual void setValid(bool _bValid) override;
+
+ /** notifyConnectionChange is callback which is called when the table selection has changed and a new connection exists
+ @param _pConnectionData the connection which exists between the new tables
+ */
+ virtual void notifyConnectionChange() override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/relationdesign/RTableConnection.cxx b/dbaccess/source/ui/relationdesign/RTableConnection.cxx
new file mode 100644
index 000000000..ba60ae546
--- /dev/null
+++ b/dbaccess/source/ui/relationdesign/RTableConnection.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "RTableConnection.hxx"
+#include <RTableConnectionData.hxx>
+#include <RelationTableView.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <ConnectionLine.hxx>
+
+using namespace dbaui;
+ORelationTableConnection::ORelationTableConnection( ORelationTableView* pContainer,
+ const TTableConnectionData::value_type& pTabConnData )
+ :OTableConnection( pContainer, pTabConnData )
+{
+}
+
+ORelationTableConnection::ORelationTableConnection( const ORelationTableConnection& rConn )
+ : VclReferenceBase(), OTableConnection( rConn )
+{
+ // no own members, thus the base class functionality is enough
+}
+
+ORelationTableConnection& ORelationTableConnection::operator=( const ORelationTableConnection& rConn )
+{
+ // this doesn't change anything, since the base class tests this, too and I don't have my own members to copy
+ if (&rConn == this)
+ return *this;
+
+ OTableConnection::operator=( rConn );
+ return *this;
+}
+
+void ORelationTableConnection::Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
+{
+ OTableConnection::Draw(rRenderContext, rRect);
+ ORelationTableConnectionData* pData = static_cast< ORelationTableConnectionData* >(GetData().get());
+ if (pData && (pData->GetCardinality() == Cardinality::Undefined))
+ return;
+
+ // search lines for top line
+ tools::Rectangle aBoundingRect;
+ tools::Long nTop = GetBoundingRect().Bottom();
+ tools::Long nTemp;
+
+ const OConnectionLine* pTopLine = nullptr;
+ const std::vector<std::unique_ptr<OConnectionLine>>& rConnLineList = GetConnLineList();
+
+ for (auto const& elem : rConnLineList)
+ {
+ if( elem->IsValid() )
+ {
+ aBoundingRect = elem->GetBoundingRect();
+ nTemp = aBoundingRect.Top();
+ if(nTemp < nTop)
+ {
+ nTop = nTemp;
+ pTopLine = elem.get();
+ }
+ }
+ }
+
+ // cardinality
+ if (!pTopLine)
+ return;
+
+ tools::Rectangle aSourcePos = pTopLine->GetSourceTextPos();
+ tools::Rectangle aDestPos = pTopLine->GetDestTextPos();
+
+ OUString aSourceText;
+ OUString aDestText;
+
+ switch (pData->GetCardinality())
+ {
+ case Cardinality::OneMany:
+ aSourceText = "1";
+ aDestText = "n";
+ break;
+
+ case Cardinality::ManyOne:
+ aSourceText = "n";
+ aDestText = "1";
+ break;
+
+ case Cardinality::OneOne:
+ aSourceText = "1";
+ aDestText = "1";
+ break;
+ default: break;
+ }
+
+ if (IsSelected())
+ rRenderContext.SetTextColor(Application::GetSettings().GetStyleSettings().GetHighlightColor());
+ else
+ rRenderContext.SetTextColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor());
+
+ rRenderContext.DrawText(aSourcePos, aSourceText, DrawTextFlags::Clip | DrawTextFlags::Center | DrawTextFlags::Bottom);
+ rRenderContext.DrawText(aDestPos, aDestText, DrawTextFlags::Clip | DrawTextFlags::Center | DrawTextFlags::Bottom);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/relationdesign/RTableConnection.hxx b/dbaccess/source/ui/relationdesign/RTableConnection.hxx
new file mode 100644
index 000000000..0448d494f
--- /dev/null
+++ b/dbaccess/source/ui/relationdesign/RTableConnection.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableConnection.hxx>
+
+namespace dbaui
+{
+ class ORelationTableView;
+ class ORelationTableConnection : public OTableConnection
+ {
+ public:
+ ORelationTableConnection( ORelationTableView* pContainer, const TTableConnectionData::value_type& pTabConnData );
+ ORelationTableConnection( const ORelationTableConnection& rConn );
+ // important comment to the CopyConstructor see OTableConnection(const OTableConnection&)
+
+ ORelationTableConnection& operator=( const ORelationTableConnection& rConn );
+
+ virtual void Draw(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ using OTableConnection::Draw;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx b/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx
new file mode 100644
index 000000000..26b39b69c
--- /dev/null
+++ b/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx
@@ -0,0 +1,398 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <RTableConnectionData.hxx>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <osl/diagnose.h>
+
+using namespace dbaui;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+ORelationTableConnectionData::ORelationTableConnectionData()
+ :m_nUpdateRules(KeyRule::NO_ACTION)
+ ,m_nDeleteRules(KeyRule::NO_ACTION)
+ ,m_nCardinality(Cardinality::Undefined)
+{
+}
+
+ORelationTableConnectionData::ORelationTableConnectionData( const TTableWindowData::value_type& _pReferencingTable,
+ const TTableWindowData::value_type& _pReferencedTable,
+ const OUString& rConnName )
+ :OTableConnectionData( _pReferencingTable, _pReferencedTable )
+ ,m_nUpdateRules(KeyRule::NO_ACTION)
+ ,m_nDeleteRules(KeyRule::NO_ACTION)
+ ,m_nCardinality(Cardinality::Undefined)
+{
+ m_aConnName = rConnName;
+
+ if ( !m_aConnName.isEmpty() )
+ SetCardinality();
+}
+
+ORelationTableConnectionData::ORelationTableConnectionData( const ORelationTableConnectionData& rConnData )
+ :OTableConnectionData( rConnData )
+{
+ *this = rConnData;
+}
+
+ORelationTableConnectionData::~ORelationTableConnectionData()
+{
+}
+
+void ORelationTableConnectionData::DropRelation()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // delete relation
+ Reference< XIndexAccess> xKeys = getReferencingTable()->getKeys();
+ if( m_aConnName.isEmpty() || !xKeys.is() )
+ return;
+
+ const sal_Int32 nCount = xKeys->getCount();
+ for(sal_Int32 i = 0;i < nCount;++i)
+ {
+ Reference< XPropertySet> xKey(xKeys->getByIndex(i),UNO_QUERY);
+ OSL_ENSURE(xKey.is(),"Key is not valid!");
+ if(xKey.is())
+ {
+ OUString sName;
+ xKey->getPropertyValue(PROPERTY_NAME) >>= sName;
+ if(sName == m_aConnName)
+ {
+ Reference< XDrop> xDrop(xKeys,UNO_QUERY);
+ OSL_ENSURE(xDrop.is(),"can't drop key because we haven't a drop interface!");
+ if(xDrop.is())
+ xDrop->dropByIndex(i);
+ break;
+ }
+ }
+ }
+}
+
+void ORelationTableConnectionData::ChangeOrientation()
+{
+ // exchange Source- and DestFieldName of the lines
+ OUString sTempString;
+ for (auto const& elem : m_vConnLineData)
+ {
+ sTempString = elem->GetSourceFieldName();
+ elem->SetSourceFieldName( elem->GetDestFieldName() );
+ elem->SetDestFieldName( sTempString );
+ }
+
+ // adapt member
+ TTableWindowData::value_type pTemp = m_pReferencingTable;
+ m_pReferencingTable = m_pReferencedTable;
+ m_pReferencedTable = pTemp;
+}
+
+void ORelationTableConnectionData::SetCardinality()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_nCardinality = Cardinality::Undefined;
+
+ if( IsSourcePrimKey() )
+ {
+ if( IsDestPrimKey() )
+ m_nCardinality = Cardinality::OneOne;
+ else
+ m_nCardinality = Cardinality::OneMany;
+ }
+
+ if( IsDestPrimKey() )
+ {
+ if( !IsSourcePrimKey() )
+ m_nCardinality = Cardinality::ManyOne;
+ }
+
+}
+
+bool ORelationTableConnectionData::checkPrimaryKey(const Reference< XPropertySet>& i_xTable,EConnectionSide _eEConnectionSide) const
+{
+ // check if Table has the primary key column depending on _eEConnectionSide
+ sal_uInt16 nPrimKeysCount = 0,
+ nValidLinesCount = 0;
+ const Reference< XNameAccess> xKeyColumns = dbtools::getPrimaryKeyColumns_throw(i_xTable);
+ if ( xKeyColumns.is() )
+ {
+ Sequence< OUString> aKeyColumns = xKeyColumns->getElementNames();
+ const OUString* pKeyIter = aKeyColumns.getConstArray();
+ const OUString* pKeyEnd = pKeyIter + aKeyColumns.getLength();
+
+ for(;pKeyIter != pKeyEnd;++pKeyIter)
+ {
+ for (auto const& elem : m_vConnLineData)
+ {
+ ++nValidLinesCount;
+ if ( elem->GetFieldName(_eEConnectionSide) == *pKeyIter )
+ {
+ ++nPrimKeysCount;
+ break;
+ }
+ }
+ }
+ if ( nPrimKeysCount != aKeyColumns.getLength() )
+ return false;
+ }
+ return nPrimKeysCount && nPrimKeysCount == nValidLinesCount;
+}
+
+void ORelationTableConnectionData::IsConnectionPossible()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // if the SourceFields are a PrimKey, it's only the orientation which is wrong
+ if ( IsSourcePrimKey() && !IsDestPrimKey() )
+ ChangeOrientation();
+}
+
+void ORelationTableConnectionData::CopyFrom(const OTableConnectionData& rSource)
+{
+ // retract to the (non-virtual) operator= like in the base class
+ *this = *static_cast<const ORelationTableConnectionData*>(&rSource);
+}
+
+ORelationTableConnectionData& ORelationTableConnectionData::operator=( const ORelationTableConnectionData& rConnData )
+{
+ if (&rConnData == this)
+ return *this;
+
+ OTableConnectionData::operator=( rConnData );
+ m_nUpdateRules = rConnData.GetUpdateRules();
+ m_nDeleteRules = rConnData.GetDeleteRules();
+ m_nCardinality = rConnData.GetCardinality();
+
+ return *this;
+}
+
+namespace dbaui
+{
+bool operator==(const ORelationTableConnectionData& lhs, const ORelationTableConnectionData& rhs)
+{
+ bool bEqual = (lhs.m_nUpdateRules == rhs.m_nUpdateRules)
+ && (lhs.m_nDeleteRules == rhs.m_nDeleteRules)
+ && (lhs.m_nCardinality == rhs.m_nCardinality)
+ && (lhs.getReferencingTable() == rhs.getReferencingTable())
+ && (lhs.getReferencedTable() == rhs.getReferencedTable())
+ && (lhs.m_aConnName == rhs.m_aConnName)
+ && (lhs.m_vConnLineData.size() == rhs.m_vConnLineData.size());
+
+ if ( bEqual )
+ {
+ sal_Int32 i = 0;
+ for (auto const& elem : lhs.m_vConnLineData)
+ {
+ if ( *(rhs.m_vConnLineData[i]) != *elem )
+ {
+ bEqual = false;
+ break;
+ }
+ ++i;
+ }
+ }
+ return bEqual;
+}
+
+}
+
+bool ORelationTableConnectionData::Update()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // delete old relation
+ {
+ DropRelation();
+ IsConnectionPossible();
+ }
+
+ // reassign the keys because the orientation could be changed
+ Reference<XPropertySet> xTableProp(getReferencingTable()->getTable());
+ Reference< XIndexAccess> xKeys ( getReferencingTable()->getKeys());
+
+ if ( !xKeys.is() )
+ return false;
+ // create new relation
+ Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
+ OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
+ Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
+ OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
+
+ Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
+ OSL_ENSURE(xKey.is(),"Key is null!");
+ if ( xKey.is() && xTableProp.is() )
+ {
+ // build a foreign key name
+ OUString sSourceName;
+ xTableProp->getPropertyValue(PROPERTY_NAME) >>= sSourceName;
+ OUString sKeyName = sSourceName + getReferencedTable()->GetTableName();
+
+ xKey->setPropertyValue(PROPERTY_NAME,Any(sKeyName));
+ xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::FOREIGN));
+ xKey->setPropertyValue(PROPERTY_REFERENCEDTABLE,Any(getReferencedTable()->GetTableName()));
+ xKey->setPropertyValue(PROPERTY_UPDATERULE, Any(GetUpdateRules()));
+ xKey->setPropertyValue(PROPERTY_DELETERULE, Any(GetDeleteRules()));
+ }
+
+ Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
+ if ( xColSup.is() )
+ {
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
+ Reference<XAppend> xColumnAppend(xColumns,UNO_QUERY);
+ if ( xColumnFactory.is() )
+ {
+ for (auto const& elem : m_vConnLineData)
+ {
+ if(!(elem->GetSourceFieldName().isEmpty() || elem->GetDestFieldName().isEmpty()))
+ {
+ Reference<XPropertySet> xColumn = xColumnFactory->createDataDescriptor();
+ if ( xColumn.is() )
+ {
+ xColumn->setPropertyValue(PROPERTY_NAME,Any(elem->GetSourceFieldName()));
+ xColumn->setPropertyValue(PROPERTY_RELATEDCOLUMN,Any(elem->GetDestFieldName()));
+ xColumnAppend->appendByDescriptor(xColumn);
+ }
+ }
+ }
+
+ if ( xColumns->hasElements() )
+ xAppend->appendByDescriptor(xKey);
+ }
+ // to get the key we have to reget it because after append it is no longer valid
+ }
+
+ // get the name of foreign key; search for columns
+ m_aConnName.clear();
+ xKey.clear();
+ bool bDropRelation = false;
+ for(sal_Int32 i=0;i<xKeys->getCount();++i)
+ {
+ xKeys->getByIndex(i) >>= xKey;
+ OSL_ENSURE(xKey.is(),"Key is not valid!");
+ if ( xKey.is() )
+ {
+ OUString sReferencedTable;
+ xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
+ if ( sReferencedTable == getReferencedTable()->GetTableName() )
+ {
+ xColSup.set(xKey,UNO_QUERY_THROW);
+ try
+ {
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ Sequence< OUString> aNames = xColumns->getElementNames();
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+
+ Reference<XPropertySet> xColumn;
+ OUString sName,sRelatedColumn;
+ for ( ; pIter != pEnd ; ++pIter )
+ {
+ xColumn.set(xColumns->getByName(*pIter),UNO_QUERY_THROW);
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn;
+
+ bool bFoundElem = false;
+ for (auto const& elem : m_vConnLineData)
+ {
+ if( elem->GetSourceFieldName() == sName
+ && elem->GetDestFieldName() == sRelatedColumn )
+ {
+ bFoundElem = true;
+ break;
+ }
+ }
+ if (!bFoundElem)
+ break;
+ }
+ if ( pIter == pEnd )
+ {
+ xKey->getPropertyValue(PROPERTY_NAME) >>= sName;
+ m_aConnName = sName;
+ bDropRelation = !aNames.hasElements(); // the key contains no column, so it isn't valid and we have to drop it
+ //here we already know our column structure so we don't have to recreate the table connection data
+ xColSup.clear();
+ break;
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ }
+ xKey.clear();
+ }
+ if ( bDropRelation )
+ {
+ DropRelation();
+ OUString sError(DBA_RES(STR_QUERY_REL_COULD_NOT_CREATE));
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+
+ // The fields the relation marks may not be the same as our LineDatas mark after the relation has been updated
+ if ( xColSup.is() )
+ {
+ OConnectionLineDataVec().swap(m_vConnLineData);
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ Sequence< OUString> aNames = xColumns->getElementNames();
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+
+ m_vConnLineData.reserve( aNames.getLength() );
+ Reference<XPropertySet> xColumn;
+ OUString sName,sRelatedColumn;
+
+ for(;pIter != pEnd;++pIter)
+ {
+ xColumns->getByName(*pIter) >>= xColumn;
+ if ( xColumn.is() )
+ {
+ OConnectionLineDataRef pNewData = new OConnectionLineData();
+
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn;
+
+ pNewData->SetSourceFieldName(sName);
+ pNewData->SetDestFieldName(sRelatedColumn);
+ m_vConnLineData.push_back(pNewData);
+ }
+ }
+ }
+ // NOTE : the caller is responsible for updating any other objects referencing the old LineDatas (for instance a ConnLine)
+
+ // determine cardinality
+ SetCardinality();
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/relationdesign/RTableWindow.hxx b/dbaccess/source/ui/relationdesign/RTableWindow.hxx
new file mode 100644
index 000000000..25b8d05a1
--- /dev/null
+++ b/dbaccess/source/ui/relationdesign/RTableWindow.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableWindow.hxx>
+
+namespace dbaui
+{
+ class ORelationTableWindow : public OTableWindow
+ {
+ public:
+ ORelationTableWindow( vcl::Window* pParent,const TTableWindowData::value_type& pTabWinData)
+ : OTableWindow(pParent, pTabWinData) {}
+
+ /** returns the name which should be used when displaying join or relations
+ @return
+ The composed name or the window name.
+ */
+ virtual OUString GetName() const override { return GetComposedName(); }
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/relationdesign/RelationController.cxx b/dbaccess/source/ui/relationdesign/RelationController.cxx
new file mode 100644
index 000000000..e35eebe96
--- /dev/null
+++ b/dbaccess/source/ui/relationdesign/RelationController.cxx
@@ -0,0 +1,548 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <browserids.hxx>
+#include <comphelper/types.hxx>
+#include <core_resource.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <sqlmessage.hxx>
+#include <RelationController.hxx>
+#include <TableWindowData.hxx>
+#include <UITools.hxx>
+#include <RTableConnectionData.hxx>
+#include <RelationTableView.hxx>
+#include <RelationDesignView.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/thread.hxx>
+#include <osl/mutex.hxx>
+
+#define MAX_THREADS 10
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_ORelationDesign_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::ORelationController(context));
+}
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::util;
+using namespace ::dbtools;
+using namespace ::dbaui;
+using namespace ::comphelper;
+using namespace ::osl;
+
+OUString SAL_CALL ORelationController::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.ORelationDesign";
+}
+
+Sequence< OUString> SAL_CALL ORelationController::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.RelationDesign" };
+}
+
+ORelationController::ORelationController(const Reference< XComponentContext >& _rM)
+ : OJoinController(_rM)
+ ,m_nThreadEvent(0)
+ ,m_bRelationsPossible(true)
+{
+ InvalidateAll();
+}
+
+ORelationController::~ORelationController()
+{
+}
+
+FeatureState ORelationController::GetState(sal_uInt16 _nId) const
+{
+ FeatureState aReturn;
+ aReturn.bEnabled = m_bRelationsPossible;
+ switch (_nId)
+ {
+ case SID_RELATION_ADD_RELATION:
+ aReturn.bEnabled = !m_vTableData.empty() && isConnected() && isEditable();
+ aReturn.bChecked = false;
+ break;
+ case ID_BROWSER_SAVEDOC:
+ aReturn.bEnabled = haveDataSource() && impl_isModified();
+ break;
+ default:
+ aReturn = OJoinController::GetState(_nId);
+ break;
+ }
+ return aReturn;
+}
+
+void ORelationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
+{
+ switch(_nId)
+ {
+ case ID_BROWSER_SAVEDOC:
+ {
+ OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
+ if(!::dbaui::checkDataSourceAvailable(::comphelper::getString(getDataSource()->getPropertyValue(PROPERTY_NAME)), getORB()))
+ {
+ OUString aMessage(DBA_RES(STR_DATASOURCE_DELETED));
+ OSQLWarningBox aWarning(getFrameWeld(), aMessage);
+ aWarning.run();
+ }
+ else
+ {
+ // now we save the layout information
+ // create the output stream
+ try
+ {
+ if ( haveDataSource() && getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) )
+ {
+ ::comphelper::NamedValueCollection aWindowsData;
+ saveTableWindows( aWindowsData );
+ getDataSource()->setPropertyValue( PROPERTY_LAYOUTINFORMATION, Any( aWindowsData.getPropertyValues() ) );
+ setModified(false);
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ break;
+ case SID_RELATION_ADD_RELATION:
+ static_cast<ORelationTableView*>(static_cast<ORelationDesignView*>( getView() )->getTableView())->AddNewRelation();
+ break;
+ default:
+ OJoinController::Execute(_nId,aArgs);
+ return;
+ }
+ InvalidateFeature(_nId);
+}
+
+void ORelationController::impl_initialize()
+{
+ OJoinController::impl_initialize();
+
+ if( !getSdbMetaData().supportsRelations() )
+ {// check if this database supports relations
+
+ setEditable(false);
+ m_bRelationsPossible = false;
+ {
+ OUString sTitle(DBA_RES(STR_RELATIONDESIGN));
+ sTitle = sTitle.copy(3);
+ OSQLMessageBox aDlg(getFrameWeld(), sTitle, DBA_RES(STR_RELATIONDESIGN_NOT_AVAILABLE));
+ aDlg.run();
+ }
+ disconnect();
+ throw SQLException();
+ }
+
+ if(!m_bRelationsPossible)
+ InvalidateAll();
+
+ // we need a datasource
+ OSL_ENSURE(haveDataSource(),"ORelationController::initialize: need a datasource!");
+
+ Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
+ OSL_ENSURE(xSup.is(),"Connection isn't a XTablesSupplier!");
+ if(xSup.is())
+ m_xTables = xSup->getTables();
+ // load the layoutInformation
+ loadLayoutInformation();
+ try
+ {
+ loadData();
+ if ( !m_nThreadEvent )
+ Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished));
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+}
+
+OUString ORelationController::getPrivateTitle( ) const
+{
+ OUString sName = getDataSourceName();
+ return ::dbaui::getStrippedDatabaseName(getDataSource(),sName);
+}
+
+bool ORelationController::Construct(vcl::Window* pParent)
+{
+ setView( VclPtr<ORelationDesignView>::Create( pParent, *this, getORB() ) );
+ OJoinController::Construct(pParent);
+ return true;
+}
+
+short ORelationController::saveModified()
+{
+ short nSaved = RET_YES;
+ if(haveDataSource() && isModified())
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/designsavemodifieddialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DesignSaveModifiedDialog"));
+ nSaved = xQuery->run();
+ if(nSaved == RET_YES)
+ Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
+ }
+ return nSaved;
+}
+
+void ORelationController::describeSupportedFeatures()
+{
+ OJoinController::describeSupportedFeatures();
+ implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT );
+}
+
+namespace
+{
+ class RelationLoader : public ::osl::Thread
+ {
+ typedef std::map<OUString, std::shared_ptr<OTableWindowData>, ::comphelper::UStringMixLess> TTableDataHelper;
+ TTableDataHelper m_aTableData;
+ TTableConnectionData m_vTableConnectionData;
+ const Sequence< OUString> m_aTableList;
+ ORelationController* m_pParent;
+ const Reference< XDatabaseMetaData> m_xMetaData;
+ const Reference< XNameAccess > m_xTables;
+ const sal_Int32 m_nStartIndex;
+ const sal_Int32 m_nEndIndex;
+
+ public:
+ RelationLoader(ORelationController* _pParent
+ ,const Reference< XDatabaseMetaData>& _xMetaData
+ ,const Reference< XNameAccess >& _xTables
+ ,const Sequence< OUString>& _aTableList
+ ,const sal_Int32 _nStartIndex
+ ,const sal_Int32 _nEndIndex)
+ :m_aTableData(_xMetaData.is() && _xMetaData->supportsMixedCaseQuotedIdentifiers())
+ ,m_aTableList(_aTableList)
+ ,m_pParent(_pParent)
+ ,m_xMetaData(_xMetaData)
+ ,m_xTables(_xTables)
+ ,m_nStartIndex(_nStartIndex)
+ ,m_nEndIndex(_nEndIndex)
+ {
+ }
+
+ /// Working method which should be overridden.
+ virtual void SAL_CALL run() override;
+ virtual void SAL_CALL onTerminated() override;
+ protected:
+ virtual ~RelationLoader() override {}
+
+ void loadTableData(const Any& _aTable);
+ };
+
+ void SAL_CALL RelationLoader::run()
+ {
+ osl_setThreadName("RelationLoader");
+
+ for(sal_Int32 i = m_nStartIndex; i < m_nEndIndex; ++i)
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,
+ m_aTableList[i],
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ Any aCatalog;
+ if ( !sCatalog.isEmpty() )
+ aCatalog <<= sCatalog;
+
+ try
+ {
+ Reference< XResultSet > xResult = m_xMetaData->getImportedKeys(aCatalog, sSchema,sTable);
+ if ( xResult.is() && xResult->next() )
+ {
+ ::comphelper::disposeComponent(xResult);
+ loadTableData(m_xTables->getByName(m_aTableList[i]));
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+ void SAL_CALL RelationLoader::onTerminated()
+ {
+ m_pParent->mergeData(m_vTableConnectionData);
+ delete this;
+ }
+
+ void RelationLoader::loadTableData(const Any& _aTable)
+ {
+ Reference<XPropertySet> xTableProp(_aTable,UNO_QUERY);
+ const OUString sSourceName = ::dbtools::composeTableName( m_xMetaData, xTableProp, ::dbtools::EComposeRule::InTableDefinitions, false );
+ TTableDataHelper::const_iterator aFind = m_aTableData.find(sSourceName);
+ if ( aFind == m_aTableData.end() )
+ {
+ aFind = m_aTableData.emplace(sSourceName,std::make_shared<OTableWindowData>(xTableProp,sSourceName, sSourceName, OUString())).first;
+ aFind->second->ShowAll(false);
+ }
+ TTableWindowData::value_type pReferencingTable = aFind->second;
+ Reference<XIndexAccess> xKeys = pReferencingTable->getKeys();
+ const Reference<XKeysSupplier> xKeySup(xTableProp,UNO_QUERY);
+
+ if ( !xKeys.is() && xKeySup.is() )
+ {
+ xKeys = xKeySup->getKeys();
+ }
+
+ if ( !xKeys.is() )
+ return;
+
+ Reference<XPropertySet> xKey;
+ const sal_Int32 nCount = xKeys->getCount();
+ for(sal_Int32 i = 0 ; i < nCount ; ++i)
+ {
+ xKeys->getByIndex(i) >>= xKey;
+ sal_Int32 nKeyType = 0;
+ xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
+ if ( KeyType::FOREIGN == nKeyType )
+ {
+ OUString sReferencedTable;
+ xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
+
+ // insert windows
+ TTableDataHelper::const_iterator aRefFind = m_aTableData.find(sReferencedTable);
+ if ( aRefFind == m_aTableData.end() )
+ {
+ if ( m_xTables->hasByName(sReferencedTable) )
+ {
+ Reference<XPropertySet> xReferencedTable(m_xTables->getByName(sReferencedTable),UNO_QUERY);
+ aRefFind = m_aTableData.emplace(sReferencedTable,std::make_shared<OTableWindowData>(xReferencedTable,sReferencedTable, sReferencedTable, OUString())).first;
+ aRefFind->second->ShowAll(false);
+ }
+ else
+ continue; // table name could not be found so we do not show this table relation
+ }
+ TTableWindowData::value_type pReferencedTable = aRefFind->second;
+
+ OUString sKeyName;
+ xKey->getPropertyValue(PROPERTY_NAME) >>= sKeyName;
+ // insert connection
+ auto xTabConnData = std::make_shared<ORelationTableConnectionData>( pReferencingTable, pReferencedTable, sKeyName );
+ m_vTableConnectionData.push_back(xTabConnData);
+ // insert columns
+ const Reference<XColumnsSupplier> xColsSup(xKey,UNO_QUERY);
+ OSL_ENSURE(xColsSup.is(),"Key is no XColumnsSupplier!");
+ const Reference<XNameAccess> xColumns = xColsSup->getColumns();
+ const Sequence< OUString> aNames = xColumns->getElementNames();
+ OUString sColumnName,sRelatedName;
+ for(sal_Int32 j=0;j<aNames.getLength();++j)
+ {
+ const Reference<XPropertySet> xPropSet(xColumns->getByName(aNames[j]),UNO_QUERY);
+ OSL_ENSURE(xPropSet.is(),"Invalid column found in KeyColumns!");
+ if ( xPropSet.is() )
+ {
+ xPropSet->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
+ xPropSet->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedName;
+ }
+ xTabConnData->SetConnLine( j, sColumnName, sRelatedName );
+ }
+ // set update/del flags
+ sal_Int32 nUpdateRule = 0;
+ sal_Int32 nDeleteRule = 0;
+ xKey->getPropertyValue(PROPERTY_UPDATERULE) >>= nUpdateRule;
+ xKey->getPropertyValue(PROPERTY_DELETERULE) >>= nDeleteRule;
+
+ xTabConnData->SetUpdateRules( nUpdateRule );
+ xTabConnData->SetDeleteRules( nDeleteRule );
+
+ // set cardinality
+ xTabConnData->SetCardinality();
+ }
+ }
+ }
+}
+
+void ORelationController::mergeData(const TTableConnectionData& _aConnectionData)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ m_vTableConnectionData.insert( m_vTableConnectionData.end(), _aConnectionData.begin(), _aConnectionData.end() );
+ // here we are finished, so we can collect the table from connection data
+ for (auto const& elem : m_vTableConnectionData)
+ {
+ if ( !existsTable(elem->getReferencingTable()->GetComposedName()) )
+ {
+ m_vTableData.push_back(elem->getReferencingTable());
+ }
+ if ( !existsTable(elem->getReferencedTable()->GetComposedName()) )
+ {
+ m_vTableData.push_back(elem->getReferencedTable());
+ }
+ }
+ if ( m_nThreadEvent )
+ {
+ --m_nThreadEvent;
+ if ( !m_nThreadEvent )
+ Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished));
+ }
+}
+
+IMPL_LINK_NOARG( ORelationController, OnThreadFinished, void*, void )
+{
+ ::SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ try
+ {
+ getView()->initialize(); // show the windows and fill with our information
+ getView()->Invalidate(InvalidateFlags::NoErase);
+ ClearUndoManager();
+ setModified(false); // and we are not modified yet
+
+ if(m_vTableData.empty())
+ Execute(ID_BROWSER_ADDTABLE,Sequence<PropertyValue>());
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xWaitObject.reset();
+}
+
+void ORelationController::loadData()
+{
+ m_xWaitObject.reset(new weld::WaitObject(getFrameWeld()));
+ try
+ {
+ if ( !m_xTables.is() )
+ return;
+ DatabaseMetaData aMeta(getConnection());
+ // this may take some time
+ const Reference< XDatabaseMetaData> xMetaData = getConnection()->getMetaData();
+ const Sequence< OUString> aNames = m_xTables->getElementNames();
+ const sal_Int32 nCount = aNames.getLength();
+ if ( aMeta.supportsThreads() )
+ {
+ const sal_Int32 nMaxElements = (nCount / MAX_THREADS) +1;
+ sal_Int32 nStart = 0,nEnd = std::min(nMaxElements,nCount);
+ while(nStart != nEnd)
+ {
+ ++m_nThreadEvent;
+ RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,nStart,nEnd);
+ pThread->createSuspended();
+ pThread->setPriority(osl_Thread_PriorityBelowNormal);
+ pThread->resume();
+ nStart = nEnd;
+ nEnd += nMaxElements;
+ nEnd = std::min(nEnd,nCount);
+ }
+ }
+ else
+ {
+ RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,0,nCount);
+ pThread->run();
+ pThread->onTerminated();
+ }
+ }
+ catch(SQLException& e)
+ {
+ showError(SQLExceptionInfo(e));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+TTableWindowData::value_type ORelationController::existsTable(std::u16string_view _rComposedTableName) const
+{
+ ::comphelper::UStringMixEqual bCase(true);
+ for (auto const& elem : m_vTableData)
+ {
+ if(bCase(elem->GetComposedName(),_rComposedTableName))
+ return elem;
+ }
+ return TTableWindowData::value_type();
+}
+
+void ORelationController::loadLayoutInformation()
+{
+ try
+ {
+ OSL_ENSURE(haveDataSource(),"We need a datasource from our connection!");
+ if ( haveDataSource() )
+ {
+ if ( getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) )
+ {
+ Sequence<PropertyValue> aWindows;
+ getDataSource()->getPropertyValue(PROPERTY_LAYOUTINFORMATION) >>= aWindows;
+ loadTableWindows(aWindows);
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ }
+}
+
+void ORelationController::reset()
+{
+ loadLayoutInformation();
+ ODataView* pView = getView();
+ OSL_ENSURE(pView,"No current view!");
+ if(pView)
+ {
+ pView->initialize();
+ pView->Invalidate(InvalidateFlags::NoErase);
+ }
+}
+
+bool ORelationController::allowViews() const
+{
+ return false;
+}
+
+bool ORelationController::allowQueries() const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/relationdesign/RelationDesignView.cxx b/dbaccess/source/ui/relationdesign/RelationDesignView.cxx
new file mode 100644
index 000000000..014579cf7
--- /dev/null
+++ b/dbaccess/source/ui/relationdesign/RelationDesignView.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <RelationDesignView.hxx>
+#include <RelationTableView.hxx>
+#include <RelationController.hxx>
+#include <vcl/event.hxx>
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+ORelationDesignView::ORelationDesignView(vcl::Window* _pParent, ORelationController& _rController,const Reference< XComponentContext >& _rxContext)
+ :OJoinDesignView( _pParent, _rController, _rxContext )
+{
+}
+
+void ORelationDesignView::Construct()
+{
+ m_pTableView = VclPtr<ORelationTableView>::Create(m_pScrollWindow,this);
+ OJoinDesignView::Construct();
+}
+
+void ORelationDesignView::initialize()
+{
+ m_pTableView->clearLayoutInformation();
+ m_pTableView->ReSync();
+
+ OJoinDesignView::initialize();
+}
+
+bool ORelationDesignView::PreNotify( NotifyEvent& rNEvt )
+{
+ bool bDone = false;
+ if(rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
+ {
+ if(m_pTableView && !m_pTableView->HasChildPathFocus())
+ {
+ m_pTableView->GrabTabWinFocus();
+ bDone = true;
+ }
+ }
+ if(!bDone)
+ bDone = OJoinDesignView::PreNotify(rNEvt);
+ return bDone;
+}
+
+void ORelationDesignView::GetFocus()
+{
+ OJoinDesignView::GetFocus();
+ if ( m_pTableView && m_pTableView->IsVisible() && !m_pTableView->GetTabWinMap().empty() )
+ m_pTableView->GrabTabWinFocus();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/relationdesign/RelationTableView.cxx b/dbaccess/source/ui/relationdesign/RelationTableView.cxx
new file mode 100644
index 000000000..ea7b83146
--- /dev/null
+++ b/dbaccess/source/ui/relationdesign/RelationTableView.cxx
@@ -0,0 +1,410 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <RelationTableView.hxx>
+#include <core_resource.hxx>
+#include <browserids.hxx>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <connectivity/dbtools.hxx>
+#include <tools/diagnose_ex.h>
+#include <helpids.h>
+#include <RelationDesignView.hxx>
+#include <JoinController.hxx>
+#include <TableWindow.hxx>
+#include <TableWindowData.hxx>
+#include "RTableConnection.hxx"
+#include <RTableConnectionData.hxx>
+#include <RelationDlg.hxx>
+#include <sqlmessage.hxx>
+#include <strings.hrc>
+#include <connectivity/dbexception.hxx>
+#include "RTableWindow.hxx"
+#include <JAccess.hxx>
+#include <vcl/stdtext.hxx>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+
+using namespace dbaui;
+using namespace ::dbtools;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::accessibility;
+
+ORelationTableView::ORelationTableView( vcl::Window* pParent, ORelationDesignView* pView )
+ :OJoinTableView( pParent, pView )
+ , ::comphelper::OContainerListener(m_aMutex)
+ ,m_pExistingConnection(nullptr)
+ ,m_bInRemove(false)
+
+{
+ SetHelpId(HID_CTL_RELATIONTAB);
+}
+
+ORelationTableView::~ORelationTableView()
+{
+ disposeOnce();
+}
+
+void ORelationTableView::dispose()
+{
+ if ( m_pContainerListener.is() )
+ m_pContainerListener->dispose();
+ m_pExistingConnection.clear();
+ OJoinTableView::dispose();
+}
+
+void ORelationTableView::ReSync()
+{
+ if ( !m_pContainerListener.is() )
+ {
+ Reference< XConnection> xConnection = m_pView->getController().getConnection();
+ Reference< XTablesSupplier > xTableSupp( xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xTables = xTableSupp->getTables();
+ Reference< XContainer> xContainer(xTables,uno::UNO_QUERY);
+ if ( xContainer.is() )
+ m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
+ }
+ // Tables could have been hidden in the database, which are part of a relation. Or a table was in layout
+ // (quite often without a relation) and does not exist anymore. In both cases creation of TabWins will fail
+ // and all TabWinDatas and related ConnDates should be deleted.
+ std::vector< OUString> arrInvalidTables;
+
+ // create and insert windows
+ TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData();
+ TTableWindowData::const_reverse_iterator aIter = rTabWinDataList.rbegin();
+ for(;aIter != rTabWinDataList.rend();++aIter)
+ {
+ TTableWindowData::value_type pData = *aIter;
+ VclPtr<OTableWindow> pTabWin = createWindow(pData);
+
+ if (!pTabWin->Init())
+ {
+ // initialisation failed, which means this TabWin is not available, therefore,
+ // it should be cleaned up, including its data in the document
+ pTabWin->clearListBox();
+ pTabWin.disposeAndClear();
+ arrInvalidTables.push_back(pData->GetTableName());
+
+ rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), *aIter), rTabWinDataList.end());
+ continue;
+ }
+
+ GetTabWinMap()[pData->GetComposedName()] = pTabWin; // insert at the beginning, as the Datalist is walked through backward
+ // if there's no position or size contained in the data -> Default
+ if (!pData->HasPosition() && !pData->HasSize())
+ SetDefaultTabWinPosSize(pTabWin);
+
+ pTabWin->Show();
+ }
+
+ // insert connection
+ TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData();
+ TTableConnectionData::const_reverse_iterator aConIter = rTabConnDataList.rbegin();
+
+ for(;aConIter != rTabConnDataList.rend();++aConIter)
+ {
+ ORelationTableConnectionData* pTabConnData = static_cast<ORelationTableConnectionData*>(aConIter->get());
+ if ( !arrInvalidTables.empty() )
+ {
+ // do the tables to the connection exist?
+ OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetTableName();
+ bool bInvalid = std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
+ strTabExistenceTest = pTabConnData->getReferencedTable()->GetTableName();
+ bInvalid = bInvalid || std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
+
+ if (bInvalid)
+ {
+ // no -> bad luck, the connection is gone
+ rTabConnDataList.erase( std::remove(rTabConnDataList.begin(), rTabConnDataList.end(), *aConIter), rTabConnDataList.end() );
+ continue;
+ }
+ }
+
+ addConnection( VclPtr<ORelationTableConnection>::Create(this, *aConIter), false );
+ }
+
+ if ( !GetTabWinMap().empty() )
+ GetTabWinMap().begin()->second->GrabFocus();
+}
+
+bool ORelationTableView::IsAddAllowed()
+{
+
+ return !m_pView->getController().isReadOnly();
+}
+
+void ORelationTableView::AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest)
+{
+ // Set LineDataObject based on selected fieldname
+ // check if relation already exists
+ OTableWindow* pSourceWin = jxdSource.pListBox->GetTabWin();
+ OTableWindow* pDestWin = jxdDest.pListBox->GetTabWin();
+
+ for(VclPtr<OTableConnection> const & pFirst : getTableConnections())
+ {
+ if((pFirst->GetSourceWin() == pSourceWin && pFirst->GetDestWin() == pDestWin) ||
+ (pFirst->GetSourceWin() == pDestWin && pFirst->GetDestWin() == pSourceWin))
+ {
+ m_pExistingConnection = pFirst;
+ break;
+ }
+ }
+ // insert table connection into view
+ TTableConnectionData::value_type pTabConnData = std::make_shared<ORelationTableConnectionData>(pSourceWin->GetData(),
+ pDestWin->GetData());
+
+ // the names of the affected fields
+ weld::TreeView& rSourceTreeView = jxdSource.pListBox->get_widget();
+ OUString sSourceFieldName = rSourceTreeView.get_text(jxdSource.nEntry);
+ weld::TreeView& rDestTreeView = jxdDest.pListBox->get_widget();
+ OUString sDestFieldName = rDestTreeView.get_text(jxdDest.nEntry);
+
+ // the number of PKey-Fields in the source
+ const Reference< XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(pSourceWin->GetData()->getTable());
+ bool bAskUser = xPrimaryKeyColumns.is() && Reference< XIndexAccess>(xPrimaryKeyColumns,UNO_QUERY_THROW)->getCount() > 1;
+
+ pTabConnData->SetConnLine( 0, sSourceFieldName, sDestFieldName );
+
+ if ( bAskUser || m_pExistingConnection )
+ m_pCurrentlyTabConnData = pTabConnData; // this implies that we ask the user what to do
+ else
+ {
+ try
+ {
+ // hand over data to the database
+ if( pTabConnData->Update() )
+ {
+ // enter UI-object into ConnList
+ addConnection( VclPtr<ORelationTableConnection>::Create( this, pTabConnData ) );
+ }
+ }
+ catch(const SQLException&)
+ {
+ throw;
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "ORelationTableView::AddConnection");
+ }
+ }
+}
+
+void ORelationTableView::ConnDoubleClicked(VclPtr<OTableConnection>& rConnection)
+{
+ ORelationDialog aRelDlg(this, rConnection->GetData());
+ switch (aRelDlg.run())
+ {
+ case RET_OK:
+ // successfully updated
+ rConnection->UpdateLineList();
+ // The connection references 1 ConnData and n ConnLines, each ConnData references n LineDatas, each Line exactly 1 LineData
+ // As the Dialog and the ConnData->Update may have changed the LineDatas we have to restore the consistent state
+ break;
+
+ case RET_NO:
+ // tried at least one update, but did not succeed -> the original connection is lost
+ RemoveConnection(rConnection ,true);
+ break;
+
+ case RET_CANCEL:
+ // no break, as nothing happened and we don't need the code below
+ return;
+
+ }
+
+ Invalidate(InvalidateFlags::NoChildren);
+}
+
+void ORelationTableView::AddNewRelation()
+{
+
+ TTableConnectionData::value_type pNewConnData = std::make_shared<ORelationTableConnectionData>();
+ ORelationDialog aRelDlg(this, pNewConnData, true);
+
+ bool bSuccess = (aRelDlg.run() == RET_OK);
+ if (bSuccess)
+ {
+ // already updated by the dialog
+ // announce it to the document
+ addConnection( VclPtr<ORelationTableConnection>::Create(this, pNewConnData) );
+ }
+}
+
+bool ORelationTableView::RemoveConnection(VclPtr<OTableConnection>& rConn, bool /*_bDelete*/)
+{
+ ORelationTableConnectionData* pTabConnData = static_cast<ORelationTableConnectionData*>(rConn->GetData().get());
+ try
+ {
+ if (!m_bInRemove)
+ pTabConnData->DropRelation();
+ return OJoinTableView::RemoveConnection(rConn, true);
+ }
+ catch(SQLException& e)
+ {
+ getDesignView()->getController().showError(SQLExceptionInfo(e));
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "ORelationTableView::RemoveConnection: Something other than SQLException occurred!");
+ }
+ return false;
+}
+
+void ORelationTableView::AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool /*bNewTable*/)
+{
+ OSL_ENSURE(!_rComposedName.isEmpty(),"There must be a table name supplied!");
+ OJoinTableView::OTableWindowMap::const_iterator aIter = GetTabWinMap().find(_rComposedName);
+
+ if(aIter != GetTabWinMap().end())
+ {
+ aIter->second->SetZOrder(nullptr, ZOrderFlags::First);
+ aIter->second->GrabFocus();
+ EnsureVisible(aIter->second);
+ // no new one
+ return;
+ }
+
+ // enter the new data structure into DocShell
+ TTableWindowData::value_type pNewTabWinData(createTableWindowData( _rComposedName, rWinName,rWinName ));
+ pNewTabWinData->ShowAll(false);
+
+ // link new window into the window list
+ VclPtr<OTableWindow> pNewTabWin = createWindow( pNewTabWinData );
+ if(pNewTabWin->Init())
+ {
+ m_pView->getController().getTableWindowData().push_back( pNewTabWinData);
+ // when we already have a table with this name insert the full qualified one instead
+ GetTabWinMap()[_rComposedName] = pNewTabWin;
+
+ SetDefaultTabWinPosSize( pNewTabWin );
+ pNewTabWin->Show();
+
+ modified();
+
+ if ( m_pAccessible )
+ m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
+ Any(),
+ Any(pNewTabWin->GetAccessible()));
+ }
+ else
+ {
+ pNewTabWin->clearListBox();
+ pNewTabWin.disposeAndClear();
+ }
+}
+
+void ORelationTableView::RemoveTabWin( OTableWindow* pTabWin )
+{
+ OSQLWarningBox aDlg(GetFrameWeld(), DBA_RES(STR_QUERY_REL_DELETE_WINDOW), MessBoxStyle::YesNo | MessBoxStyle::DefaultYes);
+ if (m_bInRemove || aDlg.run() == RET_YES)
+ {
+ m_pView->getController().ClearUndoManager();
+ OJoinTableView::RemoveTabWin( pTabWin );
+
+ m_pView->getController().InvalidateFeature(SID_RELATION_ADD_RELATION);
+ m_pView->getController().InvalidateFeature(ID_BROWSER_UNDO);
+ m_pView->getController().InvalidateFeature(ID_BROWSER_REDO);
+ }
+}
+
+void ORelationTableView::lookForUiActivities()
+{
+ if(m_pExistingConnection)
+ {
+ OUString sTitle(DBA_RES(STR_RELATIONDESIGN));
+ sTitle = sTitle.copy(3);
+ OSQLMessageBox aDlg(GetFrameWeld(), DBA_RES(STR_QUERY_REL_EDIT_RELATION), OUString(), MessBoxStyle::NONE);
+ aDlg.set_title(sTitle);
+ aDlg.add_button(DBA_RES(STR_QUERY_REL_EDIT), RET_OK);
+ aDlg.set_default_response(RET_OK);
+ aDlg.add_button(DBA_RES(STR_QUERY_REL_CREATE), RET_YES);
+ aDlg.add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ sal_uInt16 nRet = aDlg.run();
+ if (nRet == RET_CANCEL)
+ {
+ m_pCurrentlyTabConnData.reset();
+ }
+ else if ( nRet == RET_OK ) // EDIT
+ {
+ ConnDoubleClicked(m_pExistingConnection);
+ m_pCurrentlyTabConnData.reset();
+ }
+ m_pExistingConnection = nullptr;
+ }
+ if(m_pCurrentlyTabConnData)
+ {
+ ORelationDialog aRelDlg(this, m_pCurrentlyTabConnData);
+ if (aRelDlg.run() == RET_OK)
+ {
+ // already updated by the dialog
+ addConnection( VclPtr<ORelationTableConnection>::Create( this, m_pCurrentlyTabConnData ) );
+ }
+ m_pCurrentlyTabConnData.reset();
+ }
+}
+
+VclPtr<OTableWindow> ORelationTableView::createWindow(const TTableWindowData::value_type& _pData)
+{
+ return VclPtr<ORelationTableWindow>::Create(this,_pData);
+}
+
+bool ORelationTableView::allowQueries() const
+{
+ return false;
+}
+
+void ORelationTableView::_elementInserted( const container::ContainerEvent& /*_rEvent*/ )
+{
+
+}
+
+void ORelationTableView::_elementRemoved( const container::ContainerEvent& _rEvent )
+{
+ m_bInRemove = true;
+ OUString sName;
+ if ( _rEvent.Accessor >>= sName )
+ {
+ OTableWindow* pTableWindow = GetTabWindow(sName);
+ if ( pTableWindow )
+ {
+ m_pView->getController().ClearUndoManager();
+ OJoinTableView::RemoveTabWin( pTableWindow );
+
+ m_pView->getController().InvalidateFeature(SID_RELATION_ADD_RELATION);
+ m_pView->getController().InvalidateFeature(ID_BROWSER_UNDO);
+ m_pView->getController().InvalidateFeature(ID_BROWSER_REDO);
+ }
+ }
+ m_bInRemove = false;
+}
+
+void ORelationTableView::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx
new file mode 100644
index 000000000..d8dce84a0
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx
@@ -0,0 +1,639 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <FieldDescriptions.hxx>
+#include <tools/diagnose_ex.h>
+#include <strings.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <comphelper/types.hxx>
+#include <comphelper/extract.hxx>
+#include <UITools.hxx>
+#include <com/sun/star/util/NumberFormat.hpp>
+
+#define DEFAULT_VARCHAR_PRECISION 100
+#define DEFAULT_OTHER_PRECISION 16
+#define DEFAULT_NUMERIC_PRECISION 5
+#define DEFAULT_NUMERIC_SCALE 0
+
+using namespace dbaui;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+
+OFieldDescription::OFieldDescription()
+ :m_nType(DataType::VARCHAR)
+ ,m_nPrecision(0)
+ ,m_nScale(0)
+ ,m_nIsNullable(ColumnValue::NULLABLE)
+ ,m_nFormatKey(0)
+ ,m_eHorJustify(SvxCellHorJustify::Standard)
+ ,m_bIsAutoIncrement(false)
+ ,m_bIsPrimaryKey(false)
+ ,m_bIsCurrency(false)
+ ,m_bHidden(false)
+{
+}
+
+OFieldDescription::OFieldDescription( const OFieldDescription& rDescr )
+ :m_aControlDefault(rDescr.m_aControlDefault)
+ ,m_aWidth(rDescr.m_aWidth)
+ ,m_aRelativePosition(rDescr.m_aRelativePosition)
+ ,m_pType(rDescr.m_pType)
+ ,m_xDest(rDescr.m_xDest)
+ ,m_xDestInfo(rDescr.m_xDestInfo)
+ ,m_sName(rDescr.m_sName)
+ ,m_sTypeName(rDescr.m_sTypeName)
+ ,m_sDescription(rDescr.m_sDescription)
+ ,m_sAutoIncrementValue(rDescr.m_sAutoIncrementValue)
+ ,m_nType(rDescr.m_nType)
+ ,m_nPrecision(rDescr.m_nPrecision)
+ ,m_nScale(rDescr.m_nScale)
+ ,m_nIsNullable(rDescr.m_nIsNullable)
+ ,m_nFormatKey(rDescr.m_nFormatKey)
+ ,m_eHorJustify(rDescr.m_eHorJustify)
+ ,m_bIsAutoIncrement(rDescr.m_bIsAutoIncrement)
+ ,m_bIsPrimaryKey(rDescr.m_bIsPrimaryKey)
+ ,m_bIsCurrency(rDescr.m_bIsCurrency)
+ ,m_bHidden(rDescr.m_bHidden)
+{
+}
+
+OFieldDescription::~OFieldDescription()
+{
+}
+
+OFieldDescription::OFieldDescription(const Reference< XPropertySet >& xAffectedCol,bool _bUseAsDest)
+ :m_nType(DataType::VARCHAR)
+ ,m_nPrecision(0)
+ ,m_nScale(0)
+ ,m_nIsNullable(ColumnValue::NULLABLE)
+ ,m_nFormatKey(0)
+ ,m_eHorJustify(SvxCellHorJustify::Standard)
+ ,m_bIsAutoIncrement(false)
+ ,m_bIsPrimaryKey(false)
+ ,m_bIsCurrency(false)
+ ,m_bHidden(false)
+{
+ OSL_ENSURE(xAffectedCol.is(),"PropertySet can not be null!");
+ if ( !xAffectedCol.is() )
+ return;
+
+ if ( _bUseAsDest )
+ {
+ m_xDest = xAffectedCol;
+ m_xDestInfo = xAffectedCol->getPropertySetInfo();
+ }
+ else
+ {
+ try
+ {
+ Reference<XPropertySetInfo> xPropSetInfo = xAffectedCol->getPropertySetInfo();
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_NAME))
+ SetName(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_NAME)));
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_DESCRIPTION))
+ SetDescription(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_DESCRIPTION)));
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_HELPTEXT))
+ {
+ OUString sHelpText;
+ xAffectedCol->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
+ SetHelpText(sHelpText);
+ }
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE))
+ SetDefaultValue( xAffectedCol->getPropertyValue(PROPERTY_DEFAULTVALUE) );
+
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
+ SetControlDefault( xAffectedCol->getPropertyValue(PROPERTY_CONTROLDEFAULT) );
+
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION))
+ SetAutoIncrementValue(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_AUTOINCREMENTCREATION)));
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_TYPE))
+ SetTypeValue(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_TYPE)));
+ if (xPropSetInfo->hasPropertyByName(PROPERTY_TYPENAME))
+ SetTypeName(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_TYPENAME)));
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_PRECISION))
+ SetPrecision(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_PRECISION)));
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_SCALE))
+ SetScale(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_SCALE)));
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_ISNULLABLE))
+ SetIsNullable(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_ISNULLABLE)));
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_FORMATKEY))
+ {
+ const Any aValue = xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY);
+ if ( aValue.hasValue() )
+ SetFormatKey(::comphelper::getINT32(aValue));
+ }
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_RELATIVEPOSITION))
+ m_aRelativePosition = xAffectedCol->getPropertyValue(PROPERTY_RELATIVEPOSITION);
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_WIDTH))
+ m_aWidth = xAffectedCol->getPropertyValue(PROPERTY_WIDTH);
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_HIDDEN))
+ xAffectedCol->getPropertyValue(PROPERTY_HIDDEN) >>= m_bHidden;
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_ALIGN))
+ {
+ const Any aValue = xAffectedCol->getPropertyValue(PROPERTY_ALIGN);
+ if ( aValue.hasValue() )
+ SetHorJustify( ::dbaui::mapTextJustify(::comphelper::getINT32(aValue)));
+ }
+ if(xPropSetInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT))
+ SetAutoIncrement(::cppu::any2bool(xAffectedCol->getPropertyValue(PROPERTY_ISAUTOINCREMENT)));
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void OFieldDescription::FillFromTypeInfo(const TOTypeInfoSP& _pType,bool _bForce,bool _bReset)
+{
+ TOTypeInfoSP pOldType = getTypeInfo();
+ if ( _pType == pOldType )
+ return;
+
+ // reset type depending information
+ if ( _bReset )
+ {
+ SetFormatKey(0);
+ SetControlDefault(Any());
+ }
+
+ bool bForce = _bForce || !pOldType || pOldType->nType != _pType->nType;
+ switch ( _pType->nType )
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ if ( bForce )
+ {
+ sal_Int32 nPrec = DEFAULT_VARCHAR_PRECISION;
+ if ( GetPrecision() )
+ nPrec = GetPrecision();
+ SetPrecision(std::min<sal_Int32>(nPrec,_pType->nPrecision));
+ }
+ break;
+ case DataType::TIMESTAMP:
+ if ( bForce && _pType->nMaximumScale)
+ {
+ SetScale(std::min<sal_Int32>(GetScale() ? GetScale() : DEFAULT_NUMERIC_SCALE,_pType->nMaximumScale));
+ }
+ break;
+ default:
+ if ( bForce )
+ {
+ sal_Int32 nPrec = DEFAULT_OTHER_PRECISION;
+ switch ( _pType->nType )
+ {
+ case DataType::BIT:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ nPrec = _pType->nPrecision;
+ break;
+ default:
+ if ( GetPrecision() )
+ nPrec = GetPrecision();
+ break;
+ }
+
+ if ( _pType->nPrecision )
+ SetPrecision(std::min<sal_Int32>(nPrec ? nPrec : DEFAULT_NUMERIC_PRECISION,_pType->nPrecision));
+ if ( _pType->nMaximumScale )
+ SetScale(std::min<sal_Int32>(GetScale() ? GetScale() : DEFAULT_NUMERIC_SCALE,_pType->nMaximumScale));
+ }
+ }
+ if ( _pType->aCreateParams.isEmpty() )
+ {
+ SetPrecision(_pType->nPrecision);
+ SetScale(_pType->nMinimumScale);
+ }
+ if ( !_pType->bNullable && IsNullable() )
+ SetIsNullable(ColumnValue::NO_NULLS);
+ if ( !_pType->bAutoIncrement && IsAutoIncrement() )
+ SetAutoIncrement(false);
+ SetCurrency( _pType->bCurrency );
+ SetType(_pType);
+ SetTypeName(_pType->aTypeName);
+}
+
+void OFieldDescription::SetName(const OUString& _rName)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_NAME) )
+ m_xDest->setPropertyValue(PROPERTY_NAME,Any(_rName));
+ else
+ m_sName = _rName;
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetHelpText(const OUString& _sHelpText)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
+ m_xDest->setPropertyValue(PROPERTY_HELPTEXT,Any(_sHelpText));
+ else
+ m_sHelpText = _sHelpText;
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetDescription(const OUString& _rDescription)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DESCRIPTION) )
+ m_xDest->setPropertyValue(PROPERTY_DESCRIPTION,Any(_rDescription));
+ else
+ m_sDescription = _rDescription;
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetDefaultValue(const Any& _rDefaultValue)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE) )
+ m_xDest->setPropertyValue(PROPERTY_DEFAULTVALUE, _rDefaultValue);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetControlDefault(const Any& _rControlDefault)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) )
+ m_xDest->setPropertyValue(PROPERTY_CONTROLDEFAULT, _rControlDefault);
+ else
+ m_aControlDefault = _rControlDefault;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetAutoIncrementValue(const OUString& _sAutoIncValue)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) )
+ m_xDest->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,Any(_sAutoIncValue));
+ else
+ m_sAutoIncrementValue = _sAutoIncValue;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetType(const TOTypeInfoSP& _pType)
+{
+ m_pType = _pType;
+ if ( !m_pType )
+ return;
+
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) )
+ m_xDest->setPropertyValue(PROPERTY_TYPE,Any(m_pType->nType));
+ else
+ m_nType = m_pType->nType;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetTypeValue(sal_Int32 _nType)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) )
+ m_xDest->setPropertyValue(PROPERTY_TYPE,Any(_nType));
+ else
+ {
+ m_nType = _nType;
+ OSL_ENSURE(!m_pType,"Invalid call here!");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetPrecision(sal_Int32 _rPrecision)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_PRECISION) )
+ m_xDest->setPropertyValue(PROPERTY_PRECISION,Any(_rPrecision));
+ else
+ m_nPrecision = _rPrecision;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetScale(sal_Int32 _rScale)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_SCALE) )
+ m_xDest->setPropertyValue(PROPERTY_SCALE,Any(_rScale));
+ else
+ m_nScale = _rScale;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetIsNullable(sal_Int32 _rIsNullable)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) )
+ m_xDest->setPropertyValue(PROPERTY_ISNULLABLE,Any(_rIsNullable));
+ else
+ m_nIsNullable = _rIsNullable;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetFormatKey(sal_Int32 _rFormatKey)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_FORMATKEY) )
+ m_xDest->setPropertyValue(PROPERTY_FORMATKEY,Any(_rFormatKey));
+ else
+ m_nFormatKey = _rFormatKey;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetHorJustify(const SvxCellHorJustify& _rHorJustify)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ALIGN) )
+ m_xDest->setPropertyValue(PROPERTY_ALIGN,Any( dbaui::mapTextAlign(_rHorJustify)));
+ else
+ m_eHorJustify = _rHorJustify;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetAutoIncrement(bool _bAuto)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT) )
+ m_xDest->setPropertyValue(PROPERTY_ISAUTOINCREMENT,Any(_bAuto));
+ else
+ m_bIsAutoIncrement = _bAuto;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::SetPrimaryKey(bool _bPKey)
+{
+ m_bIsPrimaryKey = _bPKey;
+ if ( _bPKey )
+ SetIsNullable(css::sdbc::ColumnValue::NO_NULLS);
+}
+
+void OFieldDescription::SetCurrency(bool _bIsCurrency)
+{
+ m_bIsCurrency = _bIsCurrency;
+}
+
+OUString OFieldDescription::GetName() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_NAME) )
+ return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_NAME));
+ else
+ return m_sName;
+}
+
+OUString OFieldDescription::GetDescription() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DESCRIPTION) )
+ return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_DESCRIPTION));
+ else
+ return m_sDescription;
+}
+
+OUString OFieldDescription::GetHelpText() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
+ return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_HELPTEXT));
+ else
+ return m_sHelpText;
+}
+
+css::uno::Any OFieldDescription::GetControlDefault() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) )
+ return m_xDest->getPropertyValue(PROPERTY_CONTROLDEFAULT);
+ else
+ return m_aControlDefault;
+}
+
+OUString OFieldDescription::GetAutoIncrementValue() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) )
+ return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_AUTOINCREMENTCREATION));
+ else
+ return m_sAutoIncrementValue;
+}
+
+sal_Int32 OFieldDescription::GetType() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) )
+ return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_TYPE));
+ else
+ return m_pType ? m_pType->nType : m_nType;
+}
+
+OUString OFieldDescription::GetTypeName() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPENAME) )
+ return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_TYPENAME));
+ else
+ return m_pType ? m_pType->aTypeName : m_sTypeName;
+}
+
+sal_Int32 OFieldDescription::GetPrecision() const
+{
+ sal_Int32 nPrec = m_nPrecision;
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_PRECISION) )
+ nPrec = ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_PRECISION));
+
+ TOTypeInfoSP pTypeInfo = getTypeInfo();
+ if ( pTypeInfo )
+ {
+ switch ( pTypeInfo->nType )
+ {
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ if ( !nPrec )
+ nPrec = pTypeInfo->nPrecision;
+ break;
+ }
+ }
+
+ return nPrec;
+}
+
+sal_Int32 OFieldDescription::GetScale() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_SCALE) )
+ return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_SCALE));
+ else
+ return m_nScale;
+}
+
+sal_Int32 OFieldDescription::GetIsNullable() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) )
+ return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ISNULLABLE));
+ else
+ return m_nIsNullable;
+}
+
+sal_Int32 OFieldDescription::GetFormatKey() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_FORMATKEY) )
+ return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_FORMATKEY));
+ else
+ return m_nFormatKey;
+}
+
+SvxCellHorJustify OFieldDescription::GetHorJustify() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ALIGN) )
+ return ::dbaui::mapTextJustify(::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ALIGN)));
+ else
+ return m_eHorJustify;
+}
+
+
+TOTypeInfoSP OFieldDescription::getSpecialTypeInfo() const
+{
+ TOTypeInfoSP pSpecialType = std::make_shared<OTypeInfo>();
+ *pSpecialType = *m_pType;
+ pSpecialType->nPrecision = GetPrecision();
+ pSpecialType->nMaximumScale = static_cast<sal_Int16>(GetScale());
+ pSpecialType->bAutoIncrement = IsAutoIncrement(); // http://dba.openoffice.org/issues/show_bug.cgi?id=115398 fixed by ludob
+ return pSpecialType;
+}
+
+bool OFieldDescription::IsAutoIncrement() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT) )
+ return ::cppu::any2bool(m_xDest->getPropertyValue(PROPERTY_ISAUTOINCREMENT));
+ else
+ return m_bIsAutoIncrement;
+}
+
+
+bool OFieldDescription::IsNullable() const
+{
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) )
+ return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ISNULLABLE)) == css::sdbc::ColumnValue::NULLABLE;
+ else
+ return m_nIsNullable == css::sdbc::ColumnValue::NULLABLE;
+}
+
+void OFieldDescription::SetTypeName(const OUString& _sTypeName)
+{
+ try
+ {
+ if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPENAME) )
+ m_xDest->setPropertyValue(PROPERTY_TYPENAME,Any(_sTypeName));
+ else
+ m_sTypeName = _sTypeName;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OFieldDescription::copyColumnSettingsTo(const Reference< XPropertySet >& _rxColumn)
+{
+ if ( !_rxColumn.is() )
+ return;
+
+ Reference<XPropertySetInfo> xInfo = _rxColumn->getPropertySetInfo();
+
+ if ( GetFormatKey() != NumberFormat::ALL && xInfo->hasPropertyByName(PROPERTY_FORMATKEY) )
+ _rxColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(GetFormatKey()));
+ if ( GetHorJustify() != SvxCellHorJustify::Standard && xInfo->hasPropertyByName(PROPERTY_ALIGN) )
+ _rxColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(GetHorJustify())));
+ if ( !GetHelpText().isEmpty() && xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
+ _rxColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(GetHelpText()));
+ if ( GetControlDefault().hasValue() && xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) )
+ _rxColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,GetControlDefault());
+
+ if(xInfo->hasPropertyByName(PROPERTY_RELATIVEPOSITION))
+ _rxColumn->setPropertyValue(PROPERTY_RELATIVEPOSITION,m_aRelativePosition);
+ if(xInfo->hasPropertyByName(PROPERTY_WIDTH))
+ _rxColumn->setPropertyValue(PROPERTY_WIDTH,m_aWidth);
+ if(xInfo->hasPropertyByName(PROPERTY_HIDDEN))
+ _rxColumn->setPropertyValue(PROPERTY_HIDDEN,Any(m_bHidden));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TEditControl.cxx b/dbaccess/source/ui/tabledesign/TEditControl.cxx
new file mode 100644
index 000000000..5f7809882
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TEditControl.cxx
@@ -0,0 +1,1679 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TEditControl.hxx"
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <helpids.h>
+#include <comphelper/types.hxx>
+#include <FieldDescControl.hxx>
+#include <FieldDescriptions.hxx>
+#include "TableUndo.hxx"
+#include <TableController.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbtools.hxx>
+#include <SqlNameEdit.hxx>
+#include <TableRowExchange.hxx>
+#include <o3tl/safeint.hxx>
+#include <sot/storage.hxx>
+#include <svx/svxids.hrc>
+#include <UITools.hxx>
+#include "TableFieldControl.hxx"
+#include <dsntypes.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::dbaui;
+using namespace ::comphelper;
+using namespace ::svt;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+
+
+#define HANDLE_ID 0
+
+// default field widths
+#define FIELDNAME_WIDTH 100
+#define FIELDTYPE_WIDTH 150
+#define FIELDDESCR_WIDTH 300
+
+// Maximum length in description field
+#define MAX_DESCR_LEN 256
+
+OTableEditorCtrl::ClipboardInvalidator::ClipboardInvalidator(OTableEditorCtrl* _pOwner)
+: m_aInvalidateTimer("dbaccess ClipboardInvalidator")
+, m_pOwner(_pOwner)
+{
+
+ m_aInvalidateTimer.SetTimeout(500);
+ m_aInvalidateTimer.SetInvokeHandler(LINK(this, OTableEditorCtrl::ClipboardInvalidator, OnInvalidate));
+ m_aInvalidateTimer.Start();
+}
+
+OTableEditorCtrl::ClipboardInvalidator::~ClipboardInvalidator()
+{
+ m_aInvalidateTimer.Stop();
+}
+
+void OTableEditorCtrl::ClipboardInvalidator::Stop()
+{
+ m_aInvalidateTimer.Stop();
+}
+
+IMPL_LINK_NOARG(OTableEditorCtrl::ClipboardInvalidator, OnInvalidate, Timer *, void)
+{
+ m_pOwner->GetView()->getController().InvalidateFeature(SID_CUT);
+ m_pOwner->GetView()->getController().InvalidateFeature(SID_COPY);
+ m_pOwner->GetView()->getController().InvalidateFeature(SID_PASTE);
+}
+
+void OTableEditorCtrl::Init()
+{
+ OTableRowView::Init();
+
+ // Should it be opened ReadOnly?
+ bool bRead(GetView()->getController().isReadOnly());
+
+ SetReadOnly( bRead );
+
+ // Insert the columns
+ InsertDataColumn( FIELD_NAME, DBA_RES(STR_TAB_FIELD_COLUMN_NAME), FIELDNAME_WIDTH );
+
+ InsertDataColumn( FIELD_TYPE, DBA_RES(STR_TAB_FIELD_COLUMN_DATATYPE), FIELDTYPE_WIDTH );
+
+ ::dbaccess::ODsnTypeCollection aDsnTypes(GetView()->getController().getORB());
+ bool bShowColumnDescription = aDsnTypes.supportsColumnDescription(::comphelper::getString(GetView()->getController().getDataSource()->getPropertyValue(PROPERTY_URL)));
+ InsertDataColumn( HELP_TEXT, DBA_RES(STR_TAB_HELP_TEXT), bShowColumnDescription ? FIELDTYPE_WIDTH : FIELDDESCR_WIDTH );
+
+ if ( bShowColumnDescription )
+ {
+ InsertDataColumn( COLUMN_DESCRIPTION, DBA_RES(STR_COLUMN_DESCRIPTION), FIELDTYPE_WIDTH );
+ }
+
+ InitCellController();
+
+ // Insert the rows
+ RowInserted(0, m_pRowList->size());
+}
+
+OTableEditorCtrl::OTableEditorCtrl(vcl::Window* pWindow, OTableDesignView* pView)
+ :OTableRowView(pWindow)
+ ,m_pView(pView)
+ ,pNameCell(nullptr)
+ ,pTypeCell(nullptr)
+ ,pHelpTextCell(nullptr)
+ ,pDescrCell(nullptr)
+ ,pDescrWin(nullptr)
+ ,nCutEvent(nullptr)
+ ,nPasteEvent(nullptr)
+ ,nDeleteEvent(nullptr)
+ ,nInsNewRowsEvent(nullptr)
+ ,nInvalidateTypeEvent(nullptr)
+ ,m_eChildFocus(NONE)
+ ,nOldDataPos(-1)
+ ,bReadOnly(true)
+ ,m_aInvalidate(this)
+{
+ SetHelpId(HID_TABDESIGN_BACKGROUND);
+ GetDataWindow().SetHelpId(HID_CTL_TABLEEDIT);
+
+ m_pRowList = &GetView()->getController().getRows();
+ m_nDataPos = 0;
+}
+
+SfxUndoManager& OTableEditorCtrl::GetUndoManager() const
+{
+ return GetView()->getController().GetUndoManager();
+}
+
+
+void OTableEditorCtrl::SetReadOnly( bool bRead )
+{
+ // nothing to do?
+ if (bRead == IsReadOnly())
+ // This check is important, as the underlying Def may be unnecessarily locked or unlocked
+ // or worse, this action may not be reversed afterwards
+ return;
+
+ bReadOnly = bRead;
+
+ // Disable active cells
+ sal_Int32 nRow(GetCurRow());
+ sal_uInt16 nCol(GetCurColumnId());
+ DeactivateCell();
+
+ // Select the correct Browsers cursor
+ BrowserMode nMode(BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT |
+ BrowserMode::HLINES | BrowserMode::VLINES|BrowserMode::AUTOSIZE_LASTCOL);
+ if( !bReadOnly )
+ nMode |= BrowserMode::HIDECURSOR;
+ SetMode(nMode);
+
+ if( !bReadOnly )
+ ActivateCell( nRow, nCol );
+}
+
+void OTableEditorCtrl::InitCellController()
+{
+ // Cell Field name
+ sal_Int32 nMaxTextLen = 0;
+ OUString sExtraNameChars;
+ Reference<XConnection> xCon;
+ try
+ {
+ xCon = GetView()->getController().getConnection();
+ Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>();
+
+ // length 0 is treated by Entry::set_max_length as unlimited
+ nMaxTextLen = xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0;
+
+ sExtraNameChars = xMetaData.is() ? xMetaData->getExtraNameCharacters() : OUString();
+
+ }
+ catch(SQLException&)
+ {
+ OSL_FAIL("getMaxColumnNameLength");
+ }
+
+ pNameCell = VclPtr<OSQLNameEditControl>::Create(&GetDataWindow(), sExtraNameChars);
+ pNameCell->get_widget().set_max_length(nMaxTextLen);
+ pNameCell->setCheck( isSQL92CheckEnabled(xCon) );
+
+ // Cell type
+ pTypeCell = VclPtr<ListBoxControl>::Create( &GetDataWindow() );
+
+ // Cell description
+ pDescrCell = VclPtr<EditControl>::Create(&GetDataWindow());
+ pDescrCell->get_widget().set_max_length(MAX_DESCR_LEN);
+
+ pHelpTextCell = VclPtr<EditControl>::Create(&GetDataWindow());
+ pHelpTextCell->get_widget().set_max_length(MAX_DESCR_LEN);
+
+ pNameCell->SetHelpId(HID_TABDESIGN_NAMECELL);
+ pTypeCell->SetHelpId(HID_TABDESIGN_TYPECELL);
+ pDescrCell->SetHelpId(HID_TABDESIGN_COMMENTCELL);
+ pHelpTextCell->SetHelpId(HID_TABDESIGN_HELPTEXT);
+
+ Size aHeight;
+ const Control* pControls[] = { pTypeCell,pDescrCell,pNameCell,pHelpTextCell};
+ for(const Control* pControl : pControls)
+ {
+ const Size aTemp(pControl->GetOptimalSize());
+ if ( aTemp.Height() > aHeight.Height() )
+ aHeight.setHeight( aTemp.Height() );
+ }
+ SetDataRowHeight(aHeight.Height());
+
+ ClearModified();
+}
+
+void OTableEditorCtrl::ClearModified()
+{
+ pNameCell->get_widget().save_value();
+ pDescrCell->get_widget().save_value();
+ pHelpTextCell->get_widget().save_value();
+ pTypeCell->get_widget().save_value();
+}
+
+OTableEditorCtrl::~OTableEditorCtrl()
+{
+ disposeOnce();
+}
+
+void OTableEditorCtrl::dispose()
+{
+ // Reset the Undo-Manager
+ GetUndoManager().Clear();
+
+ m_aInvalidate.Stop();
+
+ // Take possible Events from the queue
+ if( nCutEvent )
+ Application::RemoveUserEvent( nCutEvent );
+ if( nPasteEvent )
+ Application::RemoveUserEvent( nPasteEvent );
+ if( nDeleteEvent )
+ Application::RemoveUserEvent( nDeleteEvent );
+ if( nInsNewRowsEvent )
+ Application::RemoveUserEvent( nInsNewRowsEvent );
+ if( nInvalidateTypeEvent )
+ Application::RemoveUserEvent( nInvalidateTypeEvent );
+
+ // Delete the control types
+ pNameCell.disposeAndClear();
+ pTypeCell.disposeAndClear();
+ pDescrCell.disposeAndClear();
+ pHelpTextCell.disposeAndClear();
+ pDescrWin = nullptr;
+ m_pView.clear();
+ OTableRowView::dispose();
+}
+
+bool OTableEditorCtrl::SetDataPtr( sal_Int32 nRow )
+{
+ if(nRow == -1)
+ return false;
+
+ OSL_ENSURE(nRow < static_cast<tools::Long>(m_pRowList->size()),"Row is greater than size!");
+ if(nRow >= static_cast<tools::Long>(m_pRowList->size()))
+ return false;
+ pActRow = (*m_pRowList)[nRow];
+ return pActRow != nullptr;
+}
+
+bool OTableEditorCtrl::SeekRow(sal_Int32 _nRow)
+{
+ // Call the Base class to remember which row must be repainted
+ EditBrowseBox::SeekRow(_nRow);
+
+ m_nCurrentPos = _nRow;
+ return SetDataPtr(_nRow);
+}
+
+void OTableEditorCtrl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect,
+ sal_uInt16 nColumnId ) const
+{
+ const OUString aText( GetCellText( m_nCurrentPos, nColumnId ));
+
+ rDev.Push( vcl::PushFlags::CLIPREGION );
+ rDev.SetClipRegion(vcl::Region(rRect));
+ rDev.DrawText( rRect, aText, DrawTextFlags::Left | DrawTextFlags::VCenter );
+ rDev.Pop();
+}
+
+CellController* OTableEditorCtrl::GetController(sal_Int32 nRow, sal_uInt16 nColumnId)
+{
+ // If EditorCtrl is ReadOnly, editing is forbidden
+ Reference<XPropertySet> xTable = GetView()->getController().getTable();
+ if (IsReadOnly() || ( xTable.is() &&
+ xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE) &&
+ ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW"))
+ return nullptr;
+
+ // If the row is ReadOnly, editing is forbidden
+ SetDataPtr( nRow );
+ if( pActRow->IsReadOnly() )
+ return nullptr;
+
+ OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
+ switch (nColumnId)
+ {
+ case FIELD_NAME:
+ return new EditCellController( pNameCell );
+ case FIELD_TYPE:
+ if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty())
+ return new ListBoxCellController( pTypeCell );
+ else return nullptr;
+ case HELP_TEXT:
+ if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty())
+ return new EditCellController( pHelpTextCell );
+ else
+ return nullptr;
+ case COLUMN_DESCRIPTION:
+ if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty())
+ return new EditCellController( pDescrCell );
+ else
+ return nullptr;
+ default:
+ return nullptr;
+ }
+}
+
+void OTableEditorCtrl::InitController(CellControllerRef&, sal_Int32 nRow, sal_uInt16 nColumnId)
+{
+ SeekRow( nRow == -1 ? GetCurRow() : nRow);
+ OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
+ OUString aInitString;
+
+ switch (nColumnId)
+ {
+ case FIELD_NAME:
+ {
+ if( pActFieldDescr )
+ aInitString = pActFieldDescr->GetName();
+
+ weld::Entry& rEntry = pNameCell->get_widget();
+ rEntry.set_text(aInitString);
+ rEntry.save_value();
+ break;
+ }
+ case FIELD_TYPE:
+ {
+ if ( pActFieldDescr && pActFieldDescr->getTypeInfo() )
+ aInitString = pActFieldDescr->getTypeInfo()->aUIName;
+
+ // Set the ComboBox contents
+ weld::ComboBox& rTypeList = pTypeCell->get_widget();
+ rTypeList.clear();
+ if( !pActFieldDescr )
+ break;
+
+ const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo();
+ for (auto const& elem : rTypeInfo)
+ rTypeList.append_text(elem.second->aUIName);
+ rTypeList.set_active_text(aInitString);
+ }
+
+ break;
+ case HELP_TEXT:
+ {
+ if( pActFieldDescr )
+ aInitString = pActFieldDescr->GetHelpText();
+ weld::Entry& rEntry = pHelpTextCell->get_widget();
+ rEntry.set_text(aInitString);
+ rEntry.save_value();
+ break;
+ }
+ case COLUMN_DESCRIPTION:
+ {
+ if( pActFieldDescr )
+ aInitString = pActFieldDescr->GetDescription();
+ weld::Entry& rEntry = pDescrCell->get_widget();
+ rEntry.set_text(aInitString);
+ rEntry.save_value();
+ break;
+ }
+ }
+}
+
+EditBrowseBox::RowStatus OTableEditorCtrl::GetRowStatus(sal_Int32 nRow) const
+{
+ const_cast<OTableEditorCtrl*>(this)->SetDataPtr( nRow );
+ if( !pActRow )
+ return EditBrowseBox::CLEAN;
+ if (nRow >= 0 && nRow == m_nDataPos)
+ {
+ if( pActRow->IsPrimaryKey() )
+ return EditBrowseBox::CURRENT_PRIMARYKEY;
+ return EditBrowseBox::CURRENT;
+ }
+ else
+ {
+ if( pActRow->IsPrimaryKey() )
+ return EditBrowseBox::PRIMARYKEY;
+ return EditBrowseBox::CLEAN;
+ }
+}
+
+void OTableEditorCtrl::SaveCurRow()
+{
+ if (GetFieldDescr(GetCurRow()) == nullptr)
+ // there is no data in the current row
+ return;
+ if (!SaveModified())
+ return;
+
+ SetDataPtr(GetCurRow());
+ pDescrWin->SaveData( pActRow->GetActFieldDescr() );
+}
+
+void OTableEditorCtrl::DisplayData(sal_Int32 nRow)
+{
+ // go to the correct cell
+ SetDataPtr(nRow);
+
+ // Disable Edit-Mode temporarily
+ bool bWasEditing = IsEditing();
+ if (bWasEditing)
+ DeactivateCell();
+
+ CellControllerRef aTemp;
+ InitController(aTemp, nRow, FIELD_NAME);
+ InitController(aTemp, nRow, FIELD_TYPE);
+ InitController(aTemp, nRow, COLUMN_DESCRIPTION);
+ InitController(aTemp, nRow, HELP_TEXT);
+
+ GoToRow(nRow);
+ // Update the Description-Window
+ GetView()->GetDescWin()->DisplayData(GetFieldDescr(nRow));
+ // redraw the row
+ RowModified(nRow);
+
+ // and re-enable edit mode
+ ActivateCell(nRow, GetCurColumnId());
+}
+
+void OTableEditorCtrl::CursorMoved()
+{
+ // New line?
+ m_nDataPos = GetCurRow();
+ if( m_nDataPos != nOldDataPos && m_nDataPos != -1)
+ {
+ CellControllerRef aTemp;
+ InitController(aTemp,m_nDataPos,FIELD_NAME);
+ InitController(aTemp,m_nDataPos,FIELD_TYPE);
+ InitController(aTemp,m_nDataPos,COLUMN_DESCRIPTION);
+ InitController(aTemp,m_nDataPos,HELP_TEXT);
+ }
+
+ OTableRowView::CursorMoved();
+}
+
+sal_Int32 OTableEditorCtrl::HasFieldName( std::u16string_view rFieldName )
+{
+
+ Reference<XConnection> xCon = GetView()->getController().getConnection();
+ Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>();
+
+ ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
+
+ sal_Int32 nCount(0);
+ for (auto const& row : *m_pRowList)
+ {
+ OFieldDescription* pFieldDescr = row->GetActFieldDescr();
+ if( pFieldDescr && bCase(rFieldName,pFieldDescr->GetName()))
+ nCount++;
+ }
+ return nCount;
+}
+
+void OTableEditorCtrl::SaveData(sal_Int32 nRow, sal_uInt16 nColId)
+{
+ // Store the cell content
+ SetDataPtr( nRow == -1 ? GetCurRow() : nRow);
+ OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
+
+ switch( nColId)
+ {
+ // Store NameCell
+ case FIELD_NAME:
+ {
+ // If there is no name, do nothing
+ weld::Entry& rEntry = pNameCell->get_widget();
+ const OUString aName(rEntry.get_text());
+
+ if( aName.isEmpty() )
+ {
+ // If FieldDescr exists, the field is deleted and the old content restored
+ if (pActFieldDescr)
+ {
+ GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, FIELD_TYPE, pActFieldDescr->getTypeInfo()));
+ SwitchType(TOTypeInfoSP());
+ pActFieldDescr = pActRow->GetActFieldDescr();
+ }
+ else
+ return;
+ }
+ if(pActFieldDescr)
+ pActFieldDescr->SetName( aName );
+ rEntry.save_value();
+
+ break;
+ }
+
+ // Store the field type
+ case FIELD_TYPE:
+ break;
+
+ // Store DescrCell
+ case HELP_TEXT:
+ {
+ // if the current field description is NULL, set Default
+ weld::Entry& rEntry = pHelpTextCell->get_widget();
+ if( !pActFieldDescr )
+ {
+ rEntry.set_text(OUString());
+ rEntry.save_value();
+ }
+ else
+ pActFieldDescr->SetHelpText(rEntry.get_text());
+ break;
+ }
+ case COLUMN_DESCRIPTION:
+ {
+ // Set the default if the field description is null
+ weld::Entry& rEntry = pDescrCell->get_widget();
+ if( !pActFieldDescr )
+ {
+ rEntry.set_text(OUString());
+ rEntry.save_value();
+ }
+ else
+ pActFieldDescr->SetDescription(rEntry.get_text());
+ break;
+ }
+ case FIELD_PROPERTY_DEFAULT:
+ case FIELD_PROPERTY_REQUIRED:
+ case FIELD_PROPERTY_TEXTLEN:
+ case FIELD_PROPERTY_NUMTYPE:
+ case FIELD_PROPERTY_AUTOINC:
+ case FIELD_PROPERTY_LENGTH:
+ case FIELD_PROPERTY_SCALE:
+ case FIELD_PROPERTY_BOOL_DEFAULT:
+ pDescrWin->SaveData(pActFieldDescr);
+
+ if ( FIELD_PROPERTY_AUTOINC == nColId && pActFieldDescr->IsAutoIncrement() )
+ {
+ OTableController& rController = GetView()->getController();
+ if ( rController.isAutoIncrementPrimaryKey() )
+ {
+ pActFieldDescr->SetPrimaryKey( true );
+ InvalidateHandleColumn();
+ Invalidate();
+ }
+ }
+ break;
+ }
+}
+
+bool OTableEditorCtrl::SaveModified()
+{
+ sal_uInt16 nColId = GetCurColumnId();
+
+ switch( nColId )
+ {
+ // Field type
+ case FIELD_TYPE:
+ {
+ // Reset the type
+ resetType();
+ } break;
+ }
+
+ return true;
+}
+
+bool OTableEditorCtrl::CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol)
+{
+
+ if (!EditBrowseBox::CursorMoving(nNewRow, nNewCol))
+ return false;
+
+ // Called after SaveModified(), current row is still the old one
+ m_nDataPos = nNewRow;
+ nOldDataPos = GetCurRow();
+
+ // Reset the markers
+ InvalidateStatusCell( nOldDataPos );
+ InvalidateStatusCell( m_nDataPos );
+
+ // Store the data from the Property window
+ if( SetDataPtr(nOldDataPos) && pDescrWin)
+ pDescrWin->SaveData( pActRow->GetActFieldDescr() );
+
+ // Show new data in the Property window
+ if( SetDataPtr(m_nDataPos) && pDescrWin)
+ pDescrWin->DisplayData( pActRow->GetActFieldDescr() );
+
+ return true;
+}
+
+IMPL_LINK_NOARG( OTableEditorCtrl, InvalidateFieldType, void*, void )
+{
+ nInvalidateTypeEvent = nullptr;
+ Invalidate( GetFieldRectPixel(nOldDataPos, FIELD_TYPE) );
+}
+
+void OTableEditorCtrl::CellModified( sal_Int32 nRow, sal_uInt16 nColId )
+{
+
+ // If the description is null, use the default
+ if(nRow == -1)
+ nRow = GetCurRow();
+ SetDataPtr( nRow );
+ OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr();
+
+ OUString sActionDescription;
+ switch ( nColId )
+ {
+ case FIELD_NAME: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_NAME ); break;
+ case FIELD_TYPE: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_TYPE ); break;
+ case HELP_TEXT:
+ case COLUMN_DESCRIPTION: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_DESCRIPTION ); break;
+ default: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_ATTRIBUTE ); break;
+ }
+
+ GetUndoManager().EnterListAction( sActionDescription, OUString(), 0, ViewShellId(-1) );
+ if (!pActFieldDescr)
+ {
+ const OTypeInfoMap& rTypeInfoMap = GetView()->getController().getTypeInfo();
+ if ( !rTypeInfoMap.empty() )
+ {
+ OTypeInfoMap::const_iterator aTypeIter = rTypeInfoMap.find(DataType::VARCHAR);
+ if ( aTypeIter == rTypeInfoMap.end() )
+ aTypeIter = rTypeInfoMap.begin();
+ pActRow->SetFieldType( aTypeIter->second );
+ }
+ else
+ pActRow->SetFieldType( GetView()->getController().getTypeInfoFallBack() );
+
+ nInvalidateTypeEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, InvalidateFieldType), nullptr, true );
+ pActFieldDescr = pActRow->GetActFieldDescr();
+ pDescrWin->DisplayData( pActFieldDescr );
+ GetUndoManager().AddUndoAction( std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, nColId+1, TOTypeInfoSP()) );
+ }
+
+ if( nColId != FIELD_TYPE )
+ GetUndoManager().AddUndoAction( std::make_unique<OTableDesignCellUndoAct>(this, nRow, nColId) );
+ else
+ {
+ GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, GetCurRow(), nColId, GetFieldDescr(GetCurRow())->getTypeInfo()));
+ resetType();
+ }
+
+ SaveData(nRow,nColId);
+ // SaveData could create an undo action as well
+ GetUndoManager().LeaveListAction();
+ RowModified(nRow);
+
+ // Set the Modify flag
+ GetView()->getController().setModified( true );
+ InvalidateFeatures();
+}
+
+void OTableEditorCtrl::resetType()
+{
+ sal_Int32 nPos = pTypeCell->get_widget().get_active();
+ if(nPos != -1)
+ SwitchType( GetView()->getController().getTypeInfo(nPos) );
+ else
+ SwitchType(TOTypeInfoSP());
+}
+
+void OTableEditorCtrl::CellModified()
+{
+ CellModified( GetCurRow(), GetCurColumnId() );
+}
+
+void OTableEditorCtrl::InvalidateFeatures()
+{
+ GetView()->getController().InvalidateFeature(SID_UNDO);
+ GetView()->getController().InvalidateFeature(SID_REDO);
+ GetView()->getController().InvalidateFeature(SID_SAVEDOC);
+}
+
+void OTableEditorCtrl::CopyRows()
+{
+ // set to the right row and save it
+ if( SetDataPtr(m_nDataPos) )
+ pDescrWin->SaveData( pActRow->GetActFieldDescr() );
+
+ // Copy selected rows to the ClipboardList
+ std::shared_ptr<OTableRow> pClipboardRow;
+ std::shared_ptr<OTableRow> pRow;
+ std::vector< std::shared_ptr<OTableRow> > vClipboardList;
+ vClipboardList.reserve(GetSelectRowCount());
+
+ for( tools::Long nIndex=FirstSelectedRow(); nIndex != SFX_ENDOFSELECTION; nIndex=NextSelectedRow() )
+ {
+ pRow = (*m_pRowList)[nIndex];
+ OSL_ENSURE(pRow,"OTableEditorCtrl::CopyRows: Row is NULL!");
+ if ( pRow && pRow->GetActFieldDescr() )
+ {
+ pClipboardRow = std::make_shared<OTableRow>( *pRow );
+ vClipboardList.push_back( pClipboardRow);
+ }
+ }
+ if(!vClipboardList.empty())
+ {
+ rtl::Reference<OTableRowExchange> pData = new OTableRowExchange(std::move(vClipboardList));
+ pData->CopyToClipboard(GetParent());
+ }
+}
+
+OUString OTableEditorCtrl::GenerateName( const OUString& rName )
+{
+ // Create a base name for appending numbers to
+ OUString aBaseName;
+ Reference<XConnection> xCon = GetView()->getController().getConnection();
+ Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>();
+
+ sal_Int32 nMaxTextLen(xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0);
+
+ if( (rName.getLength()+2) >nMaxTextLen )
+ aBaseName = rName.copy( 0, nMaxTextLen-2 );
+ else
+ aBaseName = rName;
+
+ // append a sequential number to the base name (up to 99)
+ OUString aFieldName( rName);
+ sal_Int32 i=1;
+ while( HasFieldName(aFieldName) )
+ {
+ aFieldName = aBaseName + OUString::number(i);
+ i++;
+ }
+
+ return aFieldName;
+}
+
+void OTableEditorCtrl::InsertRows( sal_Int32 nRow )
+{
+
+ std::vector< std::shared_ptr<OTableRow> > vInsertedUndoRedoRows; // need for undo/redo handling
+ // get rows from clipboard
+ TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
+ if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED))
+ {
+ ::tools::SvRef<SotTempStream> aStreamRef;
+ bool bOk = aTransferData.GetSotStorageStream(SotClipboardFormatId::SBA_TABED,aStreamRef);
+ if (bOk && aStreamRef.is())
+ {
+ aStreamRef->Seek(STREAM_SEEK_TO_BEGIN);
+ aStreamRef->ResetError();
+ sal_Int32 nInsertRow = nRow;
+ std::shared_ptr<OTableRow> pRow;
+ sal_Int32 nSize = 0;
+ (*aStreamRef).ReadInt32( nSize );
+ vInsertedUndoRedoRows.reserve(nSize);
+ for(sal_Int32 i=0;i < nSize;++i)
+ {
+ pRow = std::make_shared<OTableRow>();
+ ReadOTableRow( *aStreamRef, *pRow );
+ pRow->SetReadOnly( false );
+ sal_Int32 nType = pRow->GetActFieldDescr()->GetType();
+ if ( pRow->GetActFieldDescr() )
+ pRow->GetActFieldDescr()->SetType(GetView()->getController().getTypeInfoByType(nType));
+ // Adjust the field names
+ pRow->GetActFieldDescr()->SetName( GenerateName( pRow->GetActFieldDescr()->GetName() ) );
+ pRow->SetPos(nInsertRow);
+ m_pRowList->insert( m_pRowList->begin()+nInsertRow,pRow );
+ vInsertedUndoRedoRows.push_back(std::make_shared<OTableRow>(*pRow));
+ nInsertRow++;
+ }
+ }
+ }
+ // RowInserted calls CursorMoved.
+ // The UI data should not be stored here.
+ RowInserted( nRow,vInsertedUndoRedoRows.size() );
+
+ // Create the Undo-Action
+ GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsUndoAct>(this, nRow, std::move(vInsertedUndoRedoRows)) );
+ GetView()->getController().setModified( true );
+ InvalidateFeatures();
+}
+
+void OTableEditorCtrl::DeleteRows()
+{
+ OSL_ENSURE(GetView()->getController().isDropAllowed(),"Call of DeleteRows not valid here. Please check isDropAllowed!");
+ // Create the Undo-Action
+ GetUndoManager().AddUndoAction( std::make_unique<OTableEditorDelUndoAct>(this) );
+
+ // Delete all marked rows
+ tools::Long nIndex = FirstSelectedRow();
+ nOldDataPos = nIndex;
+
+ while( nIndex != SFX_ENDOFSELECTION )
+ {
+ // Remove rows
+ m_pRowList->erase( m_pRowList->begin()+nIndex );
+ RowRemoved( nIndex );
+
+ // Insert the empty row at the end
+ m_pRowList->push_back( std::make_shared<OTableRow>());
+ RowInserted( GetRowCount()-1 );
+
+ nIndex = FirstSelectedRow();
+ }
+
+ // Force the current record to be displayed
+ m_nDataPos = GetCurRow();
+ InvalidateStatusCell( nOldDataPos );
+ InvalidateStatusCell( m_nDataPos );
+ SetDataPtr( m_nDataPos );
+ ActivateCell();
+ pDescrWin->DisplayData( pActRow->GetActFieldDescr() );
+ GetView()->getController().setModified( true );
+ InvalidateFeatures();
+}
+
+void OTableEditorCtrl::InsertNewRows( sal_Int32 nRow )
+{
+ OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!");
+ // Create Undo-Action
+ sal_Int32 nInsertRows = GetSelectRowCount();
+ if( !nInsertRows )
+ nInsertRows = 1;
+ GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsNewUndoAct>(this, nRow, nInsertRows) );
+ // Insert the number of selected rows
+ for( tools::Long i=nRow; i<(nRow+nInsertRows); i++ )
+ m_pRowList->insert( m_pRowList->begin()+i ,std::make_shared<OTableRow>());
+ RowInserted( nRow, nInsertRows );
+
+ GetView()->getController().setModified( true );
+ InvalidateFeatures();
+}
+
+void OTableEditorCtrl::SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText )
+{
+ // Set the Browser Controls
+ if( nColId < FIELD_FIRST_VIRTUAL_COLUMN )
+ {
+ GoToRow( nRow );
+ GoToColumnId( nColId );
+ CellControllerRef xController = Controller();
+ if(xController.is())
+ xController->GetWindow().SetText( rText );
+ else
+ RowModified(nRow,nColId);
+ }
+
+ // Set the Tabpage controls
+ else
+ {
+ pDescrWin->SetControlText( nColId, rText );
+ }
+}
+
+void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo )
+{
+ // Relocate the current pointer
+ if( nRow == -1 )
+ nRow = GetCurRow();
+ OFieldDescription* pFieldDescr = GetFieldDescr( nRow );
+ if( !pFieldDescr && nColId != FIELD_TYPE)
+ return;
+
+ // Set individual fields
+ switch( nColId )
+ {
+ case FIELD_TYPE:
+ SwitchType( _pTypeInfo );
+ break;
+ default:
+ OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
+ }
+ SetControlText(nRow,nColId,_pTypeInfo ? _pTypeInfo->aUIName : OUString());
+}
+
+void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rNewData )
+{
+ // Relocate the current pointer
+ if( nRow == -1 )
+ nRow = GetCurRow();
+ OFieldDescription* pFieldDescr = GetFieldDescr( nRow );
+ if( !pFieldDescr && nColId != FIELD_TYPE)
+ return;
+
+ OUString sValue;
+ // Set individual fields
+ switch( nColId )
+ {
+ case FIELD_NAME:
+ sValue = ::comphelper::getString(_rNewData);
+ pFieldDescr->SetName( sValue );
+ break;
+
+ case FIELD_TYPE:
+ OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
+ break;
+
+ case COLUMN_DESCRIPTION:
+ sValue = ::comphelper::getString(_rNewData);
+ pFieldDescr->SetDescription( sValue );
+ break;
+
+ case FIELD_PROPERTY_DEFAULT:
+ pFieldDescr->SetControlDefault( _rNewData );
+ sValue = GetView()->GetDescWin()->getGenPage()->getControlDefault(pFieldDescr);
+ break;
+
+ case FIELD_PROPERTY_REQUIRED:
+ {
+ sValue = ::comphelper::getString(_rNewData);
+ pFieldDescr->SetIsNullable( sValue.toInt32() );
+ }
+ break;
+
+ case FIELD_PROPERTY_TEXTLEN:
+ case FIELD_PROPERTY_LENGTH:
+ {
+ sValue = ::comphelper::getString(_rNewData);
+ pFieldDescr->SetPrecision( sValue.toInt32() );
+ }
+ break;
+
+ case FIELD_PROPERTY_NUMTYPE:
+ OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!");
+ break;
+
+ case FIELD_PROPERTY_AUTOINC:
+ {
+ sValue = ::comphelper::getString(_rNewData);
+ pFieldDescr->SetAutoIncrement(sValue == DBA_RES(STR_VALUE_YES));
+ }
+ break;
+ case FIELD_PROPERTY_SCALE:
+ {
+ sValue = ::comphelper::getString(_rNewData);
+ pFieldDescr->SetScale(sValue.toInt32());
+ }
+ break;
+
+ case FIELD_PROPERTY_BOOL_DEFAULT:
+ sValue = GetView()->GetDescWin()->BoolStringPersistent(::comphelper::getString(_rNewData));
+ pFieldDescr->SetControlDefault(Any(sValue));
+ break;
+
+ case FIELD_PROPERTY_FORMAT:
+ {
+ sValue = ::comphelper::getString(_rNewData);
+ pFieldDescr->SetFormatKey(sValue.toInt32());
+ }
+ break;
+ }
+
+ SetControlText(nRow,nColId,sValue);
+}
+
+Any OTableEditorCtrl::GetCellData( sal_Int32 nRow, sal_uInt16 nColId )
+{
+ OFieldDescription* pFieldDescr = GetFieldDescr( nRow );
+ if( !pFieldDescr )
+ return Any();
+
+ // Relocate the current pointer
+ if( nRow==-1 )
+ nRow = GetCurRow();
+ SetDataPtr( nRow );
+
+ static const OUString strYes(DBA_RES(STR_VALUE_YES));
+ static const OUString strNo(DBA_RES(STR_VALUE_NO));
+ OUString sValue;
+ // Read out the fields
+ switch( nColId )
+ {
+ case FIELD_NAME:
+ sValue = pFieldDescr->GetName();
+ break;
+
+ case FIELD_TYPE:
+ if ( pFieldDescr->getTypeInfo() )
+ sValue = pFieldDescr->getTypeInfo()->aUIName;
+ break;
+
+ case COLUMN_DESCRIPTION:
+ sValue = pFieldDescr->GetDescription();
+ break;
+ case HELP_TEXT:
+ sValue = pFieldDescr->GetHelpText();
+ break;
+
+ case FIELD_PROPERTY_DEFAULT:
+ return pFieldDescr->GetControlDefault();
+
+ case FIELD_PROPERTY_REQUIRED:
+ sValue = pFieldDescr->GetIsNullable() == ColumnValue::NULLABLE ? strYes : strNo;
+ break;
+
+ case FIELD_PROPERTY_TEXTLEN:
+ case FIELD_PROPERTY_LENGTH:
+ sValue = OUString::number(pFieldDescr->GetPrecision());
+ break;
+
+ case FIELD_PROPERTY_NUMTYPE:
+ OSL_FAIL("OTableEditorCtrl::GetCellData: invalid column!");
+ break;
+
+ case FIELD_PROPERTY_AUTOINC:
+ sValue = pFieldDescr->IsAutoIncrement() ? strYes : strNo;
+ break;
+
+ case FIELD_PROPERTY_SCALE:
+ sValue = OUString::number(pFieldDescr->GetScale());
+ break;
+
+ case FIELD_PROPERTY_BOOL_DEFAULT:
+ sValue = GetView()->GetDescWin()->BoolStringUI(::comphelper::getString(pFieldDescr->GetControlDefault()));
+ break;
+
+ case FIELD_PROPERTY_FORMAT:
+ sValue = OUString::number(pFieldDescr->GetFormatKey());
+ break;
+ }
+
+ return Any(sValue);
+}
+
+OUString OTableEditorCtrl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const
+{
+ OUString sCellText;
+ const_cast< OTableEditorCtrl* >( this )->GetCellData( nRow, nColId ) >>= sCellText;
+ return sCellText;
+}
+
+sal_uInt32 OTableEditorCtrl::GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId)
+{
+ return GetTextWidth(GetCellText(nRow, nColId)) + 2 * GetTextWidth("0");
+}
+
+OFieldDescription* OTableEditorCtrl::GetFieldDescr( sal_Int32 nRow )
+{
+ std::vector< std::shared_ptr<OTableRow> >::size_type nListCount(
+ m_pRowList->size());
+ if( (nRow<0) || (sal::static_int_cast< unsigned long >(nRow)>=nListCount) )
+ {
+ OSL_FAIL("(nRow<0) || (nRow>=nListCount)");
+ return nullptr;
+ }
+ std::shared_ptr<OTableRow> pRow = (*m_pRowList)[ nRow ];
+ if( !pRow )
+ return nullptr;
+ return pRow->GetActFieldDescr();
+}
+
+bool OTableEditorCtrl::IsCutAllowed()
+{
+ bool bIsCutAllowed = (GetView()->getController().isAddAllowed() && GetView()->getController().isDropAllowed()) ||
+ GetView()->getController().isAlterAllowed();
+
+ if (bIsCutAllowed)
+ {
+ int nStartPos, nEndPos;
+ switch(m_eChildFocus)
+ {
+ case DESCRIPTION:
+ {
+ weld::Entry& rEntry = pDescrCell->get_widget();
+ bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
+ break;
+ }
+ case HELPTEXT:
+ {
+ weld::Entry& rEntry = pHelpTextCell->get_widget();
+ bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
+ break;
+ }
+ case NAME:
+ {
+ weld::Entry& rEntry = pNameCell->get_widget();
+ bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
+ break;
+ }
+ case ROW:
+ bIsCutAllowed = IsCopyAllowed();
+ break;
+ default:
+ bIsCutAllowed = false;
+ break;
+ }
+ }
+
+ return bIsCutAllowed;
+}
+
+bool OTableEditorCtrl::IsCopyAllowed()
+{
+ bool bIsCopyAllowed = false;
+ int nStartPos, nEndPos;
+ if (m_eChildFocus == DESCRIPTION )
+ {
+ weld::Entry& rEntry = pDescrCell->get_widget();
+ bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
+ }
+ else if(HELPTEXT == m_eChildFocus )
+ {
+ weld::Entry& rEntry = pHelpTextCell->get_widget();
+ bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
+ }
+ else if(m_eChildFocus == NAME)
+ {
+ weld::Entry& rEntry = pNameCell->get_widget();
+ bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos);
+ }
+ else if(m_eChildFocus == ROW)
+ {
+ Reference<XPropertySet> xTable = GetView()->getController().getTable();
+ if( !GetSelectRowCount() || (xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW"))
+ return false;
+
+ // If one of the selected rows is empty, Copy is not possible
+ std::shared_ptr<OTableRow> pRow;
+ tools::Long nIndex = FirstSelectedRow();
+ while( nIndex != SFX_ENDOFSELECTION )
+ {
+ pRow = (*m_pRowList)[nIndex];
+ if( !pRow->GetActFieldDescr() )
+ return false;
+
+ nIndex = NextSelectedRow();
+ }
+
+ bIsCopyAllowed = true;
+ }
+
+ return bIsCopyAllowed;
+}
+
+bool OTableEditorCtrl::IsPasteAllowed() const
+{
+ bool bAllowed = GetView()->getController().isAddAllowed();
+ if ( bAllowed )
+ {
+ TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
+ bool bRowFormat = aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED);
+ if ( m_eChildFocus == ROW )
+ bAllowed = bRowFormat;
+ else
+ bAllowed = !bRowFormat && aTransferData.HasFormat(SotClipboardFormatId::STRING);
+ }
+
+ return bAllowed;
+}
+
+void OTableEditorCtrl::cut()
+{
+ if(m_eChildFocus == NAME)
+ {
+ if(GetView()->getController().isAlterAllowed())
+ {
+ SaveData(-1,FIELD_NAME);
+ pNameCell->get_widget().cut_clipboard();
+ CellModified(-1,FIELD_NAME);
+ }
+ }
+ else if(m_eChildFocus == DESCRIPTION)
+ {
+ if(GetView()->getController().isAlterAllowed())
+ {
+ SaveData(-1,COLUMN_DESCRIPTION);
+ pDescrCell->get_widget().cut_clipboard();
+ CellModified(-1,COLUMN_DESCRIPTION);
+ }
+ }
+ else if(HELPTEXT == m_eChildFocus )
+ {
+ if(GetView()->getController().isAlterAllowed())
+ {
+ SaveData(-1,HELP_TEXT);
+ pHelpTextCell->get_widget().cut_clipboard();
+ CellModified(-1,HELP_TEXT);
+ }
+ }
+ else if(m_eChildFocus == ROW)
+ {
+ if (nCutEvent)
+ Application::RemoveUserEvent(nCutEvent);
+ nCutEvent = Application::PostUserEvent(LINK(this, OTableEditorCtrl, DelayedCut), nullptr, true);
+ }
+}
+
+void OTableEditorCtrl::copy()
+{
+ if (GetSelectRowCount())
+ OTableRowView::copy();
+ else if(m_eChildFocus == NAME)
+ {
+ weld::Entry& rEntry = pNameCell->get_widget();
+ rEntry.copy_clipboard();
+ }
+ else if(HELPTEXT == m_eChildFocus )
+ {
+ weld::Entry& rEntry = pHelpTextCell->get_widget();
+ rEntry.copy_clipboard();
+ }
+ else if(m_eChildFocus == DESCRIPTION )
+ {
+ weld::Entry& rEntry = pDescrCell->get_widget();
+ rEntry.copy_clipboard();
+ }
+}
+
+void OTableEditorCtrl::paste()
+{
+ TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent()));
+ if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED))
+ {
+ if( nPasteEvent )
+ Application::RemoveUserEvent( nPasteEvent );
+ nPasteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedPaste), nullptr, true );
+ }
+ else if(m_eChildFocus == NAME)
+ {
+ if(GetView()->getController().isAlterAllowed())
+ {
+ pNameCell->get_widget().paste_clipboard();
+ CellModified();
+ }
+ }
+ else if(HELPTEXT == m_eChildFocus )
+ {
+ if(GetView()->getController().isAlterAllowed())
+ {
+ pHelpTextCell->get_widget().paste_clipboard();
+ CellModified();
+ }
+ }
+ else if(m_eChildFocus == DESCRIPTION)
+ {
+ if(GetView()->getController().isAlterAllowed())
+ {
+ pDescrCell->get_widget().paste_clipboard();
+ CellModified();
+ }
+ }
+}
+
+bool OTableEditorCtrl::IsDeleteAllowed()
+{
+
+ return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed();
+}
+
+bool OTableEditorCtrl::IsInsertNewAllowed( sal_Int32 nRow )
+{
+
+ bool bInsertNewAllowed = GetView()->getController().isAddAllowed();
+ // If fields can be added, Paste in the new fields
+ if (bInsertNewAllowed && !GetView()->getController().isDropAllowed())
+ {
+ SetDataPtr(nRow);
+ if( GetActRow()->IsReadOnly() )
+ return false;
+ }
+
+ return bInsertNewAllowed;
+}
+
+bool OTableEditorCtrl::IsPrimaryKeyAllowed()
+{
+ if( !GetSelectRowCount() )
+ return false;
+
+ OTableController& rController = GetView()->getController();
+ if ( !rController.getSdbMetaData().supportsPrimaryKeys() )
+ return false;
+
+ Reference<XPropertySet> xTable = rController.getTable();
+ // Key must not be changed
+ // This applies only if the table is not new and not a css::sdbcx::View. Otherwise no DROP is executed
+
+ if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW")
+ return false;
+ // If there is an empty field, no primary key
+ // The entry is only permitted if
+ // - there are no empty entries in the selection
+ // - No Memo or Image entries
+ // - DROP is not permitted (see above) and the column is not Required (not null flag is not set).
+ tools::Long nIndex = FirstSelectedRow();
+ std::shared_ptr<OTableRow> pRow;
+ while( nIndex != SFX_ENDOFSELECTION )
+ {
+ pRow = (*m_pRowList)[nIndex];
+ OFieldDescription* pFieldDescr = pRow->GetActFieldDescr();
+ if(!pFieldDescr)
+ return false;
+ else
+ {
+ // Memo and Image fields cannot be primary keys
+ // or if the column cannot be dropped and the Required flag is not set
+ // or if a css::sdbcx::View is available and the Required flag is not set
+ const TOTypeInfoSP& pTypeInfo = pFieldDescr->getTypeInfo();
+ if( pTypeInfo->nSearchType == ColumnSearch::NONE
+ || (pFieldDescr->IsNullable() && pRow->IsReadOnly())
+ )
+ return false;
+ }
+
+ nIndex = NextSelectedRow();
+ }
+
+ return true;
+}
+
+void OTableEditorCtrl::Command(const CommandEvent& rEvt)
+{
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ Point aMenuPos( rEvt.GetMousePosPixel() );
+ if (!rEvt.IsMouseEvent())
+ {
+ if ( 1 == GetSelectColumnCount() )
+ {
+ sal_uInt16 nSelId = GetColumnId(
+ sal::static_int_cast< sal_uInt16 >(
+ FirstSelectedColumn() ) );
+ ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) );
+
+ aMenuPos = aColRect.TopCenter();
+ }
+ else if ( GetSelectRowCount() > 0 )
+ {
+ ::tools::Rectangle aColRect( GetFieldRectPixel( FirstSelectedRow(), HANDLE_ID ) );
+
+ aMenuPos = aColRect.TopCenter();
+ }
+ else
+ {
+ OTableRowView::Command(rEvt);
+ return;
+ }
+ }
+
+ // Show the Context menu
+ if( !IsReadOnly() )
+ {
+ sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(aMenuPos.X()));
+ sal_Int32 nRow = GetRowAtYPosPixel(aMenuPos.Y());
+
+ if ( HANDLE_ID != nColId )
+ {
+ if ( nRow < 0 && nColId != BROWSER_INVALIDID )
+ { // hit the header
+ if ( 3 != nColId )
+ { // 3 would mean the last column, and this last column is auto-sized
+ if ( !IsColumnSelected( nColId ) )
+ SelectColumnId( nColId );
+
+ ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ xContextMenu->remove("delete");
+ xContextMenu->remove("separator");
+ if (xContextMenu->popup_at_rect(pPopupParent, aRect) == "width")
+ adjustBrowseBoxColumnWidth( this, nColId );
+ }
+ }
+ }
+ else
+ {
+ ::tools::Rectangle aRect(aMenuPos, Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+
+ if (!IsCutAllowed())
+ xContextMenu->remove("cut");
+ if (!IsCopyAllowed())
+ xContextMenu->remove("copy");
+ if (!IsPasteAllowed())
+ xContextMenu->remove("paste");
+ if (!IsDeleteAllowed())
+ xContextMenu->remove("delete");
+ if (!IsPrimaryKeyAllowed())
+ xContextMenu->remove("primarykey");
+ if (!IsInsertNewAllowed(nRow))
+ xContextMenu->remove("insert");
+ xContextMenu->set_active("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey());
+
+ if( SetDataPtr(m_nDataPos) )
+ pDescrWin->SaveData( pActRow->GetActFieldDescr() );
+
+ // All actions which change the number of rows must be run asynchronously
+ // otherwise there may be problems between the Context menu and the Browser
+ m_nDataPos = GetCurRow();
+ OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
+ if (sIdent == "cut")
+ cut();
+ else if (sIdent == "copy")
+ copy();
+ else if (sIdent == "paste")
+ paste();
+ else if (sIdent == "delete")
+ {
+ if( nDeleteEvent )
+ Application::RemoveUserEvent( nDeleteEvent );
+ nDeleteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedDelete), nullptr, true );
+ }
+ else if (sIdent == "insert")
+ {
+ if( nInsNewRowsEvent )
+ Application::RemoveUserEvent( nInsNewRowsEvent );
+ nInsNewRowsEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedInsNewRows), nullptr, true );
+ }
+ else if (sIdent == "primarykey")
+ {
+ SetPrimaryKey( !IsPrimaryKey() );
+ }
+ }
+ }
+ }
+ break;
+ default:
+ OTableRowView::Command(rEvt);
+ }
+
+}
+
+IMPL_LINK_NOARG( OTableEditorCtrl, DelayedCut, void*, void )
+{
+ nCutEvent = nullptr;
+ OTableRowView::cut();
+}
+
+IMPL_LINK_NOARG( OTableEditorCtrl, DelayedPaste, void*, void )
+{
+ nPasteEvent = nullptr;
+
+ sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition();
+ if ( !GetView()->getController().getTable().is() )
+ nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : GetCurRow();
+
+ if (!IsInsertNewAllowed(nPastePosition))
+ { // Insertion is not allowed, only appending, so test if there are full cells after the PastePosition
+
+ auto aIter = std::find_if(m_pRowList->rbegin(), m_pRowList->rend(), [](const std::shared_ptr<OTableRow>& rxRow) {
+ return rxRow && rxRow->GetActFieldDescr() && !rxRow->GetActFieldDescr()->GetName().isEmpty(); });
+ auto nFreeFromPos = static_cast<sal_Int32>(std::distance(aIter, m_pRowList->rend())); // from here on there are only empty rows
+ if (nPastePosition < nFreeFromPos) // if at least one PastePosition is full, go right to the end
+ nPastePosition = nFreeFromPos;
+ }
+
+ OTableRowView::Paste( nPastePosition );
+ SetNoSelection();
+ GoToRow( nPastePosition );
+}
+
+IMPL_LINK_NOARG( OTableEditorCtrl, DelayedDelete, void*, void )
+{
+ nDeleteEvent = nullptr;
+ DeleteRows();
+}
+
+IMPL_LINK_NOARG( OTableEditorCtrl, DelayedInsNewRows, void*, void )
+{
+ nInsNewRowsEvent = nullptr;
+ sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition();
+ if ( !GetView()->getController().getTable().is() )
+ nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : m_nDataPos;
+
+ InsertNewRows( nPastePosition );
+ SetNoSelection();
+ GoToRow( nPastePosition );
+}
+
+void OTableEditorCtrl::AdjustFieldDescription(OFieldDescription* _pFieldDesc,
+ MultiSelection& _rMultiSel,
+ sal_Int32 _nPos,
+ bool _bSet,
+ bool _bPrimaryKey)
+{
+ _pFieldDesc->SetPrimaryKey( _bPrimaryKey );
+ if(!_bSet && _pFieldDesc->getTypeInfo()->bNullable)
+ {
+ _pFieldDesc->SetIsNullable(ColumnValue::NO_NULLS);
+ _pFieldDesc->SetControlDefault(Any());
+ }
+ if ( _pFieldDesc->IsAutoIncrement() && !_bPrimaryKey )
+ {
+ OTableController& rController = GetView()->getController();
+ if ( rController.isAutoIncrementPrimaryKey() )
+ {
+ _pFieldDesc->SetAutoIncrement(false);
+ }
+ }
+ // update field description
+ pDescrWin->DisplayData(_pFieldDesc);
+
+ _rMultiSel.Insert( _nPos );
+ _rMultiSel.Select( _nPos );
+}
+
+void OTableEditorCtrl::SetPrimaryKey( bool bSet )
+{
+ // Delete any existing Primary Keys
+ MultiSelection aDeletedPrimKeys;
+ aDeletedPrimKeys.SetTotalRange( Range(0,GetRowCount()) );
+
+ sal_Int32 nRow = 0;
+ for (auto const& row : *m_pRowList)
+ {
+ OFieldDescription* pFieldDescr = row->GetActFieldDescr();
+ if( pFieldDescr && row->IsPrimaryKey() && (!bSet || !IsRowSelected(nRow)) )
+ {
+ AdjustFieldDescription(pFieldDescr,aDeletedPrimKeys,nRow,bSet,false);
+ }
+ ++nRow;
+ }
+
+ // Set the primary keys of the marked rows
+ MultiSelection aInsertedPrimKeys;
+ aInsertedPrimKeys.SetTotalRange( Range(0,GetRowCount()) );
+ if( bSet )
+ {
+ tools::Long nIndex = FirstSelectedRow();
+ while( nIndex != SFX_ENDOFSELECTION )
+ {
+ // Set the key
+ std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nIndex];
+ OFieldDescription* pFieldDescr = pRow->GetActFieldDescr();
+ if(pFieldDescr)
+ AdjustFieldDescription(pFieldDescr,aInsertedPrimKeys,nIndex,false,true);
+
+ nIndex = NextSelectedRow();
+ }
+ }
+
+ GetUndoManager().AddUndoAction( std::make_unique<OPrimKeyUndoAct>(this, aDeletedPrimKeys, aInsertedPrimKeys) );
+
+ // Invalidate the handle-columns
+ InvalidateHandleColumn();
+
+ // Set the TableDocSh's ModifyFlag
+ GetView()->getController().setModified( true );
+ InvalidateFeatures();
+}
+
+bool OTableEditorCtrl::IsPrimaryKey()
+{
+ // Are all marked fields part of the Primary Key ?
+ tools::Long nPrimaryKeys = 0;
+ sal_Int32 nRow=0;
+ for (auto const& row : *m_pRowList)
+ {
+ if( IsRowSelected(nRow) && !row->IsPrimaryKey() )
+ return false;
+ if( row->IsPrimaryKey() )
+ ++nPrimaryKeys;
+ ++nRow;
+ }
+
+ // Are there any unselected fields that are part of the Key ?
+ return GetSelectRowCount() == nPrimaryKeys;
+}
+
+void OTableEditorCtrl::SwitchType( const TOTypeInfoSP& _pType )
+{
+ // if there is no assigned field name
+ sal_Int32 nRow(GetCurRow());
+ OFieldDescription* pActFieldDescr = GetFieldDescr( nRow );
+ if( pActFieldDescr )
+ // Store the old description
+ pDescrWin->SaveData( pActFieldDescr );
+
+ if ( nRow < 0 || o3tl::make_unsigned(nRow) > m_pRowList->size() )
+ return;
+ // Show the new description
+ std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nRow];
+ pRow->SetFieldType( _pType, true );
+ if ( _pType )
+ {
+ weld::ComboBox& rTypeList = pTypeCell->get_widget();
+ const sal_Int32 nCurrentlySelected = rTypeList.get_active();
+
+ if ( ( nCurrentlySelected == -1 )
+ || ( GetView()->getController().getTypeInfo( nCurrentlySelected ) != _pType )
+ )
+ {
+ sal_Int32 nEntryPos = 0;
+ const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo();
+ for (auto const& elem : rTypeInfo)
+ {
+ if(elem.second == _pType)
+ break;
+ ++nEntryPos;
+ }
+ if (nEntryPos < rTypeList.get_count())
+ rTypeList.set_active(nEntryPos);
+ }
+ }
+
+ pActFieldDescr = pRow->GetActFieldDescr();
+ if (pActFieldDescr != nullptr && !pActFieldDescr->GetFormatKey())
+ {
+ sal_Int32 nFormatKey = ::dbtools::getDefaultNumberFormat( pActFieldDescr->GetType(),
+ pActFieldDescr->GetScale(),
+ pActFieldDescr->IsCurrency(),
+ Reference< XNumberFormatTypes>(GetView()->getController().getNumberFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY),
+ GetView()->getLocale());
+
+ pActFieldDescr->SetFormatKey(nFormatKey);
+ }
+
+ pDescrWin->DisplayData( pActFieldDescr );
+}
+
+OTableDesignView* OTableEditorCtrl::GetView() const
+{
+ return m_pView;
+}
+
+void OTableEditorCtrl::DeactivateCell(bool bUpdate)
+{
+ OTableRowView::DeactivateCell(bUpdate);
+ // now we have to deactivate the field description
+ sal_Int32 nRow(GetCurRow());
+ if (pDescrWin)
+ pDescrWin->SetReadOnly(bReadOnly || !SetDataPtr(nRow) || GetActRow()->IsReadOnly());
+}
+
+bool OTableEditorCtrl::PreNotify( NotifyEvent& rNEvt )
+{
+ if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
+ {
+ if( pHelpTextCell && pHelpTextCell->HasChildPathFocus() )
+ m_eChildFocus = HELPTEXT;
+ else if( pDescrCell && pDescrCell->HasChildPathFocus() )
+ m_eChildFocus = DESCRIPTION;
+ else if(pNameCell && pNameCell->HasChildPathFocus() )
+ m_eChildFocus = NAME;
+ else
+ m_eChildFocus = ROW;
+ }
+
+ return OTableRowView::PreNotify(rNEvt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TEditControl.hxx b/dbaccess/source/ui/tabledesign/TEditControl.hxx
new file mode 100644
index 000000000..7b1d46781
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TEditControl.hxx
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <TableDesignControl.hxx>
+#include <TableDesignView.hxx>
+#include "TableFieldDescWin.hxx"
+#include <TableRow.hxx>
+#include <TypeInfo.hxx>
+
+class Edit;
+class SfxUndoManager;
+namespace dbaui
+{
+ class OSQLNameEditControl;
+
+ class OTableEditorCtrl : public OTableRowView
+ {
+ enum ChildFocusState
+ {
+ HELPTEXT,
+ DESCRIPTION,
+ NAME,
+ ROW,
+ NONE
+ };
+
+ std::vector< std::shared_ptr<OTableRow> >* m_pRowList;
+
+ VclPtr<OTableDesignView> m_pView;
+ VclPtr<OSQLNameEditControl> pNameCell;
+ VclPtr<::svt::ListBoxControl> pTypeCell;
+ VclPtr<::svt::EditControl> pHelpTextCell;
+ VclPtr<::svt::EditControl> pDescrCell;
+ OTableFieldDescWin* pDescrWin; // properties of one column
+
+ std::shared_ptr<OTableRow> pActRow;
+
+ ImplSVEvent * nCutEvent;
+ ImplSVEvent * nPasteEvent;
+ ImplSVEvent * nDeleteEvent;
+ ImplSVEvent * nInsNewRowsEvent;
+ ImplSVEvent * nInvalidateTypeEvent;
+ ChildFocusState m_eChildFocus;
+
+ tools::Long nOldDataPos;
+
+ bool bReadOnly;
+
+ // helper class
+ class ClipboardInvalidator final
+ {
+ private:
+ AutoTimer m_aInvalidateTimer;
+ VclPtr<OTableEditorCtrl> m_pOwner;
+
+ public:
+ explicit ClipboardInvalidator(OTableEditorCtrl*);
+ ~ClipboardInvalidator();
+ void Stop();
+
+ private:
+ DECL_LINK(OnInvalidate, Timer*, void);
+ };
+
+ friend class OTableEditorCtrl::ClipboardInvalidator;
+
+ ClipboardInvalidator m_aInvalidate;
+
+ protected:
+ virtual void Command( const CommandEvent& rEvt ) override;
+ virtual bool SeekRow(sal_Int32 nRow) override;
+ virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect,
+ sal_uInt16 nColumnId ) const override;
+
+ virtual void CursorMoved() override;
+ virtual RowStatus GetRowStatus(sal_Int32 nRow) const override;
+
+ virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override;
+ virtual void InitController(::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol) override;
+
+ virtual void CellModified() override;
+ virtual bool SaveModified() override; // is called before changing a cell (false prevents change)
+
+ virtual OUString GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const override;
+ virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override;
+
+ virtual void CopyRows() override;
+ virtual void InsertRows( sal_Int32 nRow ) override;
+ virtual void DeleteRows() override;
+ virtual void InsertNewRows( sal_Int32 nRow ) override;
+
+ virtual bool IsPrimaryKeyAllowed() override;
+ virtual bool IsInsertNewAllowed( sal_Int32 nRow ) override;
+ virtual bool IsDeleteAllowed() override;
+
+ void ClearModified();
+
+ void SetPrimaryKey( bool bSet );
+ bool IsPrimaryKey();
+
+ public:
+ explicit OTableEditorCtrl(vcl::Window* pParentWin, OTableDesignView* pView);
+ virtual ~OTableEditorCtrl() override;
+ virtual void dispose() override;
+ virtual bool CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol) override;
+ SfxUndoManager& GetUndoManager() const;
+
+ void SetDescrWin( OTableFieldDescWin* pWin )
+ {
+ pDescrWin = pWin;
+ if (pDescrWin && pActRow)
+ pDescrWin->DisplayData(pActRow->GetActFieldDescr());
+ }
+ void SaveCurRow();
+ void SwitchType( const TOTypeInfoSP& _pType );
+
+ /// force displaying of the given row
+ void DisplayData( sal_Int32 nRow );
+
+ virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) override;
+ virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rSaveData ) override;
+ virtual css::uno::Any GetCellData( sal_Int32 nRow, sal_uInt16 nColId ) override;
+ virtual void SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText ) override;
+
+ virtual OTableDesignView* GetView() const override;
+
+ std::vector< std::shared_ptr<OTableRow> >* GetRowList(){ return m_pRowList; }
+
+ const std::shared_ptr<OTableRow>& GetActRow() const { return pActRow; }
+ void CellModified( sal_Int32 nRow, sal_uInt16 nColId );
+ void SetReadOnly( bool bRead );
+
+ virtual void Init() override;
+ virtual void DeactivateCell(bool bUpdate = true) override;
+
+ bool IsCutAllowed();
+ bool IsCopyAllowed();
+ bool IsPasteAllowed() const;
+ bool IsReadOnly() const { return bReadOnly;}
+ OFieldDescription* GetFieldDescr( sal_Int32 nRow );
+
+ // Window overrides
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+
+ // IClipboardTest
+ virtual bool isCutAllowed() override { return IsCutAllowed(); }
+ virtual bool isCopyAllowed() override { return IsCopyAllowed(); }
+ virtual bool isPasteAllowed() override { return IsPasteAllowed(); }
+
+ virtual void cut() override;
+ virtual void copy() override;
+ virtual void paste() override;
+
+ private:
+ DECL_LINK( DelayedCut, void*, void );
+ DECL_LINK( DelayedPaste, void*, void );
+ DECL_LINK( DelayedDelete, void*, void );
+ DECL_LINK( DelayedInsNewRows, void*, void );
+ DECL_LINK( InvalidateFieldType, void*, void );
+
+ void InitCellController();
+ sal_Int32 HasFieldName( std::u16string_view rFieldName );
+ OUString GenerateName( const OUString& rName );
+ bool SetDataPtr( sal_Int32 nRow );
+
+ void SaveData(sal_Int32 nRow, sal_uInt16 nColumnId);
+ /** AdjustFieldDescription set the needed values for the description
+ @param _pFieldDesc the field description where to set the values
+ @param _rMultiSel contains the positions which changed for undo/redo
+ @param _nPos the current position
+ @param _bSet should a key be set
+ @param _bPrimaryKey which value should the pkey have
+ */
+ void AdjustFieldDescription( OFieldDescription* _pFieldDesc,
+ MultiSelection& _rMultiSel,
+ sal_Int32 _nPos,
+ bool _bSet,
+ bool _bPrimaryKey);
+ /** InvalidateFeatures invalidates the slots SID_UNDO | SID_REDO | SID_SAVEDOC
+ */
+ void InvalidateFeatures();
+
+ void resetType();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableController.cxx b/dbaccess/source/ui/tabledesign/TableController.cxx
new file mode 100644
index 000000000..07fe30a91
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableController.cxx
@@ -0,0 +1,1495 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <FieldDescriptions.hxx>
+#include "TEditControl.hxx"
+#include <TableController.hxx>
+#include <TableDesignView.hxx>
+#include <TableRow.hxx>
+#include <TypeInfo.hxx>
+#include <UITools.hxx>
+#include <browserids.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <defaultobjectnamecheck.hxx>
+#include <dlgsave.hxx>
+#include <indexdialog.hxx>
+#include <sqlmessage.hxx>
+
+#include <com/sun/star/frame/XTitleChangeListener.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/XAlterTable.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <algorithm>
+#include <functional>
+#include <set>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OTableDesign_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OTableController(context));
+}
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::util;
+using namespace ::dbtools;
+using namespace ::dbaui;
+using namespace ::comphelper;
+
+// number of columns when creating it from scratch
+#define NEWCOLS 128
+
+namespace
+{
+ void dropTable(const Reference<XNameAccess>& _rxTable,const OUString& _sTableName)
+ {
+ if ( _rxTable->hasByName(_sTableName) )
+ {
+ Reference<XDrop> xNameCont(_rxTable,UNO_QUERY);
+ OSL_ENSURE(xNameCont.is(),"No drop interface for tables!");
+ if ( xNameCont.is() )
+ xNameCont->dropByName(_sTableName);
+ }
+ }
+}
+
+OUString SAL_CALL OTableController::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.OTableDesign";
+}
+
+Sequence< OUString> OTableController::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.TableDesign" };
+}
+
+OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM)
+ ,m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES))
+ ,m_bAllowAutoIncrementValue(false)
+ ,m_bNew(true)
+{
+
+ InvalidateAll();
+ m_pTypeInfo = std::make_shared<OTypeInfo>();
+ m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';');
+}
+
+OTableController::~OTableController()
+{
+ m_aTypeInfoIndex.clear();
+ m_aTypeInfo.clear();
+
+}
+
+void OTableController::startTableListening()
+{
+ Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast<XModifyListener*>(this));
+}
+
+void OTableController::stopTableListening()
+{
+ Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(static_cast<XModifyListener*>(this));
+}
+
+void OTableController::disposing()
+{
+ OTableController_BASE::disposing();
+ clearView();
+
+ m_vRowList.clear();
+}
+
+FeatureState OTableController::GetState(sal_uInt16 _nId) const
+{
+ FeatureState aReturn;
+ // disabled automatically
+
+ switch (_nId)
+ {
+ case ID_BROWSER_CLOSE:
+ aReturn.bEnabled = true;
+ break;
+ case ID_BROWSER_EDITDOC:
+ aReturn.bChecked = isEditable();
+ aReturn.bEnabled = true;
+ break;
+ case ID_BROWSER_SAVEDOC:
+ aReturn.bEnabled = isEditable() && std::any_of(m_vRowList.begin(),m_vRowList.end(),std::mem_fn(&OTableRow::isValid));
+ break;
+ case ID_BROWSER_SAVEASDOC:
+ aReturn.bEnabled = isConnected() && isEditable();
+ if ( aReturn.bEnabled )
+ {
+ aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(),
+ std::mem_fn(&OTableRow::isValid));
+ }
+ break;
+
+ case ID_BROWSER_CUT:
+ aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed();
+ break;
+ case ID_BROWSER_COPY:
+ aReturn.bEnabled = getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed();
+ break;
+ case ID_BROWSER_PASTE:
+ aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed();
+ break;
+ case SID_INDEXDESIGN:
+ aReturn.bEnabled =
+ ( ( ((!m_bNew && impl_isModified()) || impl_isModified())
+ || Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is()
+ )
+ && isConnected()
+ );
+ if ( aReturn.bEnabled )
+ {
+ aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(),
+ std::mem_fn(&OTableRow::isValid));
+ }
+ break;
+ default:
+ aReturn = OTableController_BASE::GetState(_nId);
+ }
+ return aReturn;
+}
+
+void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
+{
+ switch(_nId)
+ {
+ case ID_BROWSER_EDITDOC:
+ setEditable(!isEditable());
+ static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable());
+ InvalidateFeature(ID_BROWSER_SAVEDOC);
+ InvalidateFeature(ID_BROWSER_PASTE);
+ InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
+ break;
+ case ID_BROWSER_SAVEASDOC:
+ doSaveDoc(true);
+ break;
+ case ID_BROWSER_SAVEDOC:
+ static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow();
+ doSaveDoc(false);
+ break;
+ case ID_BROWSER_CUT:
+ static_cast<OTableDesignView*>(getView())->cut();
+ break;
+ case ID_BROWSER_COPY:
+ static_cast<OTableDesignView*>(getView())->copy();
+ break;
+ case ID_BROWSER_PASTE:
+ static_cast<OTableDesignView*>(getView())->paste();
+ break;
+ case SID_INDEXDESIGN:
+ doEditIndexes();
+ break;
+ default:
+ OTableController_BASE::Execute(_nId,aArgs);
+ }
+ InvalidateFeature(_nId);
+}
+
+bool OTableController::doSaveDoc(bool _bSaveAs)
+{
+ if (!isConnected())
+ reconnect(true); // ask the user for a new connection
+ Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
+
+ if (!xTablesSup.is())
+ {
+ OUString aMessage(DBA_RES(STR_TABLEDESIGN_CONNECTION_MISSING));
+ OSQLWarningBox aWarning(getFrameWeld(), aMessage);
+ aWarning.run();
+ return false;
+ }
+
+ // check if a column exists
+ // TODO
+
+ Reference<XNameAccess> xTables;
+ OUString sCatalog, sSchema;
+
+ bool bNew = m_sName.isEmpty();
+ bNew = bNew || m_bNew || _bSaveAs;
+
+ try
+ {
+ xTables = xTablesSup->getTables();
+ OSL_ENSURE(xTables.is(),"The tables can't be null!");
+ bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName));
+
+ // first we need a name for our query so ask the user
+ if(bNew)
+ {
+ OUString aName = DBA_RES(STR_TBL_TITLE);
+ OUString aDefaultName = aName.getToken(0,' ');
+ aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName);
+
+ DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE );
+ OSaveAsDlg aDlg(getFrameWeld(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker, SADFlags::NONE);
+ if (aDlg.run() != RET_OK)
+ return false;
+
+ m_sName = aDlg.getName();
+ sCatalog = aDlg.getCatalog();
+ sSchema = aDlg.getSchema();
+ }
+
+ // did we get a name
+ if(m_sName.isEmpty())
+ return false;
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("OTableController::doSaveDoc: nothing is expected to happen here!");
+ }
+
+ bool bAlter = false;
+ bool bError = false;
+ SQLExceptionInfo aInfo;
+ try
+ {
+ // check the columns for double names
+ if(!checkColumns(bNew || !xTables->hasByName(m_sName)))
+ {
+ return false;
+ }
+
+ Reference<XPropertySet> xTable;
+ if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists
+ {
+ dropTable(xTables,m_sName);
+
+ Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
+ OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!");
+ xTable = xFact->createDataDescriptor();
+ OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!");
+ // to set the name is only allowed when the query is new
+ xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog));
+ xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema));
+ xTable->setPropertyValue(PROPERTY_NAME,Any(m_sName));
+
+ // now append the columns
+ Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY);
+ appendColumns(xColSup,bNew);
+ // now append the primary key
+ Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
+ appendPrimaryKey(xKeySup,bNew);
+ }
+ // now set the properties
+ if(bNew)
+ {
+ Reference<XAppend> xAppend(xTables,UNO_QUERY);
+ OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!");
+ xAppend->appendByDescriptor(xTable);
+
+ assignTable();
+ if(!m_xTable.is()) // correct name and try again
+ {
+ // it can be that someone inserted new data for us
+ m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false );
+ assignTable();
+ }
+ // now check if our datasource has set a tablefilter and if append the new table name to it
+ ::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld()); // we are not interested in the return value
+ Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY);
+ if ( xEventListener.is() )
+ {
+ frame::TitleChangedEvent aEvent;
+ xEventListener->titleChanged(aEvent);
+ }
+ releaseNumberForComponent();
+ }
+ else if(m_xTable.is())
+ {
+ bAlter = true;
+ alterColumns();
+ }
+ reSyncRows();
+ }
+ catch(const SQLContext& e)
+ {
+ aInfo = SQLExceptionInfo(e);
+ }
+ catch(const SQLWarning& e)
+ {
+ aInfo = SQLExceptionInfo(e);
+ }
+ catch(const SQLException& e)
+ {
+ aInfo = SQLExceptionInfo(e);
+ }
+ catch(const ElementExistException& )
+ {
+ OUString sText( DBA_RES( STR_NAME_ALREADY_EXISTS ) );
+ sText = sText.replaceFirst( "#" , m_sName);
+ OSQLMessageBox aDlg(getFrameWeld(), DBA_RES( STR_ERROR_DURING_CREATION ), sText, MessBoxStyle::Ok, MessageType::Error);
+ aDlg.run();
+ bError = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ bError = true;
+ }
+
+ if ( aInfo.isValid() )
+ aInfo.prepend( DBA_RES( STR_TABLEDESIGN_SAVE_ERROR ) );
+ showError(aInfo);
+
+ if (aInfo.isValid() || bError)
+ {
+ if(!bAlter || bNew)
+ {
+ m_sName.clear();
+ stopTableListening();
+ m_xTable = nullptr;
+ }
+ }
+ return ! (aInfo.isValid() || bError);
+}
+
+void OTableController::doEditIndexes()
+{
+ // table needs to be saved before editing indexes
+ if (m_bNew || isModified())
+ {
+ std::unique_ptr<weld::MessageDialog> xAsk(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ DBA_RES(STR_QUERY_SAVE_TABLE_EDIT_INDEXES)));
+ if (RET_YES != xAsk->run())
+ return;
+
+ if (!doSaveDoc(false))
+ return;
+
+ OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?");
+ }
+
+ Reference< XNameAccess > xIndexes; // will be the keys of the table
+ Sequence< OUString > aFieldNames; // will be the column names of the table
+ try
+ {
+ // get the keys
+ Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY);
+ if (xIndexesSupp.is())
+ {
+ xIndexes = xIndexesSupp->getIndexes();
+ OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!");
+ }
+ else
+ OSL_FAIL("OTableController::doEditIndexes: should never have reached this (no indexes supplier)!");
+
+ // get the field names
+ Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY);
+ OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!");
+ if (xColSupp.is())
+ {
+ Reference< XNameAccess > xCols = xColSupp->getColumns();
+ OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!");
+ if (xCols.is())
+ aFieldNames = xCols->getElementNames();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if (!xIndexes.is())
+ return;
+
+ DbaIndexDialog aDialog(getFrameWeld(), aFieldNames, xIndexes, getConnection(), getORB());
+ if (RET_OK != aDialog.run())
+ return;
+
+}
+
+void OTableController::impl_initialize()
+{
+ try
+ {
+ OTableController_BASE::impl_initialize();
+
+ const NamedValueCollection& rArguments( getInitParams() );
+
+ rArguments.get_ensureType( PROPERTY_CURRENTTABLE, m_sName );
+
+ // read autoincrement value set in the datasource
+ ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue);
+
+ assignTable();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ try
+ {
+ ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information
+ }
+ catch(const SQLException&)
+ {
+ OSQLWarningBox aWarning(getFrameWeld(), DBA_RES( STR_NO_TYPE_INFO_AVAILABLE));
+ aWarning.run();
+ throw;
+ }
+ try
+ {
+ loadData(); // fill the column information from the table
+ getView()->initialize(); // show the windows and fill with our information
+ ClearUndoManager();
+ setModified(false); // and we are not modified yet
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+bool OTableController::Construct(vcl::Window* pParent)
+{
+ setView( VclPtr<OTableDesignView>::Create( pParent, getORB(), *this ) );
+ OTableController_BASE::Construct(pParent);
+ return true;
+}
+
+sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/)
+{
+ if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed )
+ return true;
+
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( getView() && getView()->IsInModalMode() )
+ return false;
+ if ( getView() )
+ static_cast<OTableDesignView*>(getView())->GrabFocus();
+ bool bCheck = true;
+ if ( isModified() )
+ {
+ if ( std::any_of(m_vRowList.begin(),m_vRowList.end(),
+ std::mem_fn(&OTableRow::isValid)) )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/tabledesignsavemodifieddialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("TableDesignSaveModifiedDialog"));
+ switch (xQuery->run())
+ {
+ case RET_YES:
+ Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
+ if ( isModified() )
+ bCheck = false; // when we save the table this must be false else some press cancel
+ break;
+ case RET_CANCEL:
+ bCheck = false;
+ break;
+ default:
+ break;
+ }
+ }
+ else if ( !m_bNew )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/deleteallrowsdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DeleteAllRowsDialog"));
+ switch (xQuery->run())
+ {
+ case RET_YES:
+ {
+ try
+ {
+ Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY);
+ Reference<XNameAccess> xTables = xTablesSup->getTables();
+ dropTable(xTables,m_sName);
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("OTableController::suspend: nothing is expected to happen here!");
+ }
+
+ }
+ break;
+ case RET_CANCEL:
+ bCheck = false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return bCheck;
+}
+
+void OTableController::describeSupportedFeatures()
+{
+ OSingleDocumentController::describeSupportedFeatures();
+
+ implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:NewDoc", SID_NEWDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:GetUndoStrings", SID_GETUNDOSTRINGS );
+ implDescribeSupportedFeature( ".uno:GetRedoStrings", SID_GETREDOSTRINGS );
+}
+
+void OTableController::impl_onModifyChanged()
+{
+ OSingleDocumentController::impl_onModifyChanged();
+ InvalidateFeature( SID_INDEXDESIGN );
+}
+
+void SAL_CALL OTableController::disposing( const EventObject& _rSource )
+{
+ if ( _rSource.Source == m_xTable )
+ { // some deleted our table so we have a new one
+ stopTableListening();
+ m_xTable = nullptr;
+ m_bNew = true;
+ setModified(true);
+ }
+ else
+ OTableController_BASE::disposing( _rSource );
+}
+
+void OTableController::losingConnection( )
+{
+ // let the base class do its reconnect
+ OTableController_BASE::losingConnection( );
+
+ // remove from the table
+ Reference< XComponent > xComponent(m_xTable, UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY);
+ xComponent->removeEventListener(xEvtL);
+ }
+ stopTableListening();
+ m_xTable = nullptr;
+ assignTable();
+ if(!m_xTable.is())
+ {
+ m_bNew = true;
+ setModified(true);
+ }
+ InvalidateAll();
+}
+
+TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const
+{
+ return queryTypeInfoByType(_nDataType,m_aTypeInfo);
+}
+
+void OTableController::appendColumns(Reference<XColumnsSupplier> const & _rxColSup, bool _bNew, bool _bKeyColumns)
+{
+ try
+ {
+ // now append the columns
+ OSL_ENSURE(_rxColSup.is(),"No columns supplier");
+ if(!_rxColSup.is())
+ return;
+ Reference<XNameAccess> xColumns = _rxColSup->getColumns();
+ OSL_ENSURE(xColumns.is(),"No columns");
+ Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
+
+ Reference<XAppend> xAppend(xColumns,UNO_QUERY);
+ OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
+
+ for (auto const& row : m_vRowList)
+ {
+ OSL_ENSURE(row,"OTableRow is null!");
+ OFieldDescription* pField = row->GetActFieldDescr();
+ if ( !pField || (!_bNew && row->IsReadOnly() && !_bKeyColumns) )
+ continue;
+
+ Reference<XPropertySet> xColumn;
+ if(pField->IsPrimaryKey() || !_bKeyColumns)
+ xColumn = xColumnFactory->createDataDescriptor();
+ if(xColumn.is())
+ {
+ if(!_bKeyColumns)
+ ::dbaui::setColumnProperties(xColumn,pField);
+ else
+ xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName()));
+
+ xAppend->appendByDescriptor(xColumn);
+ xColumn = nullptr;
+ // now only the settings are missing
+ if(xColumns->hasByName(pField->GetName()))
+ {
+ xColumns->getByName(pField->GetName()) >>= xColumn;
+ if(xColumn.is())
+ pField->copyColumnSettingsTo(xColumn);
+ }
+ else
+ {
+ OSL_FAIL("OTableController::appendColumns: invalid field name!");
+ }
+
+ }
+ }
+ }
+ catch(const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OTableController::appendPrimaryKey(Reference<XKeysSupplier> const & _rxSup, bool _bNew)
+{
+ if(!_rxSup.is())
+ return; // the database doesn't support keys
+
+ OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
+ Reference<XIndexAccess> xKeys = _rxSup->getKeys();
+ Reference<XPropertySet> xProp;
+ if (!xKeys.is())
+ return;
+ const sal_Int32 nCount = xKeys->getCount();
+ for(sal_Int32 i=0;i< nCount ;++i)
+ {
+ xKeys->getByIndex(i) >>= xProp;
+ sal_Int32 nKeyType = 0;
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
+ if(KeyType::PRIMARY == nKeyType)
+ {
+ return; // primary key already exists after appending a column
+ }
+ }
+ Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
+ OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
+ if ( !xKeyFactory.is() )
+ return;
+ Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
+ OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
+
+ Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
+ OSL_ENSURE(xKey.is(),"Key is null!");
+ xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY));
+
+ Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
+ if(xColSup.is())
+ {
+ appendColumns(xColSup,_bNew,true);
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ if(xColumns->hasElements())
+ xAppend->appendByDescriptor(xKey);
+ }
+}
+
+void OTableController::loadData()
+{
+ // if the data structure already exists, empty it
+ m_vRowList.clear();
+
+ std::shared_ptr<OTableRow> pTabEdRow;
+ Reference< XDatabaseMetaData> xMetaData = getMetaData( );
+ // fill data structure with data from DataDefinitionObject
+ if(m_xTable.is() && xMetaData.is())
+ {
+ Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY);
+ OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!");
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ // ReadOnly-Flag
+ // For Drop no row may be editable
+ // For Add only the empty rows may be editable
+ // For Add and Drop all rows can be edited
+ // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn();
+ bool bIsAlterAllowed = isAlterAllowed();
+
+ const Sequence<OUString> aColNames = xColumns->getElementNames();
+ for(const OUString& rColumn : aColNames)
+ {
+ Reference<XPropertySet> xColumn;
+ xColumns->getByName(rColumn) >>= xColumn;
+ sal_Int32 nType = 0;
+ sal_Int32 nScale = 0;
+ sal_Int32 nPrecision = 0;
+ sal_Int32 nNullable = 0;
+ sal_Int32 nFormatKey = 0;
+ sal_Int32 nAlign = 0;
+
+ bool bIsAutoIncrement = false, bIsCurrency = false;
+ OUString sName,sDescription,sTypeName,sHelpText;
+ Any aControlDefault;
+
+ // get the properties from the column
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName;
+ xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
+ xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement;
+ xColumn->getPropertyValue(PROPERTY_ISCURRENCY) >>= bIsCurrency;
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
+ xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
+ xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
+
+ if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT))
+ xColumn->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText;
+
+ if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
+ aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT);
+ if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY))
+ xColumn->getPropertyValue(PROPERTY_FORMATKEY) >>= nFormatKey;
+ if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN))
+ xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
+
+ pTabEdRow = std::make_shared<OTableRow>();
+ pTabEdRow->SetReadOnly(!bIsAlterAllowed);
+ // search for type
+ bool bForce;
+ TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,"x",nPrecision,nScale,bIsAutoIncrement,bForce);
+ if ( !pTypeInfo )
+ pTypeInfo = m_pTypeInfo;
+ pTabEdRow->SetFieldType( pTypeInfo, bForce );
+
+ OFieldDescription* pActFieldDescr = pTabEdRow->GetActFieldDescr();
+ OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!");
+ if ( pActFieldDescr )
+ {
+ pActFieldDescr->SetName(sName);
+ pActFieldDescr->SetFormatKey(nFormatKey);
+ pActFieldDescr->SetDescription(sDescription);
+ pActFieldDescr->SetHelpText(sHelpText);
+ pActFieldDescr->SetAutoIncrement(bIsAutoIncrement);
+ pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign));
+ pActFieldDescr->SetCurrency(bIsCurrency);
+
+ // special data
+ pActFieldDescr->SetIsNullable(nNullable);
+ pActFieldDescr->SetControlDefault(aControlDefault);
+ pActFieldDescr->SetPrecision(nPrecision);
+ pActFieldDescr->SetScale(nScale);
+ }
+ m_vRowList.push_back( pTabEdRow);
+ }
+ // fill the primary key information
+ Reference<XNameAccess> xKeyColumns = getKeyColumns();
+ if(xKeyColumns.is())
+ {
+ const Sequence<OUString> aKeyColumnNames = xKeyColumns->getElementNames();
+ for(const OUString& rKeyColumn : aKeyColumnNames)
+ {
+ for(std::shared_ptr<OTableRow> const& pRow : m_vRowList)
+ {
+ if(pRow->GetActFieldDescr()->GetName() == rKeyColumn)
+ {
+ pRow->SetPrimaryKey(true);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // fill empty rows
+
+ OTypeInfoMap::const_iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR);
+ if(aTypeIter == m_aTypeInfo.end())
+ aTypeIter = m_aTypeInfo.begin();
+
+ OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type information!");
+
+ bool bReadRow = !isAddAllowed();
+ for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ )
+ {
+ pTabEdRow = std::make_shared<OTableRow>();
+ pTabEdRow->SetReadOnly(bReadRow);
+ m_vRowList.push_back( pTabEdRow);
+ }
+}
+
+Reference<XNameAccess> OTableController::getKeyColumns() const
+{
+ return getPrimaryKeyColumns_throw(m_xTable);
+}
+
+bool OTableController::checkColumns(bool _bNew)
+{
+ bool bOk = true;
+ bool bFoundPKey = false;
+ Reference< XDatabaseMetaData > xMetaData = getMetaData( );
+ DatabaseMetaData aMetaData( getConnection() );
+
+ ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
+ std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
+ std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
+ for(;aIter != aEnd;++aIter)
+ {
+ OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr();
+ if (pFieldDesc && !pFieldDesc->GetName().isEmpty())
+ {
+ bFoundPKey |= (*aIter)->IsPrimaryKey();
+ // first check for duplicate names
+ bool bDuplicateNameFound = std::any_of(aIter+1, aEnd,
+ [&bCase, &pFieldDesc](const std::shared_ptr<OTableRow>& rxRow) {
+ OFieldDescription* pCompareDesc = rxRow->GetActFieldDescr();
+ return pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName());
+ });
+ if (bDuplicateNameFound)
+ {
+ OUString strMessage = DBA_RES(STR_TABLEDESIGN_DUPLICATE_NAME);
+ strMessage = strMessage.replaceFirst("$column$", pFieldDesc->GetName());
+ OSQLWarningBox aWarning(getFrameWeld(), strMessage);
+ aWarning.run();
+ return false;
+ }
+ }
+ }
+ if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() )
+ {
+ OUString sTitle(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD));
+ OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY));
+ OSQLMessageBox aBox(getFrameWeld(), sTitle,sMsg, MessBoxStyle::YesNoCancel | MessBoxStyle::DefaultYes);
+
+ switch (aBox.run())
+ {
+ case RET_YES:
+ {
+ auto pNewRow = std::make_shared<OTableRow>();
+ TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo);
+ if ( !pTypeInfo )
+ break;
+
+ pNewRow->SetFieldType( pTypeInfo );
+ OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr();
+
+ pActFieldDescr->SetAutoIncrement(false);
+ pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
+
+ pActFieldDescr->SetName( createUniqueName("ID" ));
+ pActFieldDescr->SetPrimaryKey( true );
+ m_vRowList.insert(m_vRowList.begin(),pNewRow);
+
+ static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate();
+ static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0);
+ }
+ break;
+ case RET_CANCEL:
+ bOk = false;
+ break;
+ }
+ }
+ return bOk;
+}
+
+void OTableController::alterColumns()
+{
+ Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW);
+
+ Reference<XNameAccess> xColumns = xColSup->getColumns();
+ Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW);
+ OSL_ENSURE(xColumns.is(),"No columns");
+ if ( !xColumns.is() )
+ return;
+ Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null
+
+ sal_Int32 nColumnCount = xIdxColumns->getCount();
+ Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null
+ Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null
+ Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null
+
+ bool bReload = false; // refresh the data
+
+ // contains all columns names which are already handled those which are not in the list will be deleted
+ Reference< XDatabaseMetaData> xMetaData = getMetaData( );
+
+ std::set<OUString, comphelper::UStringMixLess> aColumns(
+ comphelper::UStringMixLess(
+ !xMetaData.is()
+ || xMetaData->supportsMixedCaseQuotedIdentifiers()));
+ std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin();
+ std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end();
+ // first look for columns where something other than the name changed
+ for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos)
+ {
+ OSL_ENSURE(*aIter,"OTableRow is null!");
+ OFieldDescription* pField = (*aIter)->GetActFieldDescr();
+ if ( !pField )
+ continue;
+ if ( (*aIter)->IsReadOnly() )
+ {
+ aColumns.insert(pField->GetName());
+ continue;
+ }
+
+ Reference<XPropertySet> xColumn;
+ if ( xColumns->hasByName(pField->GetName()) )
+ {
+ aColumns.insert(pField->GetName());
+ xColumns->getByName(pField->GetName()) >>= xColumn;
+ OSL_ENSURE(xColumn.is(),"Column is null!");
+
+ sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0;
+ bool bAutoIncrement = false;
+ OUString sTypeName,sDescription;
+
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
+ xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
+ xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
+ xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement;
+ xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription;
+
+ try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "no TypeName property?!" );
+ // since this is a last minute fix for #i41785#, I want to be on the safe side,
+ // and catch errors here as early as possible (instead of the whole process of altering
+ // the columns failing)
+ // Normally, sdbcx::Column objects are expected to have a TypeName property
+ }
+
+ // check if something changed
+ if((nType != pField->GetType() ||
+ sTypeName != pField->GetTypeName() ||
+ (nPrecision != pField->GetPrecision() && nPrecision ) ||
+ nScale != pField->GetScale() ||
+ nNullable != pField->GetIsNullable() ||
+ sDescription != pField->GetDescription() ||
+ bAutoIncrement != pField->IsAutoIncrement())&&
+ xColumnFactory.is())
+ {
+ Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor();
+ ::dbaui::setColumnProperties(xNewColumn,pField);
+ // first try to alter the column
+ bool bNotOk = false;
+ try
+ {
+ // first try if we can alter the column
+ if(xAlter.is())
+ xAlter->alterColumnByName(pField->GetName(),xNewColumn);
+ }
+ catch(const SQLException&)
+ {
+ if(xDrop.is() && xAppend.is())
+ {
+ OUString aMessage( DBA_RES( STR_TABLEDESIGN_ALTER_ERROR ) );
+ aMessage = aMessage.replaceFirst( "$column$", pField->GetName() );
+
+ SQLExceptionInfo aError( ::cppu::getCaughtException() );
+ OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes , &aError);
+ bNotOk = aMsg.run() == RET_YES;
+ }
+ else
+ throw;
+ }
+ // if something went wrong or we can't alter columns
+ // drop and append a new one
+ if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is())
+ {
+ xDrop->dropByName(pField->GetName());
+ try
+ {
+ xAppend->appendByDescriptor(xNewColumn);
+ }
+ catch(const SQLException&)
+ { // an error occurred so we try to reactivate the old one
+ xAppend->appendByDescriptor(xColumn);
+ throw;
+ }
+ }
+ // exceptions are caught outside
+ xNewColumn = nullptr;
+ if(xColumns->hasByName(pField->GetName()))
+ xColumns->getByName(pField->GetName()) >>= xColumn;
+ bReload = true;
+ }
+
+ }
+ else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount)
+ { // we can't find the column so we could try it with the index before we drop and append a new column
+ try
+ {
+ Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor();
+ ::dbaui::setColumnProperties(xNewColumn,pField);
+ xAlter->alterColumnByIndex(nPos,xNewColumn);
+ if(xColumns->hasByName(pField->GetName()))
+ { // ask for the append by name
+ aColumns.insert(pField->GetName());
+ xColumns->getByName(pField->GetName()) >>= xColumn;
+ if(xColumn.is())
+ pField->copyColumnSettingsTo(xColumn);
+ }
+ else
+ {
+ OSL_FAIL("OTableController::alterColumns: invalid column (2)!");
+ }
+ }
+ catch(const SQLException&)
+ { // we couldn't alter the column so we have to add new columns
+ SQLExceptionInfo aError( ::cppu::getCaughtException() );
+ bReload = true;
+ if(xDrop.is() && xAppend.is())
+ {
+ OUString aMessage(DBA_RES(STR_TABLEDESIGN_ALTER_ERROR));
+ aMessage = aMessage.replaceFirst("$column$",pField->GetName());
+ OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, &aError);
+ if (aMsg.run() != RET_YES)
+ {
+ Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW);
+ OUString sName;
+ xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ aColumns.insert(sName);
+ aColumns.insert(pField->GetName());
+ continue;
+ }
+ }
+ else
+ throw;
+ }
+ }
+ else
+ bReload = true;
+ }
+ // alter column settings
+
+ // first look for columns where something other than the name changed
+ for (auto const& row : m_vRowList)
+ {
+ OSL_ENSURE(row,"OTableRow is null!");
+ OFieldDescription* pField = row->GetActFieldDescr();
+ if ( !pField )
+ continue;
+ if ( row->IsReadOnly() )
+ {
+ aColumns.insert(pField->GetName());
+ continue;
+ }
+
+ Reference<XPropertySet> xColumn;
+ if ( xColumns->hasByName(pField->GetName()) )
+ {
+ xColumns->getByName(pField->GetName()) >>= xColumn;
+ Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo();
+ if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) )
+ xColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(pField->GetHelpText()));
+
+ if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
+ xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault());
+ if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY))
+ xColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(pField->GetFormatKey()));
+ if(xInfo->hasPropertyByName(PROPERTY_ALIGN))
+ xColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(pField->GetHorJustify())));
+ }
+ }
+ // second drop all columns which could be found by name
+ Reference<XNameAccess> xKeyColumns = getKeyColumns();
+ // now we have to look for the columns who could be deleted
+ if ( xDrop.is() )
+ {
+ const Sequence<OUString> aColNames = xColumns->getElementNames();
+ for(const OUString& rColumnName : aColNames)
+ {
+ if(aColumns.find(rColumnName) == aColumns.end()) // found a column to delete
+ {
+ if(xKeyColumns.is() && xKeyColumns->hasByName(rColumnName)) // check if this column is a member of the primary key
+ {
+ OUString aMsgT(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN));
+ aMsgT = aMsgT.replaceFirst("$column$",rColumnName);
+ OUString aTitle(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE));
+ OSQLMessageBox aMsg(getFrameWeld(), aTitle, aMsgT, MessBoxStyle::YesNo| MessBoxStyle::DefaultYes);
+ if (aMsg.run() == RET_YES)
+ {
+ xKeyColumns = nullptr;
+ dropPrimaryKey();
+ }
+ else
+ {
+ bReload = true;
+ continue;
+ }
+ }
+ try
+ {
+ xDrop->dropByName(rColumnName);
+ }
+ catch (const SQLException&)
+ {
+ OUString sError( DBA_RES( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) );
+ sError = sError.replaceFirst( "$column$", rColumnName );
+
+ SQLException aNewException;
+ aNewException.Message = sError;
+ aNewException.SQLState = "S1000";
+ aNewException.NextException = ::cppu::getCaughtException();
+
+ throw aNewException;
+ }
+ }
+ }
+ }
+
+ // third append the new columns
+ for(const auto& rxRow : m_vRowList)
+ {
+ OSL_ENSURE(rxRow,"OTableRow is null!");
+ OFieldDescription* pField = rxRow->GetActFieldDescr();
+ if ( !pField || rxRow->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() )
+ continue;
+
+ Reference<XPropertySet> xColumn;
+ if(!xColumns->hasByName(pField->GetName()))
+ {
+ if(xColumnFactory.is() && xAppend.is())
+ {// column not found by its name so we assume it is new
+ // Column is new
+ xColumn = xColumnFactory->createDataDescriptor();
+ ::dbaui::setColumnProperties(xColumn,pField);
+ xAppend->appendByDescriptor(xColumn);
+ if(xColumns->hasByName(pField->GetName()))
+ { // ask for the append by name
+ aColumns.insert(pField->GetName());
+ xColumns->getByName(pField->GetName()) >>= xColumn;
+ if(xColumn.is())
+ pField->copyColumnSettingsTo(xColumn);
+ }
+ else
+ {
+ OSL_FAIL("OTableController::alterColumns: invalid column!");
+ }
+ }
+ }
+ }
+
+ // check if we have to do something with the primary key
+ bool bNeedDropKey = false;
+ bool bNeedAppendKey = false;
+ if ( xKeyColumns.is() )
+ {
+ for(const auto& rxRow : m_vRowList)
+ {
+ OSL_ENSURE(rxRow,"OTableRow is null!");
+ OFieldDescription* pField = rxRow->GetActFieldDescr();
+ if ( !pField )
+ continue;
+
+ if ( pField->IsPrimaryKey()
+ && !xKeyColumns->hasByName( pField->GetName() )
+ )
+ { // new primary key column inserted which isn't already in the columns selection
+ bNeedDropKey = bNeedAppendKey = true;
+ break;
+ }
+ else if ( !pField->IsPrimaryKey()
+ && xKeyColumns->hasByName( pField->GetName() )
+ )
+ { // found a column which currently is in the primary key, but is marked not to be anymore
+ bNeedDropKey = bNeedAppendKey = true;
+ break;
+ }
+ }
+ }
+ else
+ { // no primary key available so we check if we should create one
+ bNeedAppendKey = true;
+ }
+
+ if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().hasElements() )
+ dropPrimaryKey();
+
+ if ( bNeedAppendKey )
+ {
+ Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY );
+ appendPrimaryKey( xKeySup ,false);
+ }
+
+ reSyncRows();
+
+ if ( bReload )
+ reload();
+}
+
+void OTableController::dropPrimaryKey()
+{
+ SQLExceptionInfo aInfo;
+ try
+ {
+ Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xKeys;
+ if(xKeySup.is())
+ xKeys = xKeySup->getKeys();
+
+ if(xKeys.is())
+ {
+ Reference<XPropertySet> xProp;
+ for(sal_Int32 i=0;i< xKeys->getCount();++i)
+ {
+ xProp.set(xKeys->getByIndex(i),UNO_QUERY);
+ sal_Int32 nKeyType = 0;
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
+ if(KeyType::PRIMARY == nKeyType)
+ {
+ Reference<XDrop> xDrop(xKeys,UNO_QUERY);
+ xDrop->dropByIndex(i); // delete the key
+ break;
+ }
+ }
+ }
+ }
+ catch(const SQLContext& e)
+ {
+ aInfo = SQLExceptionInfo(e);
+ }
+ catch(const SQLWarning& e)
+ {
+ aInfo = SQLExceptionInfo(e);
+ }
+ catch(const SQLException& e)
+ {
+ aInfo = SQLExceptionInfo(e);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ showError(aInfo);
+}
+
+void OTableController::assignTable()
+{
+ // get the table
+ if(m_sName.isEmpty())
+ return;
+
+ Reference<XNameAccess> xNameAccess;
+ Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
+ if(!xSup.is())
+ return;
+
+ xNameAccess = xSup->getTables();
+ OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!");
+
+ if(!xNameAccess->hasByName(m_sName))
+ return;
+
+ Reference<XPropertySet> xProp(xNameAccess->getByName(m_sName), css::uno::UNO_QUERY);
+ if (!xProp.is())
+ return;
+
+ m_xTable = xProp;
+ startTableListening();
+
+ // check if we set the table editable
+ Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData();
+ setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) );
+ if(!isEditable())
+ {
+ for( const auto& rTableRow : m_vRowList )
+ {
+ rTableRow->SetReadOnly();
+ }
+ }
+ m_bNew = false;
+ // be notified when the table is in disposing
+ InvalidateAll();
+}
+
+bool OTableController::isAddAllowed() const
+{
+ Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
+ bool bAddAllowed = !m_xTable.is();
+ if(xColsSup.is())
+ bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is();
+
+ try
+ {
+ Reference< XDatabaseMetaData > xMetaData = getMetaData( );
+ bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn());
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ bAddAllowed = false;
+ }
+
+ return bAddAllowed;
+}
+
+bool OTableController::isDropAllowed() const
+{
+ Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY);
+ bool bDropAllowed = !m_xTable.is();
+ if(xColsSup.is())
+ {
+ Reference<XNameAccess> xNameAccess = xColsSup->getColumns();
+ bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements();
+ }
+
+ Reference< XDatabaseMetaData> xMetaData = getMetaData( );
+ bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn());
+
+ return bDropAllowed;
+}
+
+bool OTableController::isAlterAllowed() const
+{
+ bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is());
+ return bAllowed;
+}
+
+void OTableController::reSyncRows()
+{
+ bool bAlterAllowed = isAlterAllowed();
+ bool bAddAllowed = isAddAllowed();
+ for (auto const& row : m_vRowList)
+ {
+ OSL_ENSURE(row,"OTableRow is null!");
+ OFieldDescription* pField = row->GetActFieldDescr();
+ if ( pField )
+ row->SetReadOnly(!bAlterAllowed);
+ else
+ row->SetReadOnly(!bAddAllowed);
+
+ }
+ static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
+
+ ClearUndoManager();
+ setModified(false); // and we are not modified yet
+}
+
+OUString OTableController::createUniqueName(const OUString& _rName)
+{
+ OUString sName = _rName;
+ Reference< XDatabaseMetaData> xMetaData = getMetaData( );
+
+ ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers());
+
+ auto lHasName = [&bCase, &sName](const std::shared_ptr<OTableRow>& rxRow) {
+ OFieldDescription* pFieldDesc = rxRow->GetActFieldDescr();
+ return pFieldDesc && !pFieldDesc->GetName().isEmpty() && bCase(sName, pFieldDesc->GetName());
+ };
+
+ sal_Int32 i = 0;
+ while(std::any_of(m_vRowList.begin(), m_vRowList.end(), lHasName))
+ {
+ // found a second name of _rName so we need another
+ sName = _rName + OUString::number(++i);
+ }
+ return sName;
+}
+
+OUString OTableController::getPrivateTitle() const
+{
+ OUString sTitle;
+ try
+ {
+ // get the table
+ if ( !m_sName.isEmpty() && getConnection().is() )
+ {
+ if ( m_xTable.is() )
+ sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::EComposeRule::InDataManipulation, false );
+ else
+ sTitle = m_sName;
+ }
+ if ( sTitle.isEmpty() )
+ {
+ OUString aName = DBA_RES(STR_TBL_TITLE);
+ sTitle = o3tl::getToken(aName,0,' ') + OUString::number(getCurrentStartNumber());
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sTitle;
+}
+
+void OTableController::reload()
+{
+ loadData(); // fill the column information from the table
+ static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information
+ ClearUndoManager();
+ setModified(false); // and we are not modified yet
+ static_cast<OTableDesignView*>(getView())->Invalidate();
+}
+
+sal_Int32 OTableController::getFirstEmptyRowPosition()
+{
+ sal_Int32 nRet = 0;
+ bool bFoundElem = false;
+ for (auto const& row : m_vRowList)
+ {
+ if ( !row || !row->GetActFieldDescr() || row->GetActFieldDescr()->GetName().isEmpty() )
+ {
+ bFoundElem = true;
+ break;
+ }
+ ++nRet;
+ }
+ if (!bFoundElem)
+ {
+ bool bReadRow = !isAddAllowed();
+ auto pTabEdRow = std::make_shared<OTableRow>();
+ pTabEdRow->SetReadOnly(bReadRow);
+ nRet = m_vRowList.size();
+ m_vRowList.push_back( pTabEdRow);
+ }
+ return nRet;
+}
+
+bool OTableController::isAutoIncrementPrimaryKey() const
+{
+ return getSdbMetaData().isAutoIncrementPrimaryKey();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableDesignControl.cxx b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx
new file mode 100644
index 000000000..1526682ed
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableDesignControl.hxx>
+#include <TableDesignView.hxx>
+#include <TableController.hxx>
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <helpids.h>
+
+using namespace ::dbaui;
+using namespace ::svt;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+// Defines
+#define HANDLE_ID 0
+
+OTableRowView::OTableRowView(vcl::Window* pParent)
+ : EditBrowseBox(pParent, EditBrowseBoxFlags::NONE, WB_TABSTOP|WB_HIDE|WB_3DLOOK,
+ BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION |
+ BrowserMode::AUTOSIZE_LASTCOL | BrowserMode::KEEPHIGHLIGHT |
+ BrowserMode::HLINES | BrowserMode::VLINES)
+ , m_nDataPos(-1)
+ , m_nCurrentPos(-1)
+ , m_nCurUndoActId(0)
+{
+ SetHelpId(HID_TABDESIGN_BACKGROUND);
+ SetSizePixel(LogicToPixel(Size(40, 12), MapMode(MapUnit::MapAppFont)));
+}
+
+void OTableRowView::Init()
+{
+ EditBrowseBox::Init();
+
+ vcl::Font aFont( GetDataWindow().GetFont() );
+ aFont.SetWeight( WEIGHT_NORMAL );
+ GetDataWindow().SetFont( aFont );
+
+ // set font for the headings to light
+ aFont = GetFont();
+ aFont.SetWeight( WEIGHT_LIGHT );
+ SetFont(aFont);
+
+ // set up HandleColumn for at maximum 5 digits
+ InsertHandleColumn(static_cast<sal_uInt16>(GetTextWidth(OUString('0')) * 4)/*, sal_True */);
+
+ BrowserMode const nMode = BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT |
+ BrowserMode::HLINES | BrowserMode::VLINES | BrowserMode::AUTOSIZE_LASTCOL;
+
+ SetMode(nMode);
+}
+
+void OTableRowView::KeyInput( const KeyEvent& rEvt )
+{
+ if (IsDeleteAllowed())
+ {
+ if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows
+ !rEvt.GetKeyCode().IsShift() &&
+ !rEvt.GetKeyCode().IsMod1())
+ {
+ DeleteRows();
+ return;
+ }
+ if( rEvt.GetKeyCode().GetCode() == KEY_F2 )
+ {
+ css::util::URL aUrl;
+ aUrl.Complete = ".uno:DSBEditDoc";
+ GetView()->getController().dispatch( aUrl,Sequence< PropertyValue >() );
+ }
+ }
+ EditBrowseBox::KeyInput(rEvt);
+}
+
+void OTableRowView::Command(const CommandEvent& rEvt)
+{
+
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ if (!rEvt.IsMouseEvent())
+ {
+ EditBrowseBox::Command(rEvt);
+ return;
+ }
+
+ sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()));
+ sal_Int32 nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
+
+ if ( nColId == HANDLE_ID )
+ {
+ ::tools::Rectangle aRect(rEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ sal_Int32 nSelectRowCount = GetSelectRowCount();
+ xContextMenu->set_sensitive("cut", nSelectRowCount != 0);
+ xContextMenu->set_sensitive("copy", nSelectRowCount != 0);
+ OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect);
+ if (sIdent == "cut")
+ cut();
+ else if (sIdent == "copy")
+ copy();
+ else if (sIdent == "insert")
+ {
+ InsertNewRows( nRow );
+ SetNoSelection();
+ GoToRow( nRow );
+ SeekRow( nRow );
+ }
+
+ return;
+ }
+
+ [[fallthrough]];
+ }
+ default:
+ EditBrowseBox::Command(rEvt);
+ }
+
+}
+
+void OTableRowView::cut()
+{
+ CopyRows();
+ DeleteRows();
+}
+
+void OTableRowView::copy()
+{
+ CopyRows();
+}
+
+void OTableRowView::paste()
+{
+ OSL_FAIL("OTableRowView::Paste : (pseudo-) abstract method called !");
+}
+
+void OTableRowView::Paste( sal_Int32 nRow )
+{
+ InsertRows( nRow );
+}
+
+EditBrowseBox::RowStatus OTableRowView::GetRowStatus(sal_Int32 nRow) const
+{
+ if (nRow >= 0 && m_nDataPos == nRow)
+ return CURRENT;
+ else
+ return CLEAN;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx
new file mode 100644
index 000000000..f81123e55
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableDesignHelpBar.hxx>
+#include <helpids.h>
+
+using namespace dbaui;
+
+#define DETAILS_MIN_HELP_WIDTH 200
+
+OTableDesignHelpBar::OTableDesignHelpBar(std::unique_ptr<weld::TextView> xTextWin)
+ : m_xTextWin(std::move(xTextWin))
+{
+ m_xTextWin->set_size_request(DETAILS_MIN_HELP_WIDTH, -1);
+ m_xTextWin->set_help_id(HID_TAB_DESIGN_HELP_TEXT_FRAME);
+}
+
+void OTableDesignHelpBar::SetHelpText(const OUString& rText)
+{
+ if (!m_xTextWin)
+ return;
+ m_xTextWin->set_text(rText);
+}
+
+bool OTableDesignHelpBar::isCopyAllowed()
+{
+ int mStartPos, nEndPos;
+ return m_xTextWin && m_xTextWin->get_selection_bounds(mStartPos, nEndPos);
+}
+
+bool OTableDesignHelpBar::isCutAllowed() { return false; }
+
+bool OTableDesignHelpBar::isPasteAllowed() { return false; }
+
+void OTableDesignHelpBar::cut() {}
+
+void OTableDesignHelpBar::copy()
+{
+ if (!m_xTextWin)
+ return;
+ m_xTextWin->copy_clipboard();
+}
+
+void OTableDesignHelpBar::paste() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableDesignView.cxx b/dbaccess/source/ui/tabledesign/TableDesignView.cxx
new file mode 100644
index 000000000..f0570ddba
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableDesignView.cxx
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableDesignView.hxx>
+#include <TableController.hxx>
+#include <helpids.h>
+#include <FieldDescriptions.hxx>
+#include "TEditControl.hxx"
+#include "TableFieldDescWin.hxx"
+#include <TableRow.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <unotools/syslocale.hxx>
+#include <memory>
+
+using namespace ::dbaui;
+using namespace ::utl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+
+OTableBorderWindow::OTableBorderWindow(OTableDesignView* pParent)
+ : InterimItemWindow(pParent, "dbaccess/ui/tableborderwindow.ui", "TableBorderWindow", false)
+ , m_xHorzSplitter(m_xBuilder->weld_paned("splitter"))
+ , m_xEditorParent(m_xBuilder->weld_container("editor"))
+ , m_xEditorParentWin(m_xEditorParent->CreateChildFrame())
+ , m_xEditorCtrl(VclPtr<OTableEditorCtrl>::Create(VCLUnoHelper::GetWindow(m_xEditorParentWin), pParent))
+ , m_xFieldDescParent(m_xBuilder->weld_container("fielddesc"))
+ , m_xFieldDescWin(new OTableFieldDescWin(m_xFieldDescParent.get(), pParent))
+{
+ SetStyle(GetStyle() | WB_DIALOGCONTROL);
+
+ m_xFieldDescWin->SetHelpId(HID_TAB_DESIGN_DESCWIN);
+
+ // set depending windows and controls
+ m_xEditorCtrl->SetDescrWin(m_xFieldDescWin.get());
+}
+
+OTableBorderWindow::~OTableBorderWindow()
+{
+ disposeOnce();
+}
+
+void OTableBorderWindow::dispose()
+{
+ // destroy children
+ m_xEditorCtrl.disposeAndClear();
+ m_xEditorParentWin->dispose();
+ m_xEditorParentWin.clear();
+ m_xEditorParent.reset();
+ m_xFieldDescWin.reset();
+ m_xFieldDescParent.reset();
+ m_xHorzSplitter.reset();
+ InterimItemWindow::dispose();
+}
+
+void OTableBorderWindow::Layout()
+{
+ // dimensions of parent window
+ auto nOutputHeight = GetSizePixel().Height();
+ auto nOldSplitPos = m_xHorzSplitter->get_position();
+ auto nSplitPos = nOldSplitPos;
+
+ // shift range of the splitter is the middle third of the output
+ auto nDragPosY = nOutputHeight/3;
+ auto nDragSizeHeight = nOutputHeight/3;
+ if (nSplitPos < nDragPosY || nSplitPos > nDragPosY + nDragSizeHeight)
+ nSplitPos = nDragPosY + nDragSizeHeight;
+
+ // set splitter
+ m_xHorzSplitter->set_position(nSplitPos);
+
+ InterimItemWindow::Layout();
+
+ if (nOldSplitPos != nSplitPos)
+ m_xHorzSplitter->set_position(nSplitPos);
+}
+
+void OTableBorderWindow::GetFocus()
+{
+ InterimItemWindow::GetFocus();
+
+ // forward the focus to the current cell of the editor control
+ if (m_xEditorCtrl)
+ m_xEditorCtrl->GrabFocus();
+}
+
+OTableDesignView::OTableDesignView( vcl::Window* pParent,
+ const Reference< XComponentContext >& _rxOrb,
+ OTableController& _rController
+ ) :
+ ODataView( pParent, _rController,_rxOrb )
+ ,m_rController( _rController )
+ ,m_eChildFocus(NONE)
+{
+
+ try
+ {
+ m_aLocale = SvtSysLocale().GetLanguageTag().getLocale();
+ }
+ catch(Exception&)
+ {
+ }
+
+ m_pWin = VclPtr<OTableBorderWindow>::Create(this);
+
+ m_pWin->GetDescWin()->connect_focus_in(LINK(this, OTableDesignView, FieldDescFocusIn));
+
+ m_pWin->Show();
+}
+
+OTableDesignView::~OTableDesignView()
+{
+ disposeOnce();
+}
+
+void OTableDesignView::dispose()
+{
+ m_pWin->Hide();
+ m_pWin.disposeAndClear();
+ ODataView::dispose();
+}
+
+void OTableDesignView::initialize()
+{
+ GetEditorCtrl()->Init();
+ GetDescWin()->Init();
+ // first call after the editctrl has been set
+
+ GetEditorCtrl()->Show();
+ GetDescWin()->Show();
+
+ GetEditorCtrl()->DisplayData(0);
+}
+
+void OTableDesignView::resizeDocumentView(tools::Rectangle& _rPlayground)
+{
+ m_pWin->SetPosSizePixel( _rPlayground.TopLeft(), _rPlayground.GetSize() );
+
+ // just for completeness: there is no space left, we occupied it all ...
+ _rPlayground.SetPos( _rPlayground.BottomRight() );
+ _rPlayground.SetSize( Size( 0, 0 ) );
+}
+
+IMPL_LINK_NOARG(OTableDesignView, FieldDescFocusIn, weld::Widget&, void)
+{
+ m_eChildFocus = DESCRIPTION;
+}
+
+bool OTableDesignView::PreNotify( NotifyEvent& rNEvt )
+{
+ if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS)
+ {
+ if( GetDescWin() && GetDescWin()->HasChildPathFocus() )
+ m_eChildFocus = DESCRIPTION;
+ else if ( GetEditorCtrl() && GetEditorCtrl()->HasChildPathFocus() )
+ m_eChildFocus = EDITOR;
+ else
+ m_eChildFocus = NONE;
+ }
+
+ return ODataView::PreNotify(rNEvt);
+}
+
+IClipboardTest* OTableDesignView::getActiveChild() const
+{
+ IClipboardTest* pTest = nullptr;
+ switch(m_eChildFocus)
+ {
+ case DESCRIPTION:
+ pTest = GetDescWin();
+ break;
+ case EDITOR:
+ pTest = GetEditorCtrl();
+ break;
+ case NONE:
+ break;
+ }
+ return pTest;
+}
+
+bool OTableDesignView::isCopyAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isCopyAllowed();
+}
+
+bool OTableDesignView::isCutAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isCutAllowed();
+}
+
+bool OTableDesignView::isPasteAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isPasteAllowed();
+}
+
+void OTableDesignView::copy()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->copy();
+}
+
+void OTableDesignView::cut()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->cut();
+}
+
+void OTableDesignView::paste()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->paste();
+}
+
+// set the view readonly or not
+void OTableDesignView::setReadOnly(bool _bReadOnly)
+{
+ GetDescWin()->SetReadOnly(_bReadOnly);
+ GetEditorCtrl()->SetReadOnly(_bReadOnly);
+}
+
+void OTableDesignView::reSync()
+{
+ GetEditorCtrl()->DeactivateCell();
+ std::shared_ptr<OTableRow> pRow = (*GetEditorCtrl()->GetRowList())[GetEditorCtrl()->GetCurRow()];
+ OFieldDescription* pFieldDescr = pRow ? pRow->GetActFieldDescr() : nullptr;
+ if ( pFieldDescr )
+ GetDescWin()->DisplayData(pFieldDescr);
+}
+
+void OTableDesignView::GetFocus()
+{
+ if ( GetEditorCtrl() )
+ GetEditorCtrl()->GrabFocus();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableFieldControl.cxx b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx
new file mode 100644
index 000000000..aa04b914a
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TableFieldControl.hxx"
+#include <TableController.hxx>
+#include <TableDesignView.hxx>
+#include "TEditControl.hxx"
+#include <strings.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <comphelper/types.hxx>
+#include <TypeInfo.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace dbaui;
+
+OTableFieldControl::OTableFieldControl(weld::Container* pParent, OTableDesignHelpBar* pHelpBar, OTableDesignView* pView)
+ : OFieldDescControl(pParent, pHelpBar)
+ , m_xView(pView)
+{
+}
+
+void OTableFieldControl::dispose()
+{
+ m_xView.clear();
+}
+
+OTableFieldControl::~OTableFieldControl()
+{
+ dispose();
+}
+
+void OTableFieldControl::CellModified(sal_Int32 nRow, sal_uInt16 nColId )
+{
+ GetCtrl()->CellModified(nRow,nColId);
+}
+
+OTableEditorCtrl* OTableFieldControl::GetCtrl() const
+{
+ assert(m_xView && "no view!");
+ return m_xView->GetEditorCtrl();
+}
+
+bool OTableFieldControl::IsReadOnly()
+{
+ bool bRead(GetCtrl()->IsReadOnly());
+ if( !bRead )
+ {
+ // The columns of a css::sdbcx::View could not be locked
+ Reference<XPropertySet> xTable = GetCtrl()->GetView()->getController().getTable();
+ if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW")
+ bRead = true;
+ else
+ {
+ std::shared_ptr<OTableRow> pCurRow = GetCtrl()->GetActRow();
+ if( pCurRow )
+ bRead = pCurRow->IsReadOnly();
+ }
+ }
+ return bRead;
+}
+
+void OTableFieldControl::ActivateAggregate( EControlType eType )
+{
+ switch(eType)
+ {
+ case tpColumnName:
+ case tpType:
+ break;
+ default:
+ OFieldDescControl::ActivateAggregate(eType);
+ }
+}
+
+void OTableFieldControl::DeactivateAggregate( EControlType eType )
+{
+ switch(eType)
+ {
+ case tpColumnName:
+ case tpType:
+ break;
+ default:
+ OFieldDescControl::DeactivateAggregate(eType);
+ }
+}
+
+void OTableFieldControl::SetModified(bool bModified)
+{
+ GetCtrl()->GetView()->getController().setModified(bModified);
+}
+
+css::uno::Reference< css::sdbc::XConnection> OTableFieldControl::getConnection()
+{
+ return GetCtrl()->GetView()->getController().getConnection();
+}
+
+css::uno::Reference< css::sdbc::XDatabaseMetaData> OTableFieldControl::getMetaData()
+{
+ Reference<XConnection> xCon = GetCtrl()->GetView()->getController().getConnection();
+ if(!xCon.is())
+ return nullptr;
+ return xCon->getMetaData();
+}
+
+Reference< XNumberFormatter > OTableFieldControl::GetFormatter() const
+{
+ return GetCtrl()->GetView()->getController().getNumberFormatter();
+}
+
+TOTypeInfoSP OTableFieldControl::getTypeInfo(sal_Int32 _nPos)
+{
+ return GetCtrl()->GetView()->getController().getTypeInfo(_nPos);
+}
+
+const OTypeInfoMap* OTableFieldControl::getTypeInfo() const
+{
+ return &GetCtrl()->GetView()->getController().getTypeInfo();
+}
+
+Locale OTableFieldControl::GetLocale() const
+{
+ return GetCtrl()->GetView()->getLocale();
+}
+
+bool OTableFieldControl::isAutoIncrementValueEnabled() const
+{
+ return GetCtrl()->GetView()->getController().isAutoIncrementValueEnabled();
+}
+
+OUString OTableFieldControl::getAutoIncrementValue() const
+{
+ return GetCtrl()->GetView()->getController().getAutoIncrementValue();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableFieldControl.hxx b/dbaccess/source/ui/tabledesign/TableFieldControl.hxx
new file mode 100644
index 000000000..4a232f86c
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableFieldControl.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <FieldDescControl.hxx>
+
+namespace dbaui
+{
+ class OTableEditorCtrl;
+ class OTableDesignHelpBar;
+ class OTableDesignView;
+
+ // OTableFieldControl
+ class OTableFieldControl : public OFieldDescControl
+ {
+ VclPtr<OTableDesignView> m_xView;
+
+ OTableEditorCtrl* GetCtrl() const;
+
+ void dispose();
+
+ protected:
+ virtual void ActivateAggregate( EControlType eType ) override;
+ virtual void DeactivateAggregate( EControlType eType ) override;
+ // are to be implemented by the derived classes
+ virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) override;
+ virtual bool IsReadOnly() override;
+ virtual void SetModified(bool bModified) override;
+ virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const override;
+
+ virtual css::lang::Locale GetLocale() const override;
+
+ virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) override;
+ virtual const OTypeInfoMap* getTypeInfo() const override;
+ virtual bool isAutoIncrementValueEnabled() const override;
+ virtual OUString getAutoIncrementValue() const override;
+
+ public:
+ OTableFieldControl(weld::Container* pParent, OTableDesignHelpBar* pHelpBar, OTableDesignView* pView);
+ virtual ~OTableFieldControl() override;
+
+ using OFieldDescControl::BoolStringPersistent;
+ using OFieldDescControl::BoolStringUI;
+
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override;
+ virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx
new file mode 100644
index 000000000..7e6c4f111
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TableFieldDescWin.hxx"
+#include <FieldDescriptions.hxx>
+#include <strings.hrc>
+#include <TableDesignHelpBar.hxx>
+#include <helpids.h>
+#include <core_resource.hxx>
+
+using namespace dbaui;
+
+OTableFieldDescWin::OTableFieldDescWin(weld::Container* pParent, OTableDesignView* pView)
+ : OChildWindow(pParent, "dbaccess/ui/fielddescpanel.ui", "FieldDescPanel")
+ , m_xHelpBar(new OTableDesignHelpBar(m_xBuilder->weld_text_view("textview")))
+ , m_xBox(m_xBuilder->weld_container("box"))
+ , m_xFieldControl(new OTableFieldControl(m_xBox.get(), m_xHelpBar.get(), pView))
+ , m_xHeader(m_xBuilder->weld_label("header"))
+ , m_eChildFocus(NONE)
+{
+ // Header
+ m_xHeader->set_label(DBA_RES(STR_TAB_PROPERTIES));
+
+ m_xFieldControl->SetHelpId(HID_TAB_DESIGN_FIELDCONTROL);
+
+ m_xHelpBar->connect_focus_in(LINK(this, OTableFieldDescWin, HelpFocusIn));
+ m_xFieldControl->connect_focus_in(LINK(this, OTableFieldDescWin, FieldFocusIn));
+}
+
+bool OTableFieldDescWin::HasChildPathFocus() const
+{
+ return m_xFieldControl->HasChildPathFocus() || m_xHelpBar->HasFocus();
+}
+
+OTableFieldDescWin::~OTableFieldDescWin()
+{
+}
+
+void OTableFieldDescWin::Init()
+{
+ m_xFieldControl->Init();
+}
+
+void OTableFieldDescWin::SetReadOnly( bool bRead )
+{
+ m_xFieldControl->SetReadOnly( bRead );
+}
+
+void OTableFieldDescWin::DisplayData( OFieldDescription* pFieldDescr )
+{
+ m_xFieldControl->DisplayData( pFieldDescr );
+}
+
+void OTableFieldDescWin::SaveData( OFieldDescription* pFieldDescr )
+{
+ m_xFieldControl->SaveData( pFieldDescr );
+}
+
+IClipboardTest* OTableFieldDescWin::getActiveChild() const
+{
+ IClipboardTest* pTest = nullptr;
+ switch(m_eChildFocus)
+ {
+ case DESCRIPTION:
+ pTest = m_xFieldControl.get();
+ break;
+ default:
+ pTest = m_xHelpBar.get();
+ break;
+ }
+ return pTest;
+}
+
+bool OTableFieldDescWin::isCopyAllowed()
+{
+ return getActiveChild() && getActiveChild()->isCopyAllowed();
+}
+
+bool OTableFieldDescWin::isCutAllowed()
+{
+ return getActiveChild() && getActiveChild()->isCutAllowed();
+}
+
+bool OTableFieldDescWin::isPasteAllowed()
+{
+ return getActiveChild() && getActiveChild()->isPasteAllowed();
+}
+
+void OTableFieldDescWin::cut()
+{
+ if (getActiveChild())
+ getActiveChild()->cut();
+}
+
+void OTableFieldDescWin::copy()
+{
+ if ( getActiveChild() )
+ getActiveChild()->copy();
+}
+
+void OTableFieldDescWin::paste()
+{
+ if (getActiveChild())
+ getActiveChild()->paste();
+}
+
+void OTableFieldDescWin::GrabFocus()
+{
+ m_xFieldControl->GrabFocus();
+}
+
+IMPL_LINK(OTableFieldDescWin, HelpFocusIn, weld::Widget&, rWidget, void)
+{
+ m_eChildFocus = HELP;
+ m_aFocusInHdl.Call(rWidget);
+}
+
+IMPL_LINK(OTableFieldDescWin, FieldFocusIn, weld::Widget&, rWidget, void)
+{
+ m_eChildFocus = DESCRIPTION;
+ m_aFocusInHdl.Call(rWidget);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx
new file mode 100644
index 000000000..9f15c1e1b
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <IClipBoardTest.hxx>
+#include <ChildWindow.hxx>
+#include "TableFieldControl.hxx"
+
+namespace dbaui
+{
+ class OTableDesignHelpBar;
+ class OTableDesignView;
+ class OFieldDescription;
+
+ class OTableFieldDescWin final : public OChildWindow
+ , public IClipboardTest
+ {
+ enum ChildFocusState
+ {
+ DESCRIPTION,
+ HELP,
+ NONE
+ };
+ private:
+ std::unique_ptr<OTableDesignHelpBar> m_xHelpBar;
+ std::unique_ptr<weld::Container> m_xBox;
+ std::unique_ptr<OTableFieldControl> m_xFieldControl;
+ std::unique_ptr<weld::Label> m_xHeader;
+ Link<weld::Widget&, void> m_aFocusInHdl;
+
+ ChildFocusState m_eChildFocus;
+
+ IClipboardTest* getActiveChild() const;
+
+ DECL_LINK(HelpFocusIn, weld::Widget&, void);
+ DECL_LINK(FieldFocusIn, weld::Widget&, void);
+
+ public:
+ explicit OTableFieldDescWin(weld::Container* pParent, OTableDesignView* pView);
+ virtual ~OTableFieldDescWin() override;
+
+ void Init();
+
+ void DisplayData( OFieldDescription* pFieldDescr );
+ void SaveData( OFieldDescription* pFieldDescr );
+ void SetReadOnly( bool bReadOnly );
+
+ void SetControlText( sal_uInt16 nControlId, const OUString& rText )
+ { m_xFieldControl->SetControlText(nControlId,rText); }
+
+ OUString BoolStringPersistent(std::u16string_view rUIString) const { return m_xFieldControl->BoolStringPersistent(rUIString); }
+ OUString BoolStringUI(const OUString& rPersistentString) const { return m_xFieldControl->BoolStringUI(rPersistentString); }
+
+ virtual bool HasChildPathFocus() const override;
+ virtual void GrabFocus() override;
+
+ // IClipboardTest
+ virtual bool isCutAllowed() override;
+ virtual bool isCopyAllowed() override;
+ virtual bool isPasteAllowed() override;
+
+ virtual void copy() override;
+ virtual void cut() override;
+ virtual void paste() override;
+
+ void connect_focus_in(const Link<weld::Widget&, void>& rLink)
+ {
+ m_aFocusInHdl = rLink;
+ }
+
+ OTableFieldControl* getGenPage() const { return m_xFieldControl.get(); }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableRow.cxx b/dbaccess/source/ui/tabledesign/TableRow.cxx
new file mode 100644
index 000000000..8f13193e1
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableRow.cxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableRow.hxx>
+#include <tools/stream.hxx>
+#include <FieldDescriptions.hxx>
+#include <comphelper/types.hxx>
+
+using namespace dbaui;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+OTableRow::OTableRow()
+ :m_pActFieldDescr( nullptr )
+ ,m_nPos( -1 )
+ ,m_bReadOnly( false )
+ ,m_bOwnsDescriptions(false)
+{
+}
+
+OTableRow::OTableRow( const OTableRow& rRow, tools::Long nPosition )
+ :m_pActFieldDescr(nullptr)
+ ,m_nPos( nPosition )
+ ,m_bReadOnly(rRow.IsReadOnly())
+ ,m_bOwnsDescriptions(false)
+{
+
+ OFieldDescription* pSrcField = rRow.GetActFieldDescr();
+ if(pSrcField)
+ {
+ m_pActFieldDescr = new OFieldDescription(*pSrcField);
+ m_bOwnsDescriptions = true;
+ }
+}
+
+OTableRow::~OTableRow()
+{
+ if(m_bOwnsDescriptions)
+ delete m_pActFieldDescr;
+}
+
+void OTableRow::SetPrimaryKey( bool bSet )
+{
+ if(m_pActFieldDescr)
+ m_pActFieldDescr->SetPrimaryKey(bSet);
+}
+
+bool OTableRow::IsPrimaryKey() const
+{
+ return m_pActFieldDescr && m_pActFieldDescr->IsPrimaryKey();
+}
+
+void OTableRow::SetFieldType( const TOTypeInfoSP& _pType, bool _bForce )
+{
+ if ( _pType )
+ {
+ if( !m_pActFieldDescr )
+ {
+ m_pActFieldDescr = new OFieldDescription();
+ m_bOwnsDescriptions = true;
+ }
+ m_pActFieldDescr->FillFromTypeInfo(_pType,_bForce,true);
+ }
+ else
+ {
+ delete m_pActFieldDescr;
+ m_pActFieldDescr = nullptr;
+ }
+}
+
+namespace dbaui
+{
+ SvStream& WriteOTableRow( SvStream& _rStr, const OTableRow& _rRow )
+ {
+ _rStr.WriteInt32( _rRow.m_nPos );
+ OFieldDescription* pFieldDesc = _rRow.GetActFieldDescr();
+ if(pFieldDesc)
+ {
+ _rStr.WriteInt32( 1 );
+ _rStr.WriteUniOrByteString(pFieldDesc->GetName(), _rStr.GetStreamCharSet());
+ _rStr.WriteUniOrByteString(pFieldDesc->GetDescription(), _rStr.GetStreamCharSet());
+ _rStr.WriteUniOrByteString(pFieldDesc->GetHelpText(), _rStr.GetStreamCharSet());
+ double nValue = 0.0;
+ Any aValue = pFieldDesc->GetControlDefault();
+ if ( aValue >>= nValue )
+ {
+ _rStr.WriteInt32( 1 );
+ _rStr.WriteDouble( nValue );
+ }
+ else
+ {
+ _rStr.WriteInt32( 2 );
+ _rStr.WriteUniOrByteString(::comphelper::getString(aValue), _rStr.GetStreamCharSet());
+ }
+
+ _rStr.WriteInt32( pFieldDesc->GetType() );
+
+ _rStr.WriteInt32( pFieldDesc->GetPrecision() );
+ _rStr.WriteInt32( pFieldDesc->GetScale() );
+ _rStr.WriteInt32( pFieldDesc->GetIsNullable() );
+ _rStr.WriteInt32( pFieldDesc->GetFormatKey() );
+ _rStr.WriteInt32( static_cast<sal_Int32>(pFieldDesc->GetHorJustify()) );
+ _rStr.WriteInt32( pFieldDesc->IsAutoIncrement() ? 1 : 0 );
+ _rStr.WriteInt32( pFieldDesc->IsPrimaryKey() ? 1 : 0 );
+ _rStr.WriteInt32( pFieldDesc->IsCurrency() ? 1 : 0 );
+ }
+ else
+ _rStr.WriteInt32( 0 );
+ return _rStr;
+ }
+ SvStream& ReadOTableRow( SvStream& _rStr, OTableRow& _rRow )
+ {
+ _rStr.ReadInt32( _rRow.m_nPos );
+ sal_Int32 nValue = 0;
+ _rStr.ReadInt32( nValue );
+ if ( !nValue )
+ return _rStr;
+ OFieldDescription* pFieldDesc = new OFieldDescription();
+ _rRow.m_pActFieldDescr = pFieldDesc;
+ pFieldDesc->SetName(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet()));
+ pFieldDesc->SetDescription(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet()));
+ pFieldDesc->SetHelpText(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet()));
+
+ _rStr.ReadInt32( nValue );
+ Any aControlDefault;
+ switch ( nValue )
+ {
+ case 1:
+ {
+ double nControlDefault;
+ _rStr.ReadDouble( nControlDefault );
+ aControlDefault <<= nControlDefault;
+ break;
+ }
+ case 2:
+ aControlDefault <<= _rStr.ReadUniOrByteString(_rStr.GetStreamCharSet());
+ break;
+ }
+
+ pFieldDesc->SetControlDefault(aControlDefault);
+
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetTypeValue(nValue);
+
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetPrecision(nValue);
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetScale(nValue);
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetIsNullable(nValue);
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetFormatKey(nValue);
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetHorJustify(static_cast<SvxCellHorJustify>(nValue));
+
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetAutoIncrement(nValue != 0);
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetPrimaryKey(nValue != 0);
+ _rStr.ReadInt32( nValue );
+ pFieldDesc->SetCurrency(nValue != 0);
+ return _rStr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableRowExchange.cxx b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx
new file mode 100644
index 000000000..c56450ac1
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TableRowExchange.hxx>
+#include <sot/formats.hxx>
+#include <sot/storage.hxx>
+#include <TableRow.hxx>
+
+namespace dbaui
+{
+ constexpr sal_uInt32 FORMAT_OBJECT_ID_SBA_TABED = 1;
+
+ using namespace ::com::sun::star::uno;
+ OTableRowExchange::OTableRowExchange(std::vector< std::shared_ptr<OTableRow> >&& _rvTableRow)
+ : m_vTableRow(std::move(_rvTableRow))
+ {
+ }
+ bool OTableRowExchange::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& /*rFlavor*/ )
+ {
+ if(nUserObjectId == FORMAT_OBJECT_ID_SBA_TABED)
+ {
+ std::vector< std::shared_ptr<OTableRow> >* pRows = static_cast< std::vector< std::shared_ptr<OTableRow> >* >(pUserObject);
+ if(pRows)
+ {
+ (*rxOStm).WriteInt32( pRows->size() ); // first stream the size
+ for (auto const& row : *pRows)
+ WriteOTableRow(*rxOStm, *row);
+ return true;
+ }
+ }
+ return false;
+ }
+ void OTableRowExchange::AddSupportedFormats()
+ {
+ if ( !m_vTableRow.empty() )
+ AddFormat(SotClipboardFormatId::SBA_TABED);
+ }
+ bool OTableRowExchange::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor);
+ if(nFormat == SotClipboardFormatId::SBA_TABED)
+ return SetObject(&m_vTableRow,FORMAT_OBJECT_ID_SBA_TABED,rFlavor);
+ return false;
+ }
+ void OTableRowExchange::ObjectReleased()
+ {
+ m_vTableRow.clear();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableUndo.cxx b/dbaccess/source/ui/tabledesign/TableUndo.cxx
new file mode 100644
index 000000000..d60756a2e
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableUndo.cxx
@@ -0,0 +1,352 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TableUndo.hxx"
+#include <strings.hrc>
+#include "TEditControl.hxx"
+#include <TableRow.hxx>
+#include <TableController.hxx>
+#include <TableDesignView.hxx>
+#include <FieldDescriptions.hxx>
+#include <svx/svxids.hrc>
+
+using namespace dbaui;
+using namespace ::svt;
+
+
+OTableDesignUndoAct::OTableDesignUndoAct(OTableRowView* pOwner, TranslateId pCommentID)
+ : OCommentUndoAction(pCommentID)
+ , m_pTabDgnCtrl(pOwner)
+{
+ m_pTabDgnCtrl->m_nCurUndoActId++;
+}
+
+OTableDesignUndoAct::~OTableDesignUndoAct()
+{
+}
+
+void OTableDesignUndoAct::Undo()
+{
+ m_pTabDgnCtrl->m_nCurUndoActId--;
+
+ // doc has not been modified if first undo was reverted
+ if( m_pTabDgnCtrl->m_nCurUndoActId == 0 )
+ {
+ m_pTabDgnCtrl->GetView()->getController().setModified(false);
+ m_pTabDgnCtrl->GetView()->getController().InvalidateFeature(SID_SAVEDOC);
+ }
+}
+
+void OTableDesignUndoAct::Redo()
+{
+ m_pTabDgnCtrl->m_nCurUndoActId++;
+
+ // restore Modified-flag after Redo of first Undo-action
+ if( m_pTabDgnCtrl->m_nCurUndoActId > 0 )
+ {
+ m_pTabDgnCtrl->GetView()->getController().setModified(true);
+ m_pTabDgnCtrl->GetView()->getController().InvalidateFeature(SID_SAVEDOC);
+ }
+}
+
+OTableDesignCellUndoAct::OTableDesignCellUndoAct( OTableRowView* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn ) :
+ OTableDesignUndoAct( pOwner ,STR_TABED_UNDO_CELLMODIFIED)
+ ,m_nCol( nColumn )
+ ,m_nRow( nRowID )
+{
+ // read text at position (m_nRow, m_nCol)
+ m_sOldText = m_pTabDgnCtrl->GetCellData( m_nRow, m_nCol );
+}
+
+OTableDesignCellUndoAct::~OTableDesignCellUndoAct()
+{
+}
+
+void OTableDesignCellUndoAct::Undo()
+{
+ // store text at old line and restore the old one
+ m_pTabDgnCtrl->ActivateCell( m_nRow, m_nCol );
+ m_sNewText = m_pTabDgnCtrl->GetCellData( m_nRow, m_nCol );
+ m_pTabDgnCtrl->SetCellData( m_nRow, m_nCol, m_sOldText );
+ // line has not been modified if the first Undo was reverted
+ if (m_pTabDgnCtrl->GetCurUndoActId() == 1)
+ {
+ CellControllerRef xController = m_pTabDgnCtrl->Controller();
+ if ( xController.is() )
+ xController->SaveValue();
+ m_pTabDgnCtrl->GetView()->getController().setModified(false);
+
+ }
+
+ OTableDesignUndoAct::Undo();
+}
+
+void OTableDesignCellUndoAct::Redo()
+{
+ // restore new text
+ m_pTabDgnCtrl->ActivateCell( m_nRow, m_nCol );
+ m_pTabDgnCtrl->SetCellData( m_nRow, m_nCol, m_sNewText );
+
+ OTableDesignUndoAct::Redo();
+}
+
+OTableEditorUndoAct::OTableEditorUndoAct(OTableEditorCtrl* pOwner, TranslateId pCommentID)
+ : OTableDesignUndoAct(pOwner, pCommentID)
+ , pTabEdCtrl(pOwner)
+{
+}
+
+OTableEditorUndoAct::~OTableEditorUndoAct()
+{
+}
+
+OTableEditorTypeSelUndoAct::OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType )
+ :OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_TYPE_CHANGED)
+ ,m_nCol( nColumn )
+ ,m_nRow( nRowID )
+ ,m_pOldType( _pOldType )
+{
+}
+
+OTableEditorTypeSelUndoAct::~OTableEditorTypeSelUndoAct()
+{
+}
+
+void OTableEditorTypeSelUndoAct::Undo()
+{
+ // restore type
+ OFieldDescription* pFieldDesc = pTabEdCtrl->GetFieldDescr(m_nRow);
+ if(pFieldDesc)
+ m_pNewType = pFieldDesc->getTypeInfo();
+ else
+ m_pNewType = TOTypeInfoSP();
+ pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pOldType);
+ pTabEdCtrl->SwitchType( m_pOldType );
+
+ OTableEditorUndoAct::Undo();
+}
+
+void OTableEditorTypeSelUndoAct::Redo()
+{
+ // new type
+ pTabEdCtrl->GoToRowColumnId( m_nRow ,m_nCol);
+ pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pNewType);
+
+ OTableEditorUndoAct::Redo();
+}
+
+OTableEditorDelUndoAct::OTableEditorDelUndoAct( OTableEditorCtrl* pOwner) :
+ OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_ROWDELETED)
+{
+ // fill DeletedRowList
+ std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pOwner->GetRowList();
+ sal_Int32 nIndex = pOwner->FirstSelectedRow();
+ std::shared_ptr<OTableRow> pOriginalRow;
+ std::shared_ptr<OTableRow> pNewRow;
+
+ while( nIndex != SFX_ENDOFSELECTION )
+ {
+ pOriginalRow = (*pOriginalRows)[nIndex];
+ pNewRow = std::make_shared<OTableRow>( *pOriginalRow, nIndex );
+ m_aDeletedRows.push_back( pNewRow);
+
+ nIndex = pOwner->NextSelectedRow();
+ }
+}
+
+OTableEditorDelUndoAct::~OTableEditorDelUndoAct()
+{
+ m_aDeletedRows.clear();
+}
+
+void OTableEditorDelUndoAct::Undo()
+{
+ // Insert the deleted line
+ sal_uLong nPos;
+
+ std::shared_ptr<OTableRow> pNewOrigRow;
+ std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList();
+
+ for (auto const& deletedRow : m_aDeletedRows)
+ {
+ pNewOrigRow = std::make_shared<OTableRow>( *deletedRow );
+ nPos = deletedRow->GetPos();
+ pOriginalRows->insert( pOriginalRows->begin()+nPos,pNewOrigRow);
+ }
+
+ pTabEdCtrl->DisplayData(pTabEdCtrl->GetCurRow());
+ pTabEdCtrl->Invalidate();
+ OTableEditorUndoAct::Undo();
+}
+
+void OTableEditorDelUndoAct::Redo()
+{
+ // delete line again
+ std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList();
+
+ for (auto const& deletedRow : m_aDeletedRows)
+ {
+ auto it = pOriginalRows->begin() + deletedRow->GetPos();
+ pOriginalRows->erase(it);
+ }
+
+ pTabEdCtrl->DisplayData(pTabEdCtrl->GetCurRow());
+ pTabEdCtrl->Invalidate();
+ OTableEditorUndoAct::Redo();
+}
+
+OTableEditorInsUndoAct::OTableEditorInsUndoAct( OTableEditorCtrl* pOwner,
+ tools::Long nInsertPosition ,
+ std::vector< std::shared_ptr<OTableRow> >&& _vInsertedRows)
+ :OTableEditorUndoAct( pOwner,STR_TABED_UNDO_ROWINSERTED )
+ ,m_vInsertedRows(std::move(_vInsertedRows))
+ ,m_nInsPos( nInsertPosition )
+{
+}
+
+OTableEditorInsUndoAct::~OTableEditorInsUndoAct()
+{
+ m_vInsertedRows.clear();
+}
+
+void OTableEditorInsUndoAct::Undo()
+{
+ // delete lines again
+ std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList();
+ pOriginalRows->erase(pOriginalRows->begin() + m_nInsPos, pOriginalRows->begin() + m_nInsPos + m_vInsertedRows.size());
+
+ pTabEdCtrl->RowRemoved( m_nInsPos, m_vInsertedRows.size() );
+ pTabEdCtrl->InvalidateHandleColumn();
+
+ OTableEditorUndoAct::Undo();
+}
+
+void OTableEditorInsUndoAct::Redo()
+{
+ // insert lines again
+ sal_Int32 nInsertRow = m_nInsPos;
+ std::shared_ptr<OTableRow> pRow;
+ std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList();
+ for (auto const& insertedRow : m_vInsertedRows)
+ {
+ pRow = std::make_shared<OTableRow>( *insertedRow );
+ pRowList->insert( pRowList->begin()+nInsertRow ,pRow );
+ nInsertRow++;
+ }
+
+ pTabEdCtrl->RowInserted( m_nInsPos, m_vInsertedRows.size() );
+ pTabEdCtrl->InvalidateHandleColumn();
+
+ OTableEditorUndoAct::Redo();
+}
+
+OTableEditorInsNewUndoAct::OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nInsertPosition, sal_Int32 nInsertedRows ) :
+ OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_NEWROWINSERTED)
+ ,m_nInsPos( nInsertPosition )
+ ,m_nInsRows( nInsertedRows )
+{
+}
+
+OTableEditorInsNewUndoAct::~OTableEditorInsNewUndoAct()
+{
+}
+
+void OTableEditorInsNewUndoAct::Undo()
+{
+ // delete inserted lines
+ std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList();
+
+ pOriginalRows->erase(pOriginalRows->begin() + m_nInsPos, pOriginalRows->begin() + m_nInsPos + m_nInsRows);
+
+ pTabEdCtrl->RowRemoved( m_nInsPos, m_nInsRows );
+ pTabEdCtrl->InvalidateHandleColumn();
+
+ OTableEditorUndoAct::Undo();
+}
+
+void OTableEditorInsNewUndoAct::Redo()
+{
+ // insert lines again
+ std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList();
+
+ for( tools::Long i=m_nInsPos; i<(m_nInsPos+m_nInsRows); i++ )
+ pRowList->insert( pRowList->begin()+i,std::make_shared<OTableRow>() );
+
+ pTabEdCtrl->RowInserted( m_nInsPos, m_nInsRows );
+ pTabEdCtrl->InvalidateHandleColumn();
+
+ OTableEditorUndoAct::Redo();
+}
+
+OPrimKeyUndoAct::OPrimKeyUndoAct( OTableEditorCtrl* pOwner, const MultiSelection& aDeletedKeys, const MultiSelection& aInsertedKeys) :
+ OTableEditorUndoAct( pOwner ,STR_TABLEDESIGN_UNDO_PRIMKEY)
+ ,m_aDelKeys( aDeletedKeys )
+ ,m_aInsKeys( aInsertedKeys )
+ ,m_pEditorCtrl( pOwner )
+{
+}
+
+OPrimKeyUndoAct::~OPrimKeyUndoAct()
+{
+}
+
+void OPrimKeyUndoAct::Undo()
+{
+ std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList();
+ std::shared_ptr<OTableRow> pRow;
+ tools::Long nIndex;
+
+ // delete inserted keys
+ for( nIndex = m_aInsKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() )
+ {
+ OSL_ENSURE(nIndex <= static_cast<tools::Long>(pRowList->size()),"Index for undo isn't valid!");
+ pRow = (*pRowList)[nIndex];
+ pRow->SetPrimaryKey( false );
+ }
+
+ // restore deleted keys
+ for( nIndex = m_aDelKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() )
+ {
+ OSL_ENSURE(nIndex <= static_cast<tools::Long>(pRowList->size()),"Index for undo isn't valid!");
+ pRow = (*pRowList)[nIndex];
+ pRow->SetPrimaryKey( true );
+ }
+
+ m_pEditorCtrl->InvalidateHandleColumn();
+ OTableEditorUndoAct::Undo();
+}
+
+void OPrimKeyUndoAct::Redo()
+{
+ std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList();
+ tools::Long nIndex;
+
+ // delete the deleted keys
+ for( nIndex = m_aDelKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() )
+ (*pRowList)[nIndex]->SetPrimaryKey( false );
+
+ // restore the inserted keys
+ for( nIndex = m_aInsKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() )
+ (*pRowList)[nIndex]->SetPrimaryKey( true );
+
+ m_pEditorCtrl->InvalidateHandleColumn();
+ OTableEditorUndoAct::Redo();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/tabledesign/TableUndo.hxx b/dbaccess/source/ui/tabledesign/TableUndo.hxx
new file mode 100644
index 000000000..5ad23b84f
--- /dev/null
+++ b/dbaccess/source/ui/tabledesign/TableUndo.hxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <GeneralUndo.hxx>
+#include <tools/multisel.hxx>
+
+#include <vector>
+
+#include <com/sun/star/uno/Any.h>
+#include <TypeInfo.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace dbaui
+{
+ class OTableRowView;
+ class OTableRow;
+ class OTableDesignUndoAct : public OCommentUndoAction
+ {
+ protected:
+ VclPtr<OTableRowView> m_pTabDgnCtrl;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ public:
+ OTableDesignUndoAct(OTableRowView* pOwner, TranslateId pCommentID);
+ virtual ~OTableDesignUndoAct() override;
+ };
+
+ class OTableEditorCtrl;
+ class OTableEditorUndoAct : public OTableDesignUndoAct
+ {
+ protected:
+ VclPtr<OTableEditorCtrl> pTabEdCtrl;
+
+ public:
+ OTableEditorUndoAct(OTableEditorCtrl* pOwner, TranslateId pCommentID);
+ virtual ~OTableEditorUndoAct() override;
+ };
+
+ class OTableDesignCellUndoAct final : public OTableDesignUndoAct
+ {
+ sal_uInt16 m_nCol;
+ sal_Int32 m_nRow;
+ css::uno::Any m_sOldText;
+ css::uno::Any m_sNewText;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ public:
+ OTableDesignCellUndoAct( OTableRowView* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn );
+ virtual ~OTableDesignCellUndoAct() override;
+ };
+
+ class OTableEditorTypeSelUndoAct final : public OTableEditorUndoAct
+ {
+ sal_uInt16 m_nCol;
+ sal_Int32 m_nRow;
+ TOTypeInfoSP m_pOldType;
+ TOTypeInfoSP m_pNewType;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ public:
+ OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType );
+ virtual ~OTableEditorTypeSelUndoAct() override;
+ };
+
+ class OTableEditorDelUndoAct final : public OTableEditorUndoAct
+ {
+ std::vector< std::shared_ptr<OTableRow> > m_aDeletedRows;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ public:
+ explicit OTableEditorDelUndoAct( OTableEditorCtrl* pOwner );
+ virtual ~OTableEditorDelUndoAct() override;
+ };
+
+ class OTableEditorInsUndoAct final : public OTableEditorUndoAct
+ {
+ std::vector< std::shared_ptr<OTableRow> > m_vInsertedRows;
+ tools::Long m_nInsPos;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ public:
+ OTableEditorInsUndoAct( OTableEditorCtrl* pOwner,
+ tools::Long nInsertPosition,
+ std::vector< std::shared_ptr<OTableRow> >&& _vInsertedRows);
+ virtual ~OTableEditorInsUndoAct() override;
+ };
+
+ class OTableEditorInsNewUndoAct final : public OTableEditorUndoAct
+ {
+ sal_Int32 m_nInsPos;
+ sal_Int32 m_nInsRows;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ public:
+ OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nInsertPosition, sal_Int32 nInsertedRows );
+ virtual ~OTableEditorInsNewUndoAct() override;
+ };
+
+ class OPrimKeyUndoAct final : public OTableEditorUndoAct
+ {
+ MultiSelection m_aDelKeys,
+ m_aInsKeys;
+ VclPtr<OTableEditorCtrl> m_pEditorCtrl;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ public:
+ OPrimKeyUndoAct( OTableEditorCtrl* pOwner, const MultiSelection& aDeletedKeys, const MultiSelection& aInsertedKeys );
+ virtual ~OPrimKeyUndoAct() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx b/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx
new file mode 100644
index 000000000..3d24cfc24
--- /dev/null
+++ b/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <unoadmin.hxx>
+#include <advancedsettingsdlg.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <vcl/svapp.hxx>
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+ namespace {
+
+ // OAdvancedSettingsDialog
+ class OAdvancedSettingsDialog
+ :public ODatabaseAdministrationDialog
+ ,public ::comphelper::OPropertyArrayUsageHelper< OAdvancedSettingsDialog >
+ {
+
+ public:
+ explicit OAdvancedSettingsDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ protected:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ };
+
+ }
+
+ OAdvancedSettingsDialog::OAdvancedSettingsDialog(const Reference< XComponentContext >& _rxORB)
+ :ODatabaseAdministrationDialog(_rxORB)
+ {
+ }
+ Sequence<sal_Int8> SAL_CALL OAdvancedSettingsDialog::getImplementationId( )
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+ OUString SAL_CALL OAdvancedSettingsDialog::getImplementationName()
+ {
+ return "org.openoffice.comp.dbu.OAdvancedSettingsDialog";
+ }
+
+ css::uno::Sequence<OUString> SAL_CALL OAdvancedSettingsDialog::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.AdvancedDatabaseSettingsDialog" };
+ }
+
+ Reference<XPropertySetInfo> SAL_CALL OAdvancedSettingsDialog::getPropertySetInfo()
+ {
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+ ::cppu::IPropertyArrayHelper& OAdvancedSettingsDialog::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OAdvancedSettingsDialog::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ std::unique_ptr<weld::DialogController> OAdvancedSettingsDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ return std::make_unique<AdvancedSettingsDialog>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(),
+ m_aContext, m_aInitialSelection);
+ }
+
+} // namespace dbaui
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OAdvancedSettingsDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OAdvancedSettingsDialog(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/ColumnControl.cxx b/dbaccess/source/ui/uno/ColumnControl.cxx
new file mode 100644
index 000000000..9295b9954
--- /dev/null
+++ b/dbaccess/source/ui/uno/ColumnControl.cxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ColumnControl.hxx"
+#include "ColumnPeer.hxx"
+#include <strings.hxx>
+#include <vcl/window.hxx>
+#include <com/sun/star/awt/PosSize.hpp>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbu_OColumnControl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OColumnControl(context));
+}
+
+namespace dbaui
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+
+OColumnControl::OColumnControl(const Reference<XComponentContext>& rxContext)
+ : m_xContext(rxContext)
+{
+}
+
+OUString SAL_CALL OColumnControl::getImplementationName()
+{
+ return SERVICE_CONTROLDEFAULT;
+}
+sal_Bool SAL_CALL OColumnControl::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OColumnControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.awt.UnoControl","com.sun.star.sdb.ColumnDescriptorControl" };
+}
+
+OUString OColumnControl::GetComponentServiceName() const
+{
+ return "com.sun.star.sdb.ColumnDescriptorControl";
+}
+
+void SAL_CALL OColumnControl::createPeer(const Reference< XToolkit >& /*rToolkit*/, const Reference< XWindowPeer >& rParentPeer)
+{
+ ::osl::ClearableMutexGuard aGuard( GetMutex() );
+ if ( getPeer().is() )
+ return;
+
+ mbCreatingPeer = true;
+
+ vcl::Window* pParentWin = nullptr;
+ if (rParentPeer.is())
+ {
+ VCLXWindow* pParent = comphelper::getFromUnoTunnel<VCLXWindow>(rParentPeer);
+ if (pParent)
+ pParentWin = pParent->GetWindow();
+ }
+
+ rtl::Reference<OColumnPeer> pPeer = new OColumnPeer( pParentWin, m_xContext );
+ OSL_ENSURE(pPeer != nullptr, "FmXGridControl::createPeer : imp_CreatePeer didn't return a peer !");
+ setPeer( pPeer );
+
+ UnoControlComponentInfos aComponentInfos(maComponentInfos);
+ Reference< XGraphics > xGraphics( mxGraphics );
+ Reference< XView > xV(getPeer(), UNO_QUERY);
+ Reference< XWindow > xW(getPeer(), UNO_QUERY);
+
+ aGuard.clear();
+
+ updateFromModel();
+
+ xV->setZoom( aComponentInfos.nZoomX, aComponentInfos.nZoomY );
+ setPosSize( aComponentInfos.nX, aComponentInfos.nY, aComponentInfos.nWidth, aComponentInfos.nHeight, css::awt::PosSize::POSSIZE );
+
+ Reference<XPropertySet> xProp(getModel(), UNO_QUERY);
+ if ( xProp.is() )
+ {
+ Reference<XConnection> xCon(xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
+ pPeer->setConnection(xCon);
+ Reference<XPropertySet> xColumn(xProp->getPropertyValue(PROPERTY_COLUMN),UNO_QUERY);
+ pPeer->setColumn(xColumn);
+ sal_Int32 nWidth = 50;
+ xProp->getPropertyValue(PROPERTY_EDIT_WIDTH) >>= nWidth;
+ pPeer->setEditWidth(nWidth);
+ }
+
+ if (aComponentInfos.bVisible)
+ xW->setVisible(true);
+
+ if (!aComponentInfos.bEnable)
+ xW->setEnable(false);
+
+ if (maWindowListeners.getLength())
+ xW->addWindowListener( &maWindowListeners );
+
+ if (maFocusListeners.getLength())
+ xW->addFocusListener( &maFocusListeners );
+
+ if (maKeyListeners.getLength())
+ xW->addKeyListener( &maKeyListeners );
+
+ if (maMouseListeners.getLength())
+ xW->addMouseListener( &maMouseListeners );
+
+ if (maMouseMotionListeners.getLength())
+ xW->addMouseMotionListener( &maMouseMotionListeners );
+
+ if (maPaintListeners.getLength())
+ xW->addPaintListener( &maPaintListeners );
+
+ Reference< css::awt::XView > xPeerView(getPeer(), UNO_QUERY);
+ xPeerView->setZoom( maComponentInfos.nZoomX, maComponentInfos.nZoomY );
+ xPeerView->setGraphics( xGraphics );
+
+ mbCreatingPeer = false;
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/ColumnControl.hxx b/dbaccess/source/ui/uno/ColumnControl.hxx
new file mode 100644
index 000000000..63f066512
--- /dev/null
+++ b/dbaccess/source/ui/uno/ColumnControl.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/CommonTools.hxx>
+#include <toolkit/controls/unocontrol.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace dbaui
+{
+ class OColumnControl : public UnoControl
+ {
+ private:
+ css::uno::Reference< css::uno::XComponentContext> m_xContext;
+ public:
+ explicit OColumnControl(const css::uno::Reference< css::uno::XComponentContext>& rxContext);
+
+ // UnoControl
+ virtual OUString GetComponentServiceName() const override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // css::awt::XControl
+ virtual void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit >& _rToolkit, const css::uno::Reference< css::awt::XWindowPeer >& Parent) override;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/ColumnModel.cxx b/dbaccess/source/ui/uno/ColumnModel.cxx
new file mode 100644
index 000000000..de83b6176
--- /dev/null
+++ b/dbaccess/source/ui/uno/ColumnModel.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ColumnModel.hxx"
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbu_OColumnControlModel_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OColumnControlModel());
+}
+
+namespace dbaui
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+
+OColumnControlModel::OColumnControlModel()
+ :OPropertyContainer(m_aBHelper)
+ ,OColumnControlModel_BASE(m_aMutex)
+ ,m_sDefaultControl(SERVICE_CONTROLDEFAULT)
+ ,m_bEnable(true)
+ ,m_nBorder(0)
+ ,m_nWidth(50)
+{
+ registerProperties();
+}
+
+OColumnControlModel::OColumnControlModel(const OColumnControlModel* _pSource)
+ :OPropertyContainer(m_aBHelper)
+ ,OColumnControlModel_BASE(m_aMutex)
+ ,m_sDefaultControl(_pSource->m_sDefaultControl)
+ ,m_aTabStop(_pSource->m_aTabStop)
+ ,m_bEnable(_pSource->m_bEnable)
+ ,m_nBorder(_pSource->m_nBorder)
+ ,m_nWidth(50)
+{
+ registerProperties();
+}
+
+OColumnControlModel::~OColumnControlModel()
+{
+ if ( !OColumnControlModel_BASE::rBHelper.bDisposed && !OColumnControlModel_BASE::rBHelper.bInDispose )
+ {
+ acquire();
+ dispose();
+ }
+}
+
+void OColumnControlModel::registerProperties()
+{
+ registerProperty( PROPERTY_ACTIVE_CONNECTION, PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::TRANSIENT | PropertyAttribute::BOUND,
+ &m_xConnection, cppu::UnoType<decltype(m_xConnection)>::get() );
+ Any a;
+ a <<= m_xColumn;
+ registerProperty( PROPERTY_COLUMN, PROPERTY_ID_COLUMN, PropertyAttribute::TRANSIENT | PropertyAttribute::BOUND,
+ &m_xColumn, cppu::UnoType<decltype(m_xColumn)>::get() );
+
+ registerMayBeVoidProperty( PROPERTY_TABSTOP, PROPERTY_ID_TABSTOP, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &m_aTabStop, ::cppu::UnoType<sal_Int16>::get() );
+ registerProperty( PROPERTY_DEFAULTCONTROL, PROPERTY_ID_DEFAULTCONTROL, PropertyAttribute::BOUND,
+ &m_sDefaultControl, cppu::UnoType<decltype(m_sDefaultControl)>::get() );
+ registerProperty( PROPERTY_ENABLED, PROPERTY_ID_ENABLED, PropertyAttribute::BOUND,
+ &m_bEnable, cppu::UnoType<decltype(m_bEnable)>::get() );
+ registerProperty( PROPERTY_BORDER, PROPERTY_ID_BORDER, PropertyAttribute::BOUND,
+ &m_nBorder, cppu::UnoType<decltype(m_nBorder)>::get() );
+ registerProperty( PROPERTY_EDIT_WIDTH, PROPERTY_ID_EDIT_WIDTH, PropertyAttribute::BOUND,
+ &m_nWidth, cppu::UnoType<decltype(m_nWidth)>::get() );
+}
+
+// XCloneable
+Reference< XCloneable > SAL_CALL OColumnControlModel::createClone( )
+{
+ return new OColumnControlModel( this );
+}
+
+css::uno::Sequence<sal_Int8> OColumnControlModel::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OColumnControlModel::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OColumnControlModel_BASE::getTypes( ),
+ OPropertyContainer::getTypes( )
+ );
+}
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OColumnControlModel::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+::cppu::IPropertyArrayHelper& OColumnControlModel::getInfoHelper()
+{
+ return *OColumnControlModel::getArrayHelper();
+}
+::cppu::IPropertyArrayHelper* OColumnControlModel::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+OUString SAL_CALL OColumnControlModel::getImplementationName()
+{
+ return "com.sun.star.comp.dbu.OColumnControlModel";
+}
+sal_Bool SAL_CALL OColumnControlModel::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OColumnControlModel::getSupportedServiceNames()
+{
+ return { "com.sun.star.awt.UnoControlModel","com.sun.star.sdb.ColumnDescriptorControlModel" };
+}
+IMPLEMENT_FORWARD_REFCOUNT( OColumnControlModel, OColumnControlModel_BASE )
+Any SAL_CALL OColumnControlModel::queryInterface( const Type& _rType )
+{
+ return OColumnControlModel_BASE::queryInterface( _rType );
+}
+
+// css::XAggregation
+Any SAL_CALL OColumnControlModel::queryAggregation( const Type& rType )
+{
+ Any aRet(OColumnControlModel_BASE::queryAggregation(rType));
+ if (!aRet.hasValue())
+ aRet = comphelper::OPropertyContainer::queryInterface(rType);
+ return aRet;
+}
+
+OUString SAL_CALL OColumnControlModel::getServiceName()
+{
+ return OUString();
+}
+
+void OColumnControlModel::write(const Reference<XObjectOutputStream>& /*_rxOutStream*/)
+{
+ // TODO
+}
+
+void OColumnControlModel::read(const Reference<XObjectInputStream>& /*_rxInStream*/)
+{
+ // TODO
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/ColumnModel.hxx b/dbaccess/source/ui/uno/ColumnModel.hxx
new file mode 100644
index 000000000..400d03652
--- /dev/null
+++ b/dbaccess/source/ui/uno/ColumnModel.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/io/XPersistObject.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/compbase4.hxx>
+#include <connectivity/CommonTools.hxx>
+
+namespace dbaui
+{
+
+// OColumnControlModel
+typedef ::cppu::WeakAggComponentImplHelper4 < css::awt::XControlModel
+ , css::lang::XServiceInfo
+ , css::util::XCloneable
+ , css::io::XPersistObject
+ > OColumnControlModel_BASE;
+
+class OColumnControlModel;
+
+class OColumnControlModel : public ::comphelper::OMutexAndBroadcastHelper
+ ,public ::comphelper::OPropertyContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper< OColumnControlModel >
+ ,public OColumnControlModel_BASE
+{
+
+// [properties]
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference< css::beans::XPropertySet > m_xColumn;
+ OUString m_sDefaultControl;
+ css::uno::Any m_aTabStop;
+ bool m_bEnable;
+ sal_Int16 m_nBorder;
+ sal_Int32 m_nWidth;
+// [properties]
+
+ void registerProperties();
+protected:
+
+ virtual ~OColumnControlModel() override;
+ OColumnControlModel(const OColumnControlModel* _pSource);
+public:
+ explicit OColumnControlModel();
+
+// UNO binding
+ DECLARE_XINTERFACE( )
+
+// css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XAggregation
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& aType ) override;
+
+// css::io::XPersistObject
+ virtual OUString SAL_CALL getServiceName() override;
+ virtual void SAL_CALL write(const css::uno::Reference< css::io::XObjectOutputStream>& _rxOutStream) override;
+ virtual void SAL_CALL read(const css::uno::Reference< css::io::XObjectInputStream>& _rxInStream) override;
+
+// OPropertyArrayUsageHelper
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+
+ virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/ColumnPeer.cxx b/dbaccess/source/ui/uno/ColumnPeer.cxx
new file mode 100644
index 000000000..48f5fbce5
--- /dev/null
+++ b/dbaccess/source/ui/uno/ColumnPeer.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ColumnPeer.hxx"
+#include <ColumnControlWindow.hxx>
+#include <vcl/svapp.hxx>
+#include <strings.hxx>
+#include <FieldDescriptions.hxx>
+
+namespace dbaui
+{
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+
+OColumnPeer::OColumnPeer(vcl::Window* _pParent,const Reference<XComponentContext>& _rxContext)
+ :m_pActFieldDescr(nullptr)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ VclPtrInstance<OColumnControlTopLevel> pFieldControl(_pParent, _rxContext);
+ pFieldControl->SetComponentInterface(this);
+ pFieldControl->Show();
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+void OColumnPeer::setEditWidth(sal_Int32 _nWidth)
+{
+ SolarMutexGuard aGuard;
+ VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>();
+ if ( pFieldControl )
+ pFieldControl->GetControl().setEditWidth(_nWidth);
+}
+
+void OColumnPeer::setColumn(const Reference< XPropertySet>& _xColumn)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>();
+ if ( !pFieldControl )
+ return;
+
+ OColumnControlWindow& rControl = pFieldControl->GetControl();
+
+ if ( m_pActFieldDescr )
+ {
+ delete m_pActFieldDescr;
+ m_pActFieldDescr = nullptr;
+ }
+ if ( _xColumn.is() )
+ {
+ sal_Int32 nType = 0;
+ sal_Int32 nScale = 0;
+ sal_Int32 nPrecision = 0;
+ bool bAutoIncrement = false;
+ OUString sTypeName;
+
+ try
+ {
+ // get the properties from the column
+ _xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName;
+ _xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ _xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale;
+ _xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision;
+ _xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement;
+ }
+ catch(const Exception&)
+ {
+ }
+
+ m_pActFieldDescr = new OFieldDescription(_xColumn,true);
+ // search for type
+ bool bForce;
+ TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(*rControl.getTypeInfo(),nType,sTypeName,"x",nPrecision,nScale,bAutoIncrement,bForce);
+ if ( !pTypeInfo )
+ pTypeInfo = rControl.getDefaultTyp();
+
+ m_pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false);
+ m_xColumn = _xColumn;
+ }
+ rControl.DisplayData(m_pActFieldDescr);
+}
+
+void OColumnPeer::setConnection(const Reference< XConnection>& _xCon)
+{
+ SolarMutexGuard aGuard;
+ VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>();
+ if ( pFieldControl )
+ pFieldControl->GetControl().setConnection(_xCon);
+}
+
+void OColumnPeer::setProperty( const OUString& _rPropertyName, const Any& Value)
+{
+ SolarMutexGuard aGuard;
+
+ if (_rPropertyName == PROPERTY_COLUMN)
+ {
+ Reference<XPropertySet> xProp(Value,UNO_QUERY);
+ setColumn(xProp);
+ }
+ else if (_rPropertyName == PROPERTY_ACTIVE_CONNECTION)
+ {
+ Reference<XConnection> xCon(Value,UNO_QUERY);
+ setConnection(xCon);
+ }
+ else
+ VCLXWindow::setProperty(_rPropertyName,Value);
+}
+
+Any OColumnPeer::getProperty( const OUString& _rPropertyName )
+{
+ Any aProp;
+ VclPtr<OColumnControlTopLevel> pFieldControl = GetAs<OColumnControlTopLevel>();
+ if (pFieldControl && _rPropertyName == PROPERTY_COLUMN)
+ {
+ aProp <<= m_xColumn;
+ }
+ else if (pFieldControl && _rPropertyName == PROPERTY_ACTIVE_CONNECTION)
+ {
+ aProp <<= pFieldControl->GetControl().getConnection();
+ }
+ else
+ aProp = VCLXWindow::getProperty(_rPropertyName);
+ return aProp;
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/ColumnPeer.hxx b/dbaccess/source/ui/uno/ColumnPeer.hxx
new file mode 100644
index 000000000..8a92a40cd
--- /dev/null
+++ b/dbaccess/source/ui/uno/ColumnPeer.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <toolkit/awt/vclxwindow.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaui
+{
+ class OFieldDescription;
+ class OColumnPeer : public VCLXWindow
+ {
+ OFieldDescription* m_pActFieldDescr;
+ css::uno::Reference< css::beans::XPropertySet> m_xColumn;
+ public:
+
+ OColumnPeer(vcl::Window* _pParent
+ ,const css::uno::Reference< css::uno::XComponentContext>& _rxContext);
+
+ void setColumn(const css::uno::Reference< css::beans::XPropertySet>& _xColumn);
+ void setConnection(const css::uno::Reference< css::sdbc::XConnection>& _xCon);
+ void setEditWidth(sal_Int32 _nWidth);
+ // VCLXWindow
+ virtual void SAL_CALL setProperty( const OUString& PropertyName, const css::uno::Any& Value ) override;
+ virtual css::uno::Any SAL_CALL getProperty( const OUString& PropertyName ) override;
+ };
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/DBTypeWizDlg.cxx b/dbaccess/source/ui/uno/DBTypeWizDlg.cxx
new file mode 100644
index 000000000..8c9d16596
--- /dev/null
+++ b/dbaccess/source/ui/uno/DBTypeWizDlg.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DBTypeWizDlg.hxx"
+#include <dbwiz.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace dbaui;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_ODBTypeWizDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ODBTypeWizDialog(context));
+}
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+ODBTypeWizDialog::ODBTypeWizDialog(const Reference< XComponentContext >& _rxORB)
+ :ODatabaseAdministrationDialog(_rxORB)
+{
+}
+
+Sequence<sal_Int8> SAL_CALL ODBTypeWizDialog::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString SAL_CALL ODBTypeWizDialog::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.ODBTypeWizDialog";
+}
+
+css::uno::Sequence<OUString> SAL_CALL ODBTypeWizDialog::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.DataSourceTypeChangeDialog" };
+}
+
+Reference<XPropertySetInfo> SAL_CALL ODBTypeWizDialog::getPropertySetInfo()
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+::cppu::IPropertyArrayHelper& ODBTypeWizDialog::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* ODBTypeWizDialog::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+std::unique_ptr<weld::DialogController> ODBTypeWizDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ return std::make_unique<ODbTypeWizDialog>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/DBTypeWizDlg.hxx b/dbaccess/source/ui/uno/DBTypeWizDlg.hxx
new file mode 100644
index 000000000..093981a0e
--- /dev/null
+++ b/dbaccess/source/ui/uno/DBTypeWizDlg.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unoadmin.hxx>
+
+#include <comphelper/proparrhlp.hxx>
+
+namespace dbaui
+{
+class ODBTypeWizDialog final
+ :public ODatabaseAdministrationDialog
+ ,public ::comphelper::OPropertyArrayUsageHelper< ODBTypeWizDialog >
+{
+public:
+
+ explicit ODBTypeWizDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+private:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx
new file mode 100644
index 000000000..63c3d6304
--- /dev/null
+++ b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DBTypeWizDlgSetup.hxx"
+#include <dbwizsetup.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <vcl/svapp.hxx>
+
+using namespace dbaui;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_ODBTypeWizDialogSetup_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ODBTypeWizDialogSetup(context));
+}
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+
+ODBTypeWizDialogSetup::ODBTypeWizDialogSetup(const Reference< XComponentContext >& _rxORB)
+ :ODatabaseAdministrationDialog(_rxORB)
+ ,m_bOpenDatabase(true)
+ ,m_bStartTableWizard(false)
+{
+ registerProperty("OpenDatabase", 3, PropertyAttribute::TRANSIENT,
+ &m_bOpenDatabase, cppu::UnoType<bool>::get());
+
+ registerProperty("StartTableWizard", 4, PropertyAttribute::TRANSIENT,
+ &m_bStartTableWizard, cppu::UnoType<bool>::get());
+}
+
+Sequence<sal_Int8> SAL_CALL ODBTypeWizDialogSetup::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString SAL_CALL ODBTypeWizDialogSetup::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.ODBTypeWizDialogSetup";
+}
+
+css::uno::Sequence<OUString> SAL_CALL ODBTypeWizDialogSetup::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.DatabaseWizardDialog" };
+}
+
+Reference<XPropertySetInfo> SAL_CALL ODBTypeWizDialogSetup::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() );
+}
+
+::cppu::IPropertyArrayHelper& ODBTypeWizDialogSetup::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* ODBTypeWizDialogSetup::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+std::unique_ptr<weld::DialogController> ODBTypeWizDialogSetup::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ return std::make_unique<ODbTypeWizDialogSetup>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection);
+}
+
+void ODBTypeWizDialogSetup::executedDialog(sal_Int16 nExecutionResult)
+{
+ if (nExecutionResult == css::ui::dialogs::ExecutableDialogResults::OK)
+ {
+ const ODbTypeWizDialogSetup* pDialog = static_cast<ODbTypeWizDialogSetup*>(m_xDialog.get());
+ m_bOpenDatabase = pDialog->IsDatabaseDocumentToBeOpened();
+ m_bStartTableWizard = pDialog->IsTableWizardToBeStarted();
+ }
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx
new file mode 100644
index 000000000..56bd9a08a
--- /dev/null
+++ b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unoadmin.hxx>
+
+#include <comphelper/proparrhlp.hxx>
+
+namespace dbaui
+{
+class ODBTypeWizDialogSetup final
+ :public ODatabaseAdministrationDialog
+ ,public ::comphelper::OPropertyArrayUsageHelper< ODBTypeWizDialogSetup >
+{
+ bool m_bOpenDatabase;
+ bool m_bStartTableWizard;
+
+public:
+ explicit ODBTypeWizDialogSetup(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+private:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ virtual void executedDialog(sal_Int16 _nExecutionResult) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/TableFilterDlg.cxx b/dbaccess/source/ui/uno/TableFilterDlg.cxx
new file mode 100644
index 000000000..cd01f2587
--- /dev/null
+++ b/dbaccess/source/ui/uno/TableFilterDlg.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TableFilterDlg.hxx"
+#include <TablesSingleDlg.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace dbaui;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OTableFilterDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new OTableFilterDialog(context));
+}
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+OTableFilterDialog::OTableFilterDialog(const Reference< XComponentContext >& _rxORB)
+ :ODatabaseAdministrationDialog(_rxORB)
+{
+}
+
+Sequence<sal_Int8> SAL_CALL OTableFilterDialog::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString SAL_CALL OTableFilterDialog::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.OTableFilterDialog";
+}
+
+css::uno::Sequence<OUString> SAL_CALL OTableFilterDialog::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.TableFilterDialog" };
+}
+
+Reference<XPropertySetInfo> SAL_CALL OTableFilterDialog::getPropertySetInfo()
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+::cppu::IPropertyArrayHelper& OTableFilterDialog::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OTableFilterDialog::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+std::unique_ptr<weld::DialogController> OTableFilterDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ return std::make_unique<OTableSubscriptionDialog>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/TableFilterDlg.hxx b/dbaccess/source/ui/uno/TableFilterDlg.hxx
new file mode 100644
index 000000000..7c16a7f26
--- /dev/null
+++ b/dbaccess/source/ui/uno/TableFilterDlg.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unoadmin.hxx>
+
+#include <comphelper/proparrhlp.hxx>
+
+namespace dbaui
+{
+
+class OTableFilterDialog final
+ :public ODatabaseAdministrationDialog
+ ,public ::comphelper::OPropertyArrayUsageHelper< OTableFilterDialog >
+{
+
+public:
+ explicit OTableFilterDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+private:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/UserSettingsDlg.cxx b/dbaccess/source/ui/uno/UserSettingsDlg.cxx
new file mode 100644
index 000000000..7039c7396
--- /dev/null
+++ b/dbaccess/source/ui/uno/UserSettingsDlg.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "UserSettingsDlg.hxx"
+#include <UserAdminDlg.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace dbaui;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OUserSettingsDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new OUserSettingsDialog(context));
+}
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+OUserSettingsDialog::OUserSettingsDialog(const Reference< XComponentContext >& _rxORB)
+ :ODatabaseAdministrationDialog(_rxORB)
+{
+}
+
+Sequence<sal_Int8> SAL_CALL OUserSettingsDialog::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString SAL_CALL OUserSettingsDialog::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.OUserSettingsDialog";
+}
+
+css::uno::Sequence<OUString> SAL_CALL OUserSettingsDialog::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.UserAdministrationDialog" };
+}
+
+Reference<XPropertySetInfo> SAL_CALL OUserSettingsDialog::getPropertySetInfo()
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+::cppu::IPropertyArrayHelper& OUserSettingsDialog::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OUserSettingsDialog::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+std::unique_ptr<weld::DialogController> OUserSettingsDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ return std::make_unique<OUserAdminDlg>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection, m_xActiveConnection);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/UserSettingsDlg.hxx b/dbaccess/source/ui/uno/UserSettingsDlg.hxx
new file mode 100644
index 000000000..7e0780ea2
--- /dev/null
+++ b/dbaccess/source/ui/uno/UserSettingsDlg.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unoadmin.hxx>
+
+#include <comphelper/proparrhlp.hxx>
+
+namespace dbaui
+{
+// OUserSettingsDialog
+class OUserSettingsDialog final
+ :public ODatabaseAdministrationDialog
+ ,public ::comphelper::OPropertyArrayUsageHelper< OUserSettingsDialog >
+{
+
+public:
+ explicit OUserSettingsDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+private:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/admindlg.cxx b/dbaccess/source/ui/uno/admindlg.cxx
new file mode 100644
index 000000000..3e524372e
--- /dev/null
+++ b/dbaccess/source/ui/uno/admindlg.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "admindlg.hxx"
+#include <dbadmin.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace dbaui;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_ODatasourceAdministrationDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ODataSourcePropertyDialog(context));
+}
+
+namespace dbaui
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+
+ODataSourcePropertyDialog::ODataSourcePropertyDialog(const Reference<XComponentContext>& _rxORB)
+ : ODatabaseAdministrationDialog(_rxORB)
+{
+}
+
+Sequence<sal_Int8> SAL_CALL ODataSourcePropertyDialog::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString SAL_CALL ODataSourcePropertyDialog::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.ODatasourceAdministrationDialog";
+}
+
+css::uno::Sequence<OUString> SAL_CALL ODataSourcePropertyDialog::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.DatasourceAdministrationDialog" };
+}
+
+Reference<XPropertySetInfo> SAL_CALL ODataSourcePropertyDialog::getPropertySetInfo()
+{
+ Reference<XPropertySetInfo> xInfo(createPropertySetInfo(getInfoHelper()));
+ return xInfo;
+}
+
+::cppu::IPropertyArrayHelper& ODataSourcePropertyDialog::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* ODataSourcePropertyDialog::createArrayHelper() const
+{
+ Sequence<Property> aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+std::unique_ptr<weld::DialogController>
+ODataSourcePropertyDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ std::unique_ptr<ODbAdminDialog> xDialog(new ODbAdminDialog(
+ Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext));
+
+ // the initial selection
+ if (m_aInitialSelection.hasValue())
+ xDialog->selectDataSource(m_aInitialSelection);
+
+ return xDialog;
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/admindlg.hxx b/dbaccess/source/ui/uno/admindlg.hxx
new file mode 100644
index 000000000..62faabf64
--- /dev/null
+++ b/dbaccess/source/ui/uno/admindlg.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unoadmin.hxx>
+
+#include <comphelper/proparrhlp.hxx>
+
+namespace dbaui
+{
+class ODataSourcePropertyDialog final
+ :public ODatabaseAdministrationDialog
+ ,public ::comphelper::OPropertyArrayUsageHelper< ODataSourcePropertyDialog >
+{
+public:
+
+ explicit ODataSourcePropertyDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+private:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+};
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/composerdialogs.cxx b/dbaccess/source/ui/uno/composerdialogs.cxx
new file mode 100644
index 000000000..f4b8fe24a
--- /dev/null
+++ b/dbaccess/source/ui/uno/composerdialogs.cxx
@@ -0,0 +1,270 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "composerdialogs.hxx"
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <queryfilter.hxx>
+#include <queryorder.hxx>
+#include <strings.hxx>
+#include <connectivity/dbtools.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_uno_comp_sdb_RowsetOrderDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::RowsetOrderDialog(context));
+}
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_uno_comp_sdb_RowsetFilterDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::RowsetFilterDialog(context));
+}
+
+namespace dbaui
+{
+
+#define PROPERTY_ID_QUERYCOMPOSER 100
+#define PROPERTY_ID_ROWSET 101
+
+constexpr OUStringLiteral PROPERTY_QUERYCOMPOSER = u"QueryComposer";
+constexpr OUStringLiteral PROPERTY_ROWSET = u"RowSet";
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+
+ // ComposerDialog
+ ComposerDialog::ComposerDialog(const Reference< XComponentContext >& _rxORB)
+ :OGenericUnoDialog( _rxORB )
+ {
+
+ registerProperty( PROPERTY_QUERYCOMPOSER, PROPERTY_ID_QUERYCOMPOSER, PropertyAttribute::TRANSIENT,
+ &m_xComposer, cppu::UnoType<decltype(m_xComposer)>::get() );
+ registerProperty( PROPERTY_ROWSET, PROPERTY_ID_ROWSET, PropertyAttribute::TRANSIENT,
+ &m_xRowSet, cppu::UnoType<decltype(m_xRowSet)>::get() );
+ }
+
+ ComposerDialog::~ComposerDialog()
+ {
+
+ }
+
+ css::uno::Sequence<sal_Int8> ComposerDialog::getImplementationId()
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+ css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ComposerDialog::getPropertySetInfo()
+ {
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+ ::cppu::IPropertyArrayHelper& ComposerDialog::getInfoHelper()
+ {
+ return *ComposerDialog::getArrayHelper();
+ }
+ ::cppu::IPropertyArrayHelper* ComposerDialog::createArrayHelper( ) const
+ {
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ std::unique_ptr<weld::DialogController> ComposerDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ // obtain all the objects needed for the dialog
+ Reference< XConnection > xConnection;
+ Reference< XNameAccess > xColumns;
+ try
+ {
+ // the connection the row set is working with
+ if ( !::dbtools::isEmbeddedInDatabase( m_xRowSet, xConnection ) )
+ {
+ Reference< XPropertySet > xRowsetProps( m_xRowSet, UNO_QUERY );
+ if ( xRowsetProps.is() )
+ xRowsetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
+ }
+
+ // fallback: if there is a connection and thus a row set, but no composer, create one
+ if ( xConnection.is() && !m_xComposer.is() )
+ m_xComposer = ::dbtools::getCurrentSettingsComposer( Reference< XPropertySet >( m_xRowSet, UNO_QUERY ), m_aContext, rParent );
+
+ // the columns of the row set
+ Reference< XColumnsSupplier > xSuppColumns( m_xRowSet, UNO_QUERY );
+ if ( xSuppColumns.is() )
+ xColumns = xSuppColumns->getColumns();
+
+ if ( !xColumns.is() || !xColumns->hasElements() )
+ { // perhaps the composer can supply us with columns? This is necessary for cases
+ // where the dialog is invoked for a rowset which is not yet loaded
+ // #i22878#
+ xSuppColumns.set(m_xComposer, css::uno::UNO_QUERY);
+ if ( xSuppColumns.is() )
+ xColumns = xSuppColumns->getColumns();
+ }
+
+ OSL_ENSURE( xColumns.is() && xColumns->hasElements(), "ComposerDialog::createDialog: not much fun without any columns!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( !xConnection.is() || !xColumns.is() || !m_xComposer.is() )
+ {
+ // can't create the dialog if I have improper settings
+ return nullptr;
+ }
+
+ return createComposerDialog(Application::GetFrameWeld(rParent), xConnection, xColumns);
+ }
+
+ // RowsetFilterDialog
+ RowsetFilterDialog::RowsetFilterDialog( const Reference< XComponentContext >& _rxORB )
+ :ComposerDialog( _rxORB )
+ {
+ }
+
+ OUString SAL_CALL RowsetFilterDialog::getImplementationName()
+ {
+ return "com.sun.star.uno.comp.sdb.RowsetFilterDialog";
+ }
+ sal_Bool SAL_CALL RowsetFilterDialog::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+ css::uno::Sequence< OUString > SAL_CALL RowsetFilterDialog::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.FilterDialog" };
+ }
+
+ std::unique_ptr<weld::GenericDialogController> RowsetFilterDialog::createComposerDialog(weld::Window* _pParent, const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxColumns )
+ {
+ return std::make_unique<DlgFilterCrit>(_pParent, m_aContext, _rxConnection, m_xComposer, _rxColumns);
+ }
+
+ void SAL_CALL RowsetFilterDialog::initialize( const Sequence< Any >& aArguments )
+ {
+ if( aArguments.getLength() == 3 )
+ {
+ // this is the FilterDialog::createWithQuery method
+ Reference<css::sdb::XSingleSelectQueryComposer> xQueryComposer;
+ aArguments[0] >>= xQueryComposer;
+ Reference<css::sdbc::XRowSet> xRowSet;
+ aArguments[1] >>= xRowSet;
+ Reference<css::awt::XWindow> xParentWindow;
+ aArguments[2] >>= xParentWindow;
+ setPropertyValue( "QueryComposer", Any( xQueryComposer ) );
+ setPropertyValue( "RowSet", Any( xRowSet ) );
+ setPropertyValue( "ParentWindow", Any( xParentWindow ) );
+ }
+ else
+ ComposerDialog::initialize(aArguments);
+ }
+
+ void RowsetFilterDialog::executedDialog( sal_Int16 _nExecutionResult )
+ {
+ ComposerDialog::executedDialog( _nExecutionResult );
+
+ if ( _nExecutionResult && m_xDialog )
+ static_cast<DlgFilterCrit*>(m_xDialog.get())->BuildWherePart();
+ }
+
+ // RowsetOrderDialog
+ RowsetOrderDialog::RowsetOrderDialog( const Reference< XComponentContext >& _rxORB )
+ :ComposerDialog( _rxORB )
+ {
+ }
+
+ OUString SAL_CALL RowsetOrderDialog::getImplementationName()
+ {
+ return "com.sun.star.uno.comp.sdb.RowsetOrderDialog";
+ }
+ sal_Bool SAL_CALL RowsetOrderDialog::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+ css::uno::Sequence< OUString > SAL_CALL RowsetOrderDialog::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.OrderDialog" };
+ }
+
+ std::unique_ptr<weld::GenericDialogController> RowsetOrderDialog::createComposerDialog(weld::Window* pParent, const Reference< XConnection >& rxConnection, const Reference< XNameAccess >& rxColumns)
+ {
+ return std::make_unique<DlgOrderCrit>(pParent, rxConnection, m_xComposer, rxColumns);
+ }
+
+ void SAL_CALL RowsetOrderDialog::initialize( const Sequence< Any >& aArguments )
+ {
+ if (aArguments.getLength() == 2 || aArguments.getLength() == 3)
+ {
+ Reference<css::sdb::XSingleSelectQueryComposer> xQueryComposer;
+ aArguments[0] >>= xQueryComposer;
+ Reference<css::beans::XPropertySet> xRowSet;
+ aArguments[1] >>= xRowSet;
+ setPropertyValue( "QueryComposer", Any( xQueryComposer ) );
+ setPropertyValue( "RowSet", Any( xRowSet ) );
+ if (aArguments.getLength() == 3)
+ {
+ Reference<css::awt::XWindow> xParentWindow;
+ aArguments[2] >>= xParentWindow;
+ setPropertyValue("ParentWindow", Any(xParentWindow));
+ }
+ }
+ else
+ ComposerDialog::initialize(aArguments);
+ }
+
+ void RowsetOrderDialog::executedDialog( sal_Int16 _nExecutionResult )
+ {
+ ComposerDialog::executedDialog( _nExecutionResult );
+
+ if ( !m_xDialog )
+ return;
+
+ if ( _nExecutionResult )
+ static_cast<DlgOrderCrit*>(m_xDialog.get())->BuildOrderPart();
+ else if ( m_xComposer.is() )
+ m_xComposer->setOrder(static_cast<DlgOrderCrit*>(m_xDialog.get())->GetOriginalOrder());
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/composerdialogs.hxx b/dbaccess/source/ui/uno/composerdialogs.hxx
new file mode 100644
index 000000000..4e71b1c64
--- /dev/null
+++ b/dbaccess/source/ui/uno/composerdialogs.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+
+#include <comphelper/proparrhlp.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <svtools/genericunodialog.hxx>
+
+namespace dbaui
+{
+
+ // ComposerDialog
+ class ComposerDialog;
+ typedef ::comphelper::OPropertyArrayUsageHelper< ComposerDialog > ComposerDialog_PBASE;
+
+ class ComposerDialog
+ :public svt::OGenericUnoDialog
+ ,public ComposerDialog_PBASE
+ {
+ protected:
+ // <properties>
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer >
+ m_xComposer;
+ css::uno::Reference< css::sdbc::XRowSet >
+ m_xRowSet;
+ // </properties>
+
+ protected:
+ explicit ComposerDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+ virtual ~ComposerDialog() override;
+
+ public:
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+ protected:
+ // own overridables
+ virtual std::unique_ptr<weld::GenericDialogController> createComposerDialog(
+ weld::Window* _pParent,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::container::XNameAccess >& _rxColumns
+ ) = 0;
+
+ private:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ };
+
+ // RowsetFilterDialog
+ class RowsetFilterDialog : public ComposerDialog
+ {
+ public:
+ explicit RowsetFilterDialog(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ );
+
+ DECLARE_SERVICE_INFO();
+
+ protected:
+ // own overridables
+ virtual std::unique_ptr<weld::GenericDialogController> createComposerDialog(
+ weld::Window* _pParent,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::container::XNameAccess >& _rxColumns
+ ) override;
+
+ // OGenericUnoDialog overridables
+ virtual void executedDialog( sal_Int16 _nExecutionResult ) override;
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ };
+
+ // RowsetOrderDialog
+ class RowsetOrderDialog : public ComposerDialog
+ {
+ public:
+ explicit RowsetOrderDialog(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB
+ );
+
+ DECLARE_SERVICE_INFO();
+
+ protected:
+ // own overridables
+ virtual std::unique_ptr<weld::GenericDialogController> createComposerDialog(
+ weld::Window* _pParent,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::container::XNameAccess >& _rxColumns
+ ) override;
+
+ // OGenericUnoDialog overridables
+ virtual void executedDialog( sal_Int16 _nExecutionResult ) override;
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/copytablewizard.cxx b/dbaccess/source/ui/uno/copytablewizard.cxx
new file mode 100644
index 000000000..09ec99415
--- /dev/null
+++ b/dbaccess/source/ui/uno/copytablewizard.cxx
@@ -0,0 +1,1579 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <WCopyTable.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/application/XCopyTableWizard.hpp>
+#include <com/sun/star/sdb/application/CopyTableContinuation.hpp>
+#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
+#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
+#include <com/sun/star/lang/NotInitializedException.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/ConnectionPool.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <svtools/genericunodialog.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/sharedunocomponent.hxx>
+#include <vcl/svapp.hxx>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::sdb::application::XCopyTableWizard;
+ using ::com::sun::star::sdb::application::XCopyTableListener;
+ using ::com::sun::star::sdb::application::CopyTableRowEvent;
+ using ::com::sun::star::beans::Optional;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::ucb::AlreadyInitializedException;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::lang::NotInitializedException;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdbc::XDataSource;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::task::InteractionHandler;
+ using ::com::sun::star::task::XInteractionHandler;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::sdb::DatabaseContext;
+ using ::com::sun::star::sdb::XDatabaseContext;
+ using ::com::sun::star::sdb::XDocumentDataSource;
+ using ::com::sun::star::sdb::XCompletedConnection;
+ using ::com::sun::star::lang::WrappedTargetException;
+ using ::com::sun::star::sdbcx::XTablesSupplier;
+ using ::com::sun::star::sdb::XQueriesSupplier;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::sdbc::XPreparedStatement;
+ using ::com::sun::star::sdb::XSingleSelectQueryComposer;
+ using ::com::sun::star::sdbc::XDatabaseMetaData;
+ using ::com::sun::star::sdbcx::XColumnsSupplier;
+ using ::com::sun::star::sdbc::XParameters;
+ using ::com::sun::star::sdbc::XResultSet;
+ using ::com::sun::star::sdbc::XRow;
+ using ::com::sun::star::sdbcx::XRowLocate;
+ using ::com::sun::star::sdbc::XResultSetMetaDataSupplier;
+ using ::com::sun::star::sdbc::XResultSetMetaData;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::sdb::SQLContext;
+ using ::com::sun::star::sdbc::ConnectionPool;
+ using ::com::sun::star::sdbc::XDriverManager;
+ using ::com::sun::star::sdbc::DriverManager;
+ using ::com::sun::star::beans::PropertyValue;
+
+ namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
+ namespace CopyTableContinuation = ::com::sun::star::sdb::application::CopyTableContinuation;
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+
+ typedef ::utl::SharedUNOComponent< XConnection > SharedConnection;
+
+ // CopyTableWizard
+ typedef ::svt::OGenericUnoDialog CopyTableWizard_DialogBase;
+ typedef ::cppu::ImplInheritanceHelper< CopyTableWizard_DialogBase
+ , XCopyTableWizard
+ > CopyTableWizard_Base;
+
+ namespace {
+
+ class CopyTableWizard
+ :public CopyTableWizard_Base
+ ,public ::comphelper::OPropertyArrayUsageHelper< CopyTableWizard >
+ {
+ public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XCopyTableWizard
+ virtual ::sal_Int16 SAL_CALL getOperation() override;
+ virtual void SAL_CALL setOperation( ::sal_Int16 _operation ) override;
+ virtual OUString SAL_CALL getDestinationTableName() override;
+ virtual void SAL_CALL setDestinationTableName( const OUString& _destinationTableName ) override;
+ virtual Optional< OUString > SAL_CALL getCreatePrimaryKey() override;
+ virtual void SAL_CALL setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey ) override;
+ virtual sal_Bool SAL_CALL getUseHeaderLineAsColumnNames() override;
+ virtual void SAL_CALL setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames ) override;
+ virtual void SAL_CALL addCopyTableListener( const Reference< XCopyTableListener >& Listener ) override;
+ virtual void SAL_CALL removeCopyTableListener( const Reference< XCopyTableListener >& Listener ) override;
+
+ // XCopyTableWizard::XExecutableDialog
+ virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
+ virtual ::sal_Int16 SAL_CALL execute( ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XPropertySet
+ virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ public:
+ ::osl::Mutex& getMutex() { return m_aMutex; }
+ bool isInitialized() const { return m_xSourceConnection.is() && m_pSourceObject && m_xDestConnection.is(); }
+
+ explicit CopyTableWizard( const Reference< XComponentContext >& _rxORB );
+ virtual ~CopyTableWizard() override;
+
+ protected:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ virtual void executedDialog( sal_Int16 _nExecutionResult ) override;
+
+ private:
+ /// ensures our current attribute values are reflected in the dialog
+ void impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const;
+
+ /// ensures the current dialog settings are reflected in our attributes
+ void impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog );
+
+ /** returns our typed dialog
+
+ @throws css::uno::RuntimeException
+ if we don't have a dialog at the moment the method is called
+ */
+ OCopyTableWizard&
+ impl_getDialog_throw();
+
+ /** ensures the given argument sequence contains a valid data access descriptor at the given position
+ @param _rAllArgs
+ the arguments as passed to ->initialize
+ @param _nArgPos
+ the position within ->_rAllArgs which contains the data access descriptor
+ @param _out_rxConnection
+ will, upon successful return, contain the connection for the data source
+ @param _out_rxDocInteractionHandler
+ will, upon successful return, contain the interaction handler which could
+ be deduced from database document described by the descriptor, if any.
+ (It is possible that the descriptor does not allow to deduce a database document,
+ in which case <code>_out_rxDocInteractionHandler</code> will be <NULL/>.)
+ @return the data access descriptor
+ */
+ Reference< XPropertySet >
+ impl_ensureDataAccessDescriptor_throw(
+ const Sequence< Any >& _rAllArgs,
+ const sal_Int16 _nArgPos,
+ SharedConnection& _out_rxConnection,
+ Reference< XInteractionHandler >& _out_rxDocInteractionHandler
+ ) const;
+
+ /** extracts the source object (table or query) described by the given descriptor,
+ relative to m_xSourceConnection
+ */
+ std::unique_ptr< ICopyTableSourceObject >
+ impl_extractSourceObject_throw(
+ const Reference< XPropertySet >& _rxDescriptor,
+ sal_Int32& _out_rCommandType
+ ) const;
+
+ /** extracts the result set to copy records from, and the selection-related aspects, if any.
+
+ Effectively, this method extracts m_xSourceResultSet, m_aSourceSelection, and m_bSourceSelectionBookmarks.
+
+ If an inconsistent/insufficient sub set of those properties is present in the descriptor, and exception
+ is thrown.
+ */
+ void impl_extractSourceResultSet_throw(
+ const Reference< XPropertySet >& i_rDescriptor
+ );
+
+ /** checks whether the given copy source descriptor contains settings which are not
+ supported (yet)
+
+ Throws an IllegalArgumentException if the descriptor contains a valid setting, which is
+ not yet supported.
+ */
+ void impl_checkForUnsupportedSettings_throw(
+ const Reference< XPropertySet >& _rxSourceDescriptor ) const;
+
+ /** obtains the connection described by the given data access descriptor
+
+ If needed and possible, the method will ask the user, using the interaction
+ handler associated with the database described by the descriptor.
+
+ All errors are handled with the InteractionHandler associated with the data source,
+ if there is one. Else, they will be silenced (but asserted in non-product builds).
+
+ @param _rxDataSourceDescriptor
+ the data access descriptor describing the data source whose connection
+ should be obtained. Must not be <NULL/>.
+ @param _out_rxDocInteractionHandler
+ the interaction handler which could be deduced from the descriptor
+
+ @throws RuntimeException
+ if anything goes seriously wrong.
+ */
+ SharedConnection
+ impl_extractConnection_throw(
+ const Reference< XPropertySet >& _rxDataSourceDescriptor,
+ Reference< XInteractionHandler >& _out_rxDocInteractionHandler
+ ) const;
+
+ /** actually copies the table
+
+ This method is called after the dialog has been successfully executed.
+ */
+ void impl_doCopy_nothrow();
+
+ /** creates the INSERT INTO statement
+ @param _xTable The destination table.
+ */
+ OUString impl_getServerSideCopyStatement_throw( const Reference< XPropertySet >& _xTable );
+
+ /** creates the statement which, when executed, will produce the source data to copy
+
+ If the source object refers to a query which contains parameters, those parameters
+ are filled in, using an interaction handler.
+ */
+ ::utl::SharedUNOComponent< XPreparedStatement >
+ impl_createSourceStatement_throw() const;
+
+ /** copies the data rows from the given source result set to the given destination table
+ */
+ void impl_copyRows_throw(
+ const Reference< XResultSet >& _rxSourceResultSet,
+ const Reference< XPropertySet >& _rxDestTable
+ );
+
+ /** processes an error which occurred during copying
+
+ First, all listeners are ask. If a listener tells to cancel or continue copying, this is reported to the
+ method's caller. If a listener tells to ask the user, this is done, and the user's decision is
+ reported to the method's caller.
+
+ @return
+ <TRUE/> if and only if copying should be continued.
+ */
+ bool impl_processCopyError_nothrow(
+ const CopyTableRowEvent& _rEvent );
+
+private:
+ Reference<XComponentContext> m_xContext;
+
+ // attributes
+ sal_Int16 m_nOperation;
+ OUString m_sDestinationTable;
+ Optional< OUString > m_aPrimaryKeyName;
+ bool m_bUseHeaderLineAsColumnNames;
+
+ // source
+ SharedConnection m_xSourceConnection;
+ sal_Int32 m_nCommandType;
+ std::unique_ptr< ICopyTableSourceObject >
+ m_pSourceObject;
+ Reference< XResultSet > m_xSourceResultSet;
+ Sequence< Any > m_aSourceSelection;
+ bool m_bSourceSelectionBookmarks;
+
+ // destination
+ SharedConnection m_xDestConnection;
+
+ // other
+ Reference< XInteractionHandler > m_xInteractionHandler;
+ ::comphelper::OInterfaceContainerHelper3<XCopyTableListener>
+ m_aCopyTableListeners;
+ sal_Int16 m_nOverrideExecutionResult;
+ };
+
+// MethodGuard
+class CopyTableAccessGuard
+{
+public:
+ explicit CopyTableAccessGuard( CopyTableWizard& _rWizard )
+ :m_rWizard( _rWizard )
+ {
+ m_rWizard.getMutex().acquire();
+ if ( !m_rWizard.isInitialized() )
+ throw NotInitializedException();
+ }
+
+ ~CopyTableAccessGuard()
+ {
+ m_rWizard.getMutex().release();
+ }
+
+private:
+ CopyTableWizard& m_rWizard;
+};
+
+}
+
+CopyTableWizard::CopyTableWizard( const Reference< XComponentContext >& _rxORB )
+ :CopyTableWizard_Base( _rxORB )
+ ,m_xContext( _rxORB )
+ ,m_nOperation( CopyTableOperation::CopyDefinitionAndData )
+ ,m_aPrimaryKeyName( false, "ID" )
+ ,m_bUseHeaderLineAsColumnNames( true )
+ ,m_nCommandType( CommandType::COMMAND )
+ ,m_bSourceSelectionBookmarks( true )
+ ,m_aCopyTableListeners( m_aMutex )
+ ,m_nOverrideExecutionResult( -1 )
+{
+}
+
+CopyTableWizard::~CopyTableWizard()
+{
+ acquire();
+
+ // protect some members whose dtor might potentially throw
+ try { m_xSourceConnection.clear(); }
+ catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
+ try { m_xDestConnection.clear(); }
+ catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
+
+ // TODO: shouldn't we have explicit disposal support? If a listener is registered
+ // at our instance, and perhaps holds this our instance by a hard ref, then we'll never
+ // be destroyed.
+ // However, adding XComponent support to the GenericUNODialog probably requires
+ // some thinking - would it break existing clients which do not call a dispose, then?
+}
+
+OUString SAL_CALL CopyTableWizard::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.CopyTableWizard";
+}
+
+css::uno::Sequence<OUString> SAL_CALL CopyTableWizard::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.application.CopyTableWizard" };
+}
+
+Reference< XPropertySetInfo > SAL_CALL CopyTableWizard::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+::sal_Int16 SAL_CALL CopyTableWizard::getOperation()
+{
+ CopyTableAccessGuard aGuard( *this );
+ return m_nOperation;
+}
+
+void SAL_CALL CopyTableWizard::setOperation( ::sal_Int16 _operation )
+{
+ CopyTableAccessGuard aGuard( *this );
+
+ if ( ( _operation != CopyTableOperation::CopyDefinitionAndData )
+ && ( _operation != CopyTableOperation::CopyDefinitionOnly )
+ && ( _operation != CopyTableOperation::CreateAsView )
+ && ( _operation != CopyTableOperation::AppendData )
+ )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ if ( ( _operation == CopyTableOperation::CreateAsView )
+ && !OCopyTableWizard::supportsViews( m_xDestConnection )
+ )
+ throw IllegalArgumentException(
+ DBA_RES( STR_CTW_NO_VIEWS_SUPPORT ),
+ *this,
+ 1
+ );
+
+ m_nOperation = _operation;
+}
+
+OUString SAL_CALL CopyTableWizard::getDestinationTableName()
+{
+ CopyTableAccessGuard aGuard( *this );
+ return m_sDestinationTable;
+}
+
+void SAL_CALL CopyTableWizard::setDestinationTableName( const OUString& _destinationTableName )
+{
+ CopyTableAccessGuard aGuard( *this );
+ m_sDestinationTable = _destinationTableName;
+}
+
+Optional< OUString > SAL_CALL CopyTableWizard::getCreatePrimaryKey()
+{
+ CopyTableAccessGuard aGuard( *this );
+ return m_aPrimaryKeyName;
+}
+
+void SAL_CALL CopyTableWizard::setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey )
+{
+ CopyTableAccessGuard aGuard( *this );
+
+ if ( _newPrimaryKey.IsPresent && !OCopyTableWizard::supportsPrimaryKey( m_xDestConnection ) )
+ throw IllegalArgumentException(
+ DBA_RES( STR_CTW_NO_PRIMARY_KEY_SUPPORT ),
+ *this,
+ 1
+ );
+
+ m_aPrimaryKeyName = _newPrimaryKey;
+}
+
+sal_Bool SAL_CALL CopyTableWizard::getUseHeaderLineAsColumnNames()
+{
+ CopyTableAccessGuard aGuard( *this );
+ return m_bUseHeaderLineAsColumnNames;
+}
+
+void SAL_CALL CopyTableWizard::setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames )
+{
+ CopyTableAccessGuard aGuard( *this );
+ m_bUseHeaderLineAsColumnNames = _bUseHeaderLineAsColumnNames;
+}
+
+void SAL_CALL CopyTableWizard::addCopyTableListener( const Reference< XCopyTableListener >& _rxListener )
+{
+ CopyTableAccessGuard aGuard( *this );
+ if ( _rxListener.is() )
+ m_aCopyTableListeners.addInterface( _rxListener );
+}
+
+void SAL_CALL CopyTableWizard::removeCopyTableListener( const Reference< XCopyTableListener >& _rxListener )
+{
+ CopyTableAccessGuard aGuard( *this );
+ if ( _rxListener.is() )
+ m_aCopyTableListeners.removeInterface( _rxListener );
+}
+
+void SAL_CALL CopyTableWizard::setTitle( const OUString& _rTitle )
+{
+ CopyTableAccessGuard aGuard( *this );
+ CopyTableWizard_DialogBase::setTitle( _rTitle );
+}
+
+::sal_Int16 SAL_CALL CopyTableWizard::execute( )
+{
+ CopyTableAccessGuard aGuard( *this );
+
+ m_nOverrideExecutionResult = -1;
+ sal_Int16 nExecutionResult = CopyTableWizard_DialogBase::execute();
+ if ( m_nOverrideExecutionResult )
+ nExecutionResult = m_nOverrideExecutionResult;
+
+ return nExecutionResult;
+}
+
+OCopyTableWizard& CopyTableWizard::impl_getDialog_throw()
+{
+ OCopyTableWizard* pWizard = dynamic_cast<OCopyTableWizard*>(m_xDialog.get());
+ if ( !pWizard )
+ throw DisposedException( OUString(), *this );
+ return *pWizard;
+}
+
+void CopyTableWizard::impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const
+{
+ // primary key column
+ _rDialog.setCreatePrimaryKey( m_aPrimaryKeyName.IsPresent, m_aPrimaryKeyName.Value );
+ _rDialog.setUseHeaderLine(m_bUseHeaderLineAsColumnNames);
+
+ // everything else was passed at construction time already
+}
+
+void CopyTableWizard::impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog )
+{
+ m_aPrimaryKeyName.IsPresent = _rDialog.shouldCreatePrimaryKey();
+ if ( m_aPrimaryKeyName.IsPresent )
+ m_aPrimaryKeyName.Value = _rDialog.getPrimaryKeyName();
+ else
+ m_aPrimaryKeyName.Value.clear();
+
+ m_sDestinationTable = _rDialog.getName();
+
+ m_nOperation = _rDialog.getOperation();
+ m_bUseHeaderLineAsColumnNames = _rDialog.UseHeaderLine();
+}
+
+namespace
+{
+ /** tries to obtain the InteractionHandler associated with a given data source
+
+ If the data source is a sdb-level data source, it will have a DatabaseDocument associated
+ with it. This document may have an InteractionHandler used while loading it.
+
+ @throws RuntimeException
+ if it occurs during invoking any of the data source's methods, or if any of the involved
+ components violates its contract by not providing the required interfaces
+ */
+ Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XDataSource >& _rxDataSource, const Reference< XInteractionHandler >& _rFallback )
+ {
+ Reference< XInteractionHandler > xHandler( _rFallback );
+
+ // try to obtain the document model
+ Reference< XModel > xDocumentModel;
+ Reference< XDocumentDataSource > xDocDataSource( _rxDataSource, UNO_QUERY );
+ if ( xDocDataSource.is() )
+ xDocumentModel.set( xDocDataSource->getDatabaseDocument(), UNO_QUERY_THROW );
+
+ // see whether the document model can provide a handler
+ if ( xDocumentModel.is() )
+ {
+ xHandler = ::comphelper::NamedValueCollection::getOrDefault( xDocumentModel->getArgs(), u"InteractionHandler", xHandler );
+ }
+
+ return xHandler;
+ }
+ /** tries to obtain the InteractionHandler associated with a given connection
+
+ If the connection belongs to a sdb-level data source, then this data source
+ is examined for an interaction handler. Else, <NULL/> is returned.
+
+ @throws RuntimeException
+ if it occurs during invoking any of the data source's methods, or if any of the involved
+ components violates its contract by not providing the required interfaces
+ */
+ Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XConnection >& _rxConnection, const Reference< XInteractionHandler >& _rFallback )
+ {
+ // try whether there is a data source which the connection belongs to
+ Reference< XDataSource > xDataSource;
+ Reference< XChild > xAsChild( _rxConnection, UNO_QUERY );
+ if ( xAsChild.is() )
+ xDataSource.set(xAsChild->getParent(), css::uno::UNO_QUERY);
+
+ if ( xDataSource.is() )
+ return lcl_getInteractionHandler_throw( xDataSource, _rFallback );
+
+ return _rFallback;
+ }
+}
+
+Reference< XPropertySet > CopyTableWizard::impl_ensureDataAccessDescriptor_throw(
+ const Sequence< Any >& _rAllArgs, const sal_Int16 _nArgPos, SharedConnection& _out_rxConnection,
+ Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
+{
+ Reference< XPropertySet > xDescriptor;
+ _rAllArgs[ _nArgPos ] >>= xDescriptor;
+
+ // the descriptor must be non-NULL, of course
+ bool bIsValid = xDescriptor.is();
+
+ // it must support the proper service
+ if ( bIsValid )
+ {
+ Reference< XServiceInfo > xSI( xDescriptor, UNO_QUERY );
+ bIsValid = ( xSI.is()
+ && xSI->supportsService( "com.sun.star.sdb.DataAccessDescriptor" ) );
+ }
+
+ // it must be able to provide a connection
+ if ( bIsValid )
+ {
+ _out_rxConnection = impl_extractConnection_throw( xDescriptor, _out_rxDocInteractionHandler );
+ bIsValid = _out_rxConnection.is();
+ }
+
+ if ( !bIsValid )
+ {
+ throw IllegalArgumentException(
+ DBA_RES( STR_CTW_INVALID_DATA_ACCESS_DESCRIPTOR ),
+ *const_cast< CopyTableWizard* >( this ),
+ _nArgPos + 1
+ );
+ }
+
+ return xDescriptor;
+}
+
+namespace
+{
+ bool lcl_hasNonEmptyStringValue_throw( const Reference< XPropertySet >& _rxDescriptor,
+ const Reference< XPropertySetInfo >& rxPSI, const OUString& _rPropertyName )
+ {
+ OUString sValue;
+ if ( rxPSI->hasPropertyByName( _rPropertyName ) )
+ {
+ OSL_VERIFY( _rxDescriptor->getPropertyValue( _rPropertyName ) >>= sValue );
+ }
+ return !sValue.isEmpty();
+ }
+}
+
+void CopyTableWizard::impl_checkForUnsupportedSettings_throw( const Reference< XPropertySet >& _rxSourceDescriptor ) const
+{
+ OSL_PRECOND( _rxSourceDescriptor.is(), "CopyTableWizard::impl_checkForUnsupportedSettings_throw: illegal argument!" );
+ Reference< XPropertySetInfo > xPSI( _rxSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
+ OUString sUnsupportedSetting;
+
+ const OUString aSettings[] = {
+ OUString(PROPERTY_FILTER), OUString(PROPERTY_ORDER), OUString(PROPERTY_HAVING_CLAUSE), OUString(PROPERTY_GROUP_BY)
+ };
+ for (const auto & aSetting : aSettings)
+ {
+ if ( lcl_hasNonEmptyStringValue_throw( _rxSourceDescriptor, xPSI, aSetting ) )
+ {
+ sUnsupportedSetting = aSetting;
+ break;
+ }
+ }
+
+ if ( !sUnsupportedSetting.isEmpty() )
+ {
+ OUString sMessage(
+ DBA_RES(STR_CTW_ERROR_UNSUPPORTED_SETTING).
+ replaceFirst("$name$", sUnsupportedSetting));
+ throw IllegalArgumentException(
+ sMessage,
+ *const_cast< CopyTableWizard* >( this ),
+ 1
+ );
+ }
+
+}
+
+std::unique_ptr< ICopyTableSourceObject > CopyTableWizard::impl_extractSourceObject_throw( const Reference< XPropertySet >& _rxDescriptor, sal_Int32& _out_rCommandType ) const
+{
+ OSL_PRECOND( _rxDescriptor.is() && m_xSourceConnection.is(), "CopyTableWizard::impl_extractSourceObject_throw: illegal arguments!" );
+
+ Reference< XPropertySetInfo > xPSI( _rxDescriptor->getPropertySetInfo(), UNO_SET_THROW );
+ if ( !xPSI->hasPropertyByName( PROPERTY_COMMAND )
+ || !xPSI->hasPropertyByName( PROPERTY_COMMAND_TYPE )
+ )
+ throw IllegalArgumentException("Expecting a table or query specification.",
+ // TODO: resource
+ *const_cast< CopyTableWizard* >( this ), 1);
+
+ OUString sCommand;
+ _out_rCommandType = CommandType::COMMAND;
+ OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand );
+ OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND_TYPE ) >>= _out_rCommandType );
+
+ std::unique_ptr< ICopyTableSourceObject > pSourceObject;
+ Reference< XNameAccess > xContainer;
+ switch ( _out_rCommandType )
+ {
+ case CommandType::TABLE:
+ {
+ Reference< XTablesSupplier > xSuppTables( m_xSourceConnection.getTyped(), UNO_QUERY );
+ if ( xSuppTables.is() )
+ xContainer.set( xSuppTables->getTables(), UNO_SET_THROW );
+ }
+ break;
+ case CommandType::QUERY:
+ {
+ Reference< XQueriesSupplier > xSuppQueries( m_xSourceConnection.getTyped(), UNO_QUERY );
+ if ( xSuppQueries.is() )
+ xContainer.set( xSuppQueries->getQueries(), UNO_SET_THROW );
+ }
+ break;
+ default:
+ throw IllegalArgumentException(
+ DBA_RES( STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT ),
+ *const_cast< CopyTableWizard* >( this ),
+ 1
+ );
+ }
+
+ if ( xContainer.is() )
+ {
+ pSourceObject.reset( new ObjectCopySource( m_xSourceConnection,
+ Reference< XPropertySet >( xContainer->getByName( sCommand ), UNO_QUERY_THROW ) ) );
+ }
+ else
+ {
+ // our source connection is an SDBC level connection only, not a SDBCX level one
+ // Which means it cannot provide the to-be-copied object as component.
+
+ if ( _out_rCommandType == CommandType::QUERY )
+ // we cannot copy a query if the connection cannot provide it ...
+ throw IllegalArgumentException(
+ DBA_RES( STR_CTW_ERROR_NO_QUERY ),
+ *const_cast< CopyTableWizard* >( this ),
+ 1
+ );
+ pSourceObject.reset( new NamedTableCopySource( m_xSourceConnection, sCommand ) );
+ }
+
+ return pSourceObject;
+}
+
+void CopyTableWizard::impl_extractSourceResultSet_throw( const Reference< XPropertySet >& i_rDescriptor )
+{
+ Reference< XPropertySetInfo > xPSI( i_rDescriptor->getPropertySetInfo(), UNO_SET_THROW );
+
+ // extract relevant settings
+ if ( xPSI->hasPropertyByName( PROPERTY_RESULT_SET ) )
+ m_xSourceResultSet.set( i_rDescriptor->getPropertyValue( PROPERTY_RESULT_SET ), UNO_QUERY );
+
+ if ( xPSI->hasPropertyByName( PROPERTY_SELECTION ) )
+ OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_SELECTION ) >>= m_aSourceSelection );
+
+ if ( xPSI->hasPropertyByName( PROPERTY_BOOKMARK_SELECTION ) )
+ OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_BOOKMARK_SELECTION ) >>= m_bSourceSelectionBookmarks );
+
+ // sanity checks
+ const bool bHasResultSet = m_xSourceResultSet.is();
+ const bool bHasSelection = m_aSourceSelection.hasElements();
+ if ( bHasSelection && !bHasResultSet )
+ throw IllegalArgumentException("A result set is needed when specifying a selection to copy.",
+ // TODO: resource
+ *this, 1);
+
+ if ( bHasSelection && m_bSourceSelectionBookmarks )
+ {
+ Reference< XRowLocate > xRowLocate( m_xSourceResultSet, UNO_QUERY );
+ if ( !xRowLocate.is() )
+ {
+ ::dbtools::throwGenericSQLException(
+ DBA_RES(STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS),
+ *this
+ );
+ }
+ }
+}
+
+SharedConnection CopyTableWizard::impl_extractConnection_throw( const Reference< XPropertySet >& _rxDataSourceDescriptor,
+ Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
+{
+ SharedConnection xConnection;
+
+ OSL_PRECOND( _rxDataSourceDescriptor.is(), "CopyTableWizard::impl_extractConnection_throw: no descriptor!" );
+ if ( !_rxDataSourceDescriptor.is() )
+ return xConnection;
+
+ Reference< XInteractionHandler > xInteractionHandler;
+
+ do
+ {
+ Reference< XPropertySetInfo > xPSI( _rxDataSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
+
+ // if there's an ActiveConnection, use it
+ if ( xPSI->hasPropertyByName( PROPERTY_ACTIVE_CONNECTION ) )
+ {
+ Reference< XConnection > xPure;
+ OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xPure );
+ xConnection.reset( xPure, SharedConnection::NoTakeOwnership );
+ }
+ if ( xConnection.is() )
+ {
+ xInteractionHandler = lcl_getInteractionHandler_throw( xConnection.getTyped(), m_xInteractionHandler );
+ SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" );
+ break;
+ }
+
+ // there could be a DataSourceName or a DatabaseLocation, describing the css.sdb.DataSource
+ OUString sDataSource, sDatabaseLocation;
+ if ( xPSI->hasPropertyByName( PROPERTY_DATASOURCENAME ) )
+ OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sDataSource );
+ if ( xPSI->hasPropertyByName( PROPERTY_DATABASE_LOCATION ) )
+ OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATABASE_LOCATION ) >>= sDatabaseLocation );
+
+ // need a DatabaseContext for loading the data source
+ Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create( m_xContext );
+ Reference< XDataSource > xDataSource;
+ if ( !sDataSource.isEmpty() )
+ xDataSource.set( xDatabaseContext->getByName( sDataSource ), UNO_QUERY_THROW );
+ if ( !xDataSource.is() && !sDatabaseLocation.isEmpty() )
+ xDataSource.set( xDatabaseContext->getByName( sDatabaseLocation ), UNO_QUERY_THROW );
+
+ if ( xDataSource.is() )
+ {
+ // first, try connecting with completion
+ xInteractionHandler = lcl_getInteractionHandler_throw( xDataSource, m_xInteractionHandler );
+ SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" );
+ if ( xInteractionHandler.is() )
+ {
+ Reference< XCompletedConnection > xInteractiveConnection( xDataSource, UNO_QUERY );
+ if ( xInteractiveConnection.is() )
+ xConnection.reset( xInteractiveConnection->connectWithCompletion( xInteractionHandler ), SharedConnection::TakeOwnership );
+ }
+
+ // interactively connecting was not successful or possible -> connect without interaction
+ if ( !xConnection.is() )
+ {
+ xConnection.reset( xDataSource->getConnection( OUString(), OUString() ), SharedConnection::TakeOwnership );
+ }
+ }
+
+ if ( xConnection.is() )
+ break;
+
+ // finally, there could be a ConnectionResource/ConnectionInfo
+ OUString sConnectionResource;
+ Sequence< PropertyValue > aConnectionInfo;
+ if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_RESOURCE ) )
+ OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_RESOURCE ) >>= sConnectionResource );
+ if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_INFO ) )
+ OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_INFO ) >>= aConnectionInfo );
+
+ Reference< XDriverManager > xDriverManager;
+ try {
+ xDriverManager.set( ConnectionPool::create( m_xContext ), UNO_QUERY_THROW );
+ } catch( const Exception& ) { }
+ if ( !xDriverManager.is() )
+ // no connection pool installed
+ xDriverManager.set( DriverManager::create( m_xContext ), UNO_QUERY_THROW );
+
+ if ( aConnectionInfo.hasElements() )
+ xConnection.set( xDriverManager->getConnectionWithInfo( sConnectionResource, aConnectionInfo ), UNO_SET_THROW );
+ else
+ xConnection.set( xDriverManager->getConnection( sConnectionResource ), UNO_SET_THROW );
+ }
+ while ( false );
+
+ if ( xInteractionHandler != m_xInteractionHandler )
+ _out_rxDocInteractionHandler = xInteractionHandler;
+
+ return xConnection;
+}
+
+::utl::SharedUNOComponent< XPreparedStatement > CopyTableWizard::impl_createSourceStatement_throw() const
+{
+ OSL_PRECOND( m_xSourceConnection.is(), "CopyTableWizard::impl_createSourceStatement_throw: illegal call!" );
+ if ( !m_xSourceConnection.is() )
+ throw RuntimeException( "CopyTableWizard::impl_createSourceStatement_throw: illegal call!", *const_cast< CopyTableWizard* >( this ));
+
+ ::utl::SharedUNOComponent< XPreparedStatement > xStatement;
+ switch ( m_nCommandType )
+ {
+ case CommandType::TABLE:
+ xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
+ break;
+
+ case CommandType::QUERY:
+ {
+ OUString sQueryCommand( m_pSourceObject->getSelectStatement() );
+ xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
+
+ // check whether we have to fill in parameter values
+ // create and fill a composer
+
+ Reference< XMultiServiceFactory > xFactory( m_xSourceConnection, UNO_QUERY );
+ ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer;
+ if ( xFactory.is() )
+ // note: connections below the sdb-level are allowed to not support the XMultiServiceFactory interface
+ xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY );
+
+ if ( xComposer.is() )
+ {
+ xComposer->setQuery( sQueryCommand );
+
+ Reference< XParameters > xStatementParams( xStatement, UNO_QUERY );
+ OSL_ENSURE( xStatementParams.is(), "CopyTableWizard::impl_createSourceStatement_throw: no access to the statement's parameters!" );
+ // the statement should be a css.sdbc.PreparedStatement (this is what
+ // we created), and a prepared statement is required to support XParameters
+ if ( xStatementParams.is() )
+ {
+ OSL_ENSURE( m_xInteractionHandler.is(),
+ "CopyTableWizard::impl_createSourceStatement_throw: no interaction handler for the parameters request!" );
+ // we should always have an interaction handler - as last fallback, we create an own one in ::initialize
+
+ if ( m_xInteractionHandler.is() )
+ ::dbtools::askForParameters( xComposer, xStatementParams, m_xSourceConnection, m_xInteractionHandler );
+ }
+ }
+ }
+ break;
+
+ default:
+ // this should not have survived initialization phase
+ throw RuntimeException("No case matched, this should not have survived the initialization phase", *const_cast< CopyTableWizard* >( this ));
+ }
+
+ return xStatement;
+}
+
+namespace
+{
+ class ValueTransfer
+ {
+ public:
+ ValueTransfer( std::vector< sal_Int32 > _rColTypes,
+ const Reference< XRow >& _rxSource, const Reference< XParameters >& _rxDest )
+ :m_ColTypes( std::move(_rColTypes) )
+ ,m_xSource( _rxSource )
+ ,m_xDest( _rxDest )
+ {
+ }
+
+ template< typename VALUE_TYPE >
+ void transferValue( sal_Int32 _nSourcePos, sal_Int32 _nDestPos,
+ VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ),
+ void (SAL_CALL XParameters::*_pSetter)( sal_Int32, VALUE_TYPE ) )
+ {
+ VALUE_TYPE value( (m_xSource.get()->*_pGetter)( _nSourcePos ) );
+ if ( m_xSource->wasNull() )
+ m_xDest->setNull( _nDestPos, m_ColTypes[ _nSourcePos ] );
+ else
+ (m_xDest.get()->*_pSetter)( _nDestPos, value );
+ }
+
+ template< typename VALUE_TYPE >
+ void transferComplexValue( sal_Int32 _nSourcePos, sal_Int32 _nDestPos,
+ VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ),
+ void (SAL_CALL XParameters::*_pSetter)( sal_Int32, const VALUE_TYPE& ) )
+ {
+ const VALUE_TYPE value( (m_xSource.get()->*_pGetter)( _nSourcePos ) );
+ if ( m_xSource->wasNull() )
+ m_xDest->setNull( _nDestPos, m_ColTypes[ _nSourcePos ] );
+ else
+ (m_xDest.get()->*_pSetter)( _nDestPos, value );
+ }
+ private:
+ const std::vector< sal_Int32 > m_ColTypes;
+ const Reference< XRow > m_xSource;
+ const Reference< XParameters > m_xDest;
+ };
+}
+
+bool CopyTableWizard::impl_processCopyError_nothrow( const CopyTableRowEvent& _rEvent )
+{
+ try
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aCopyTableListeners );
+ while ( aIter.hasMoreElements() )
+ {
+ Reference< XCopyTableListener > xListener( aIter.next() );
+ sal_Int16 nListenerChoice = xListener->copyRowError( _rEvent );
+ switch ( nListenerChoice )
+ {
+ case CopyTableContinuation::Proceed: return true; // continue copying
+ case CopyTableContinuation::CallNextHandler: continue; // continue the loop, ask next listener
+ case CopyTableContinuation::Cancel: return false; // cancel copying
+ case CopyTableContinuation::AskUser: break; // stop asking the listeners, ask the user
+
+ default:
+ SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_processCopyError_nothrow: invalid listener response!" );
+ // ask next listener
+ continue;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // no listener felt responsible for the error, or a listener told to ask the user
+
+ try
+ {
+ SQLContext aError;
+ aError.Context = *this;
+ aError.Message = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING);
+
+ ::dbtools::SQLExceptionInfo aInfo( _rEvent.Error );
+ if ( aInfo.isValid() )
+ aError.NextException = _rEvent.Error;
+ else
+ {
+ // a non-SQL exception happened
+ Exception aException;
+ OSL_VERIFY( _rEvent.Error >>= aException );
+ SQLContext aContext;
+ aContext.Context = aException.Context;
+ aContext.Message = aException.Message;
+ aContext.Details = _rEvent.Error.getValueTypeName();
+ aError.NextException <<= aContext;
+ }
+
+ ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) );
+
+ ::rtl::Reference< ::comphelper::OInteractionApprove > xYes = new ::comphelper::OInteractionApprove;
+ xRequest->addContinuation( xYes );
+ xRequest->addContinuation( new ::comphelper::OInteractionDisapprove );
+
+ OSL_ENSURE( m_xInteractionHandler.is(),
+ "CopyTableWizard::impl_processCopyError_nothrow: we always should have an interaction handler!" );
+ if ( m_xInteractionHandler.is() )
+ m_xInteractionHandler->handle( xRequest );
+
+ if ( xYes->wasSelected() )
+ // continue copying
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // cancel copying
+ return false;
+}
+
+void CopyTableWizard::impl_copyRows_throw( const Reference< XResultSet >& _rxSourceResultSet,
+ const Reference< XPropertySet >& _rxDestTable )
+{
+ OSL_PRECOND( m_xDestConnection.is(), "CopyTableWizard::impl_copyRows_throw: illegal call!" );
+ if ( !m_xDestConnection.is() )
+ throw RuntimeException( "m_xDestConnection is set to null, CopyTableWizard::impl_copyRows_throw: illegal call!", *this );
+
+ Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
+
+ const OCopyTableWizard& rWizard = impl_getDialog_throw();
+ ODatabaseExport::TPositions aColumnPositions = rWizard.GetColumnPositions();
+ const bool bShouldCreatePrimaryKey = rWizard.shouldCreatePrimaryKey();
+
+ Reference< XRow > xRow ( _rxSourceResultSet, UNO_QUERY_THROW );
+ Reference< XRowLocate > xRowLocate ( _rxSourceResultSet, UNO_QUERY_THROW );
+
+ Reference< XResultSetMetaDataSupplier > xSuppResMeta( _rxSourceResultSet, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData> xMeta( xSuppResMeta->getMetaData() );
+
+ // we need a vector which all types
+ sal_Int32 nCount = xMeta->getColumnCount();
+ std::vector< sal_Int32 > aSourceColTypes;
+ aSourceColTypes.reserve( nCount + 1 );
+ aSourceColTypes.push_back( -1 ); // just to avoid an every time i-1 call
+
+ std::vector< sal_Int32 > aSourcePrec;
+ aSourcePrec.reserve( nCount + 1 );
+ aSourcePrec.push_back( -1 ); // just to avoid an every time i-1 call
+
+ for ( sal_Int32 k=1; k <= nCount; ++k )
+ {
+ aSourceColTypes.push_back( xMeta->getColumnType( k ) );
+ aSourcePrec.push_back( xMeta->getPrecision( k ) );
+ }
+
+ // now create, fill and execute the prepared statement
+ Reference< XPreparedStatement > xStatement( ODatabaseExport::createPreparedStatment( xDestMetaData, _rxDestTable, aColumnPositions ), UNO_SET_THROW );
+ Reference< XParameters > xStatementParams( xStatement, UNO_QUERY_THROW );
+
+ const bool bSelectedRecordsOnly = m_aSourceSelection.hasElements();
+ const Any* pSelectedRow = m_aSourceSelection.getConstArray();
+ const Any* pSelEnd = pSelectedRow + m_aSourceSelection.getLength();
+
+ sal_Int32 nRowCount = 0;
+ bool bContinue = false;
+
+ CopyTableRowEvent aCopyEvent;
+ aCopyEvent.Source = *this;
+ aCopyEvent.SourceData = _rxSourceResultSet;
+
+ do // loop as long as there are more rows or the selection ends
+ {
+ bContinue = false;
+ if ( bSelectedRecordsOnly )
+ {
+ if ( pSelectedRow != pSelEnd )
+ {
+ if ( m_bSourceSelectionBookmarks )
+ {
+ bContinue = xRowLocate->moveToBookmark( *pSelectedRow );
+ }
+ else
+ {
+ sal_Int32 nPos = 0;
+ OSL_VERIFY( *pSelectedRow >>= nPos );
+ bContinue = _rxSourceResultSet->absolute( nPos );
+ }
+ ++pSelectedRow;
+ }
+ }
+ else
+ bContinue = _rxSourceResultSet->next();
+
+ if ( !bContinue )
+ {
+ break;
+ }
+
+ ++nRowCount;
+
+ aCopyEvent.Error.clear();
+ try
+ {
+ bool bInsertedPrimaryKey = false;
+ // notify listeners
+ m_aCopyTableListeners.notifyEach( &XCopyTableListener::copyingRow, aCopyEvent );
+
+ sal_Int32 nSourceColumn( 1 );
+ ValueTransfer aTransfer( aSourceColTypes, xRow, xStatementParams );
+
+ for ( auto const& rColumnPos : aColumnPositions )
+ {
+ sal_Int32 nDestColumn = rColumnPos.first;
+ if ( nDestColumn == COLUMN_POSITION_NOT_FOUND )
+ {
+ ++nSourceColumn;
+ // otherwise we don't get the correct value when only the 2nd source column was selected
+ continue;
+ }
+
+ if ( bShouldCreatePrimaryKey && !bInsertedPrimaryKey )
+ {
+ xStatementParams->setInt( 1, nRowCount );
+ ++nSourceColumn;
+ bInsertedPrimaryKey = true;
+ continue;
+ }
+
+ if ( ( nSourceColumn < 1 ) || ( o3tl::make_unsigned(nSourceColumn) >= aSourceColTypes.size() ) )
+ { // ( we have to check here against 1 because the parameters are 1 based)
+ ::dbtools::throwSQLException("Internal error: invalid column type index.",
+ ::dbtools::StandardSQLState::INVALID_DESCRIPTOR_INDEX, *this);
+ }
+
+ switch ( aSourceColTypes[ nSourceColumn ] )
+ {
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getDouble, &XParameters::setDouble );
+ break;
+
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getString, &XParameters::setString );
+ break;
+
+ case DataType::BIGINT:
+ aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getLong, &XParameters::setLong );
+ break;
+
+ case DataType::FLOAT:
+ aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getFloat, &XParameters::setFloat );
+ break;
+
+ case DataType::LONGVARBINARY:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes );
+ break;
+
+ case DataType::DATE:
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getDate, &XParameters::setDate );
+ break;
+
+ case DataType::TIME:
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTime, &XParameters::setTime );
+ break;
+
+ case DataType::TIMESTAMP:
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTimestamp, &XParameters::setTimestamp );
+ break;
+
+ case DataType::BIT:
+ if ( aSourcePrec[nSourceColumn] > 1 )
+ {
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes );
+ break;
+ }
+ [[fallthrough]];
+ case DataType::BOOLEAN:
+ aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getBoolean, &XParameters::setBoolean );
+ break;
+
+ case DataType::TINYINT:
+ aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getByte, &XParameters::setByte );
+ break;
+
+ case DataType::SMALLINT:
+ aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getShort, &XParameters::setShort );
+ break;
+
+ case DataType::INTEGER:
+ aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getInt, &XParameters::setInt );
+ break;
+
+ case DataType::BLOB:
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBlob, &XParameters::setBlob );
+ break;
+
+ case DataType::CLOB:
+ aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getClob, &XParameters::setClob );
+ break;
+
+ default:
+ {
+ OUString aMessage( DBA_RES( STR_CTW_UNSUPPORTED_COLUMN_TYPE ) );
+
+ aMessage = aMessage.replaceFirst( "$type$", OUString::number( aSourceColTypes[ nSourceColumn ] ) );
+ aMessage = aMessage.replaceFirst( "$pos$", OUString::number( nSourceColumn ) );
+
+ ::dbtools::throwSQLException(
+ aMessage,
+ ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
+ *this
+ );
+ }
+ }
+ ++nSourceColumn;
+ }
+ xStatement->executeUpdate();
+
+ // notify listeners
+ m_aCopyTableListeners.notifyEach( &XCopyTableListener::copiedRow, aCopyEvent );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "");
+ aCopyEvent.Error = ::cppu::getCaughtException();
+ }
+
+ if ( aCopyEvent.Error.hasValue() )
+ bContinue = impl_processCopyError_nothrow( aCopyEvent );
+ }
+ while( bContinue );
+}
+
+void CopyTableWizard::impl_doCopy_nothrow()
+{
+ Any aError;
+
+ try
+ {
+ OCopyTableWizard& rWizard( impl_getDialog_throw() );
+
+ weld::WaitObject aWO(rWizard.getDialog());
+ Reference< XPropertySet > xTable;
+
+ switch ( rWizard.getOperation() )
+ {
+ case CopyTableOperation::CopyDefinitionOnly:
+ case CopyTableOperation::CopyDefinitionAndData:
+ {
+ xTable = rWizard.createTable();
+
+ if( !xTable.is() )
+ {
+ SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: createTable should throw here, shouldn't it?" );
+ break;
+ }
+
+ if( CopyTableOperation::CopyDefinitionOnly == rWizard.getOperation() )
+ break;
+
+ [[fallthrough]];
+ }
+
+ case CopyTableOperation::AppendData:
+ {
+ // note that the CopyDefinitionAndData case falls through to here.
+ assert((rWizard.getOperation() == CopyTableOperation::CopyDefinitionAndData) ||
+ (rWizard.getOperation() == CopyTableOperation::AppendData));
+ assert((rWizard.getOperation() == CopyTableOperation::CopyDefinitionAndData) == xTable.is());
+ if ( !xTable.is() )
+ {
+ assert(rWizard.getOperation() == CopyTableOperation::AppendData);
+ xTable = rWizard.getTable();
+ if ( !xTable.is() )
+ {
+ SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: getTable should throw here, shouldn't it?" );
+ break;
+ }
+ }
+
+ ::utl::SharedUNOComponent< XPreparedStatement > xSourceStatement;
+ ::utl::SharedUNOComponent< XResultSet > xSourceResultSet;
+
+ if ( m_xSourceResultSet.is() )
+ {
+ xSourceResultSet.reset( m_xSourceResultSet, ::utl::SharedUNOComponent< XResultSet >::NoTakeOwnership );
+ }
+ else
+ {
+ const bool bIsSameConnection = ( m_xSourceConnection.getTyped() == m_xDestConnection.getTyped() );
+ const bool bIsTable = ( CommandType::TABLE == m_nCommandType );
+ bool bDone = false;
+ if ( bIsSameConnection && bIsTable )
+ {
+ // try whether the server supports copying via SQL
+ try
+ {
+ m_xDestConnection->createStatement()->executeUpdate( impl_getServerSideCopyStatement_throw(xTable) );
+ bDone = true;
+ }
+ catch( const Exception& )
+ {
+ // this is allowed.
+ }
+ }
+
+ if ( !bDone )
+ {
+ xSourceStatement.set( impl_createSourceStatement_throw(), UNO_SET_THROW );
+ xSourceResultSet.set( xSourceStatement->executeQuery(), UNO_SET_THROW );
+ }
+ }
+
+ if ( xSourceResultSet.is() )
+ impl_copyRows_throw( xSourceResultSet, xTable );
+
+ // tdf#119962
+ const Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
+ OUString sDatabaseDest = xDestMetaData->getDatabaseProductName().toAsciiLowerCase();
+ // If we created a new primary key, then it won't necessarily be an IDENTITY column
+ const bool bShouldCreatePrimaryKey = rWizard.shouldCreatePrimaryKey();
+ if ( !bShouldCreatePrimaryKey && ((sDatabaseDest.indexOf("hsql") != -1) || (sDatabaseDest.indexOf("firebird") != -1)) )
+ {
+ const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, xTable, ::dbtools::EComposeRule::InDataManipulation, true );
+
+ OUString aSchema,aTable;
+ xTable->getPropertyValue("SchemaName") >>= aSchema;
+ xTable->getPropertyValue("Name") >>= aTable;
+ Any aCatalog = xTable->getPropertyValue("CatalogName");
+
+ const Reference< XResultSet > xResultPKCL(xDestMetaData->getPrimaryKeys(aCatalog,aSchema,aTable));
+ Reference< XRow > xRowPKCL(xResultPKCL, UNO_QUERY_THROW);
+ OUString sPKCL;
+ if ( xRowPKCL.is() )
+ {
+ if (xResultPKCL->next())
+ {
+ sPKCL = xRowPKCL->getString(4);
+ }
+ }
+
+ if (!sPKCL.isEmpty())
+ {
+ OUString strSql = "SELECT MAX(\"" + sPKCL + "\") FROM " + sComposedTableName;
+
+ Reference< XResultSet > xResultMAXNUM(m_xDestConnection->createStatement()->executeQuery(strSql));
+ Reference< XRow > xRow(xResultMAXNUM, UNO_QUERY_THROW);
+
+ sal_Int64 maxVal = -1L;
+ if (xResultMAXNUM->next())
+ {
+ maxVal = xRow->getLong(1);
+ }
+
+ if (maxVal > 0L)
+ {
+ strSql = "ALTER TABLE " + sComposedTableName + " ALTER \"" + sPKCL + "\" RESTART WITH " + OUString::number(maxVal + 1);
+
+ m_xDestConnection->createStatement()->execute(strSql);
+ }
+ }
+ }
+ }
+ break;
+
+ case CopyTableOperation::CreateAsView:
+ rWizard.createView();
+ break;
+
+ default:
+ SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: What operation, please?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ aError = ::cppu::getCaughtException();
+
+ // silence the error of the user cancelling the parameter's dialog
+ SQLException aSQLError;
+ if ( ( aError >>= aSQLError ) && ( aSQLError.ErrorCode == ::dbtools::ParameterInteractionCancelled ) )
+ {
+ aError.clear();
+ m_nOverrideExecutionResult = RET_CANCEL;
+ }
+ }
+
+ if ( aError.hasValue() && m_xInteractionHandler.is() )
+ {
+ try
+ {
+ ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( aError ) );
+ m_xInteractionHandler->handle( xRequest );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+OUString CopyTableWizard::impl_getServerSideCopyStatement_throw(const Reference< XPropertySet >& _xTable)
+{
+ const Reference<XColumnsSupplier> xDestColsSup(_xTable,UNO_QUERY_THROW);
+ const Sequence< OUString> aDestColumnNames = xDestColsSup->getColumns()->getElementNames();
+ const Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
+ const OUString sQuote = xDestMetaData->getIdentifierQuoteString();
+ OUStringBuffer sColumns;
+ // 1st check if the columns matching
+ for ( auto const & rColumnPositionPair : impl_getDialog_throw().GetColumnPositions() )
+ {
+ if ( COLUMN_POSITION_NOT_FOUND != rColumnPositionPair.second )
+ {
+ if ( !sColumns.isEmpty() )
+ sColumns.append(",");
+ sColumns.append(sQuote + aDestColumnNames[rColumnPositionPair.second - 1] + sQuote);
+ }
+ }
+ const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, _xTable, ::dbtools::EComposeRule::InDataManipulation, true );
+ OUString sSql("INSERT INTO " + sComposedTableName + " ( " + sColumns + " ) " + m_pSourceObject->getSelectStatement());
+
+ return sSql;
+}
+
+void SAL_CALL CopyTableWizard::initialize( const Sequence< Any >& _rArguments )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( isInitialized() )
+ throw AlreadyInitializedException( OUString(), *this );
+
+ sal_Int32 nArgCount( _rArguments.getLength() );
+ if ( ( nArgCount != 2 ) && ( nArgCount != 3 ) )
+ throw IllegalArgumentException(
+ DBA_RES( STR_CTW_ILLEGAL_PARAMETER_COUNT ),
+ *this,
+ 1
+ );
+
+ try
+ {
+ if ( nArgCount == 3 )
+ { // ->createWithInteractionHandler
+ if ( !( _rArguments[2] >>= m_xInteractionHandler ) )
+ throw IllegalArgumentException(
+ DBA_RES( STR_CTW_ERROR_INVALID_INTERACTIONHANDLER ),
+ *this,
+ 3
+ );
+ }
+ if ( !m_xInteractionHandler.is() )
+ m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr);
+
+ Reference< XInteractionHandler > xSourceDocHandler;
+ Reference< XPropertySet > xSourceDescriptor( impl_ensureDataAccessDescriptor_throw( _rArguments, 0, m_xSourceConnection, xSourceDocHandler ) );
+ impl_checkForUnsupportedSettings_throw( xSourceDescriptor );
+ m_pSourceObject = impl_extractSourceObject_throw( xSourceDescriptor, m_nCommandType );
+ impl_extractSourceResultSet_throw( xSourceDescriptor );
+
+ Reference< XInteractionHandler > xDestDocHandler;
+ impl_ensureDataAccessDescriptor_throw( _rArguments, 1, m_xDestConnection, xDestDocHandler );
+
+ if ( xDestDocHandler.is() && !m_xInteractionHandler.is() )
+ m_xInteractionHandler = xDestDocHandler;
+
+ Reference< XPropertySet > xInteractionHandler(m_xInteractionHandler, UNO_QUERY);
+ if (xInteractionHandler.is())
+ {
+ Any aParentWindow(xInteractionHandler->getPropertyValue("ParentWindow"));
+ aParentWindow >>= m_xParent;
+ }
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const SQLException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException(
+ DBA_RES( STR_CTW_ERROR_DURING_INITIALIZATION ),
+ *this,
+ ::cppu::getCaughtException()
+ );
+ }
+}
+
+::cppu::IPropertyArrayHelper& CopyTableWizard::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* CopyTableWizard::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+std::unique_ptr<weld::DialogController> CopyTableWizard::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ OSL_PRECOND( isInitialized(), "CopyTableWizard::createDialog: not initialized!" );
+ // this should have been prevented in ::execute already
+
+ auto xWizard = std::make_unique<OCopyTableWizard>(
+ Application::GetFrameWeld(rParent),
+ m_sDestinationTable,
+ m_nOperation,
+ *m_pSourceObject,
+ m_xSourceConnection.getTyped(),
+ m_xDestConnection.getTyped(),
+ m_xContext,
+ m_xInteractionHandler);
+
+ impl_attributesToDialog_nothrow(*xWizard);
+
+ return xWizard;
+}
+
+void CopyTableWizard::executedDialog( sal_Int16 _nExecutionResult )
+{
+ CopyTableWizard_DialogBase::executedDialog( _nExecutionResult );
+
+ if ( _nExecutionResult == RET_OK )
+ impl_doCopy_nothrow();
+
+ // do this after impl_doCopy_nothrow: The attributes may change during copying, for instance
+ // if the user entered an unqualified table name
+ impl_dialogToAttributes_nothrow( impl_getDialog_throw() );
+}
+
+} // namespace dbaui
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_CopyTableWizard_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::CopyTableWizard(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/dbinteraction.cxx b/dbaccess/source/ui/uno/dbinteraction.cxx
new file mode 100644
index 000000000..ad7480c1a
--- /dev/null
+++ b/dbaccess/source/ui/uno/dbinteraction.cxx
@@ -0,0 +1,387 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "dbinteraction.hxx"
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <connectivity/dbexception.hxx>
+#include <sqlmessage.hxx>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/task/XInteractionApprove.hpp>
+#include <com/sun/star/task/XInteractionDisapprove.hpp>
+#include <com/sun/star/task/XInteractionRetry.hpp>
+#include <com/sun/star/task/XInteractionAbort.hpp>
+#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
+#include <com/sun/star/sdb/XInteractionDocumentSave.hpp>
+#include <sfx2/QuerySaveDocument.hxx>
+#include <paramdialog.hxx>
+#include <vcl/svapp.hxx>
+#include <CollectionView.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbaccess_DatabaseInteractionHandler_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::SQLExceptionInteractionHandler(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbaccess_LegacyInteractionHandler_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::LegacyInteractionHandler(context));
+}
+
+namespace dbaui
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::ucb;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::beans;
+ using namespace ::dbtools;
+
+ // BasicInteractionHandler
+ BasicInteractionHandler::BasicInteractionHandler( const Reference< XComponentContext >& rxContext, const bool i_bFallbackToGeneric )
+ :m_xContext( rxContext )
+ ,m_bFallbackToGeneric( i_bFallbackToGeneric )
+ {
+ OSL_ENSURE( !m_bFallbackToGeneric,
+ "BasicInteractionHandler::BasicInteractionHandler: enabling legacy behavior, there should be no clients of this anymore!" );
+ }
+
+ void SAL_CALL BasicInteractionHandler::initialize(const Sequence<Any>& rArgs)
+ {
+ comphelper::SequenceAsHashMap aMap(rArgs);
+ m_xParentWindow.set(aMap.getValue("Parent"), UNO_QUERY);
+ }
+
+ sal_Bool SAL_CALL BasicInteractionHandler::handleInteractionRequest( const Reference< XInteractionRequest >& i_rRequest )
+ {
+ return impl_handle_throw( i_rRequest );
+ }
+
+ void SAL_CALL BasicInteractionHandler::handle( const Reference< XInteractionRequest >& i_rRequest )
+ {
+ impl_handle_throw( i_rRequest );
+ }
+
+ bool BasicInteractionHandler::impl_handle_throw( const Reference< XInteractionRequest >& i_Request )
+ {
+ Any aRequest( i_Request->getRequest() );
+ OSL_ENSURE(aRequest.hasValue(), "BasicInteractionHandler::handle: invalid request!");
+ if ( !aRequest.hasValue() )
+ // no request -> no handling
+ return false;
+
+ Sequence< Reference< XInteractionContinuation > > aContinuations( i_Request->getContinuations() );
+
+ // try to extract an SQLException (or one of its derived members
+ SQLExceptionInfo aInfo( aRequest );
+ if ( aInfo.isValid() )
+ {
+ implHandle( aInfo, aContinuations );
+ return true;
+ }
+
+ ParametersRequest aParamRequest;
+ if ( aRequest >>= aParamRequest )
+ {
+ implHandle( aParamRequest, aContinuations );
+ return true;
+ }
+
+ DocumentSaveRequest aDocuRequest;
+ if ( aRequest >>= aDocuRequest )
+ {
+ implHandle( aDocuRequest, aContinuations );
+ return true;
+ }
+
+ if ( m_bFallbackToGeneric )
+ return implHandleUnknown( i_Request );
+
+ return false;
+ }
+
+ void BasicInteractionHandler::implHandle(const ParametersRequest& _rParamRequest, const Sequence< Reference< XInteractionContinuation > >& _rContinuations)
+ {
+ SolarMutexGuard aGuard;
+ // want to open a dialog...
+
+ sal_Int32 nAbortPos = getContinuation(ABORT, _rContinuations);
+ sal_Int32 nParamPos = getContinuation(SUPPLY_PARAMETERS, _rContinuations);
+
+ Reference< XInteractionSupplyParameters > xParamCallback;
+ if (-1 != nParamPos)
+ xParamCallback.set(_rContinuations[nParamPos], UNO_QUERY);
+ OSL_ENSURE(xParamCallback.is(), "BasicInteractionHandler::implHandle(ParametersRequest): can't set the parameters without an appropriate interaction handler!s");
+
+ OParameterDialog aDlg(Application::GetFrameWeld(m_xParentWindow), _rParamRequest.Parameters, _rParamRequest.Connection, m_xContext);
+ sal_Int16 nResult = aDlg.run();
+ try
+ {
+ switch (nResult)
+ {
+ case RET_OK:
+ if (xParamCallback.is())
+ {
+ xParamCallback->setParameters(aDlg.getValues());
+ xParamCallback->select();
+ }
+ break;
+ default:
+ if (-1 != nAbortPos)
+ _rContinuations[nAbortPos]->select();
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void BasicInteractionHandler::implHandle(const SQLExceptionInfo& _rSqlInfo, const Sequence< Reference< XInteractionContinuation > >& _rContinuations)
+ {
+ SolarMutexGuard aGuard;
+ // want to open a dialog...
+
+ sal_Int32 nApprovePos = getContinuation(APPROVE, _rContinuations);
+ sal_Int32 nDisapprovePos = getContinuation(DISAPPROVE, _rContinuations);
+ sal_Int32 nAbortPos = getContinuation(ABORT, _rContinuations);
+ sal_Int32 nRetryPos = getContinuation(RETRY, _rContinuations);
+
+ // determine the style of the dialog, dependent on the present continuation types
+ MessBoxStyle nDialogStyle = MessBoxStyle::NONE;
+ bool bHaveCancel = nAbortPos != -1;
+ // "approve" means "Yes", "disapprove" means "No"
+ // VCL only supports having both (which makes sense ...)
+ if ( ( nApprovePos != -1 ) || ( nDisapprovePos != -1 ) )
+ nDialogStyle = ( bHaveCancel ? MessBoxStyle::YesNoCancel : MessBoxStyle::YesNo ) | MessBoxStyle::DefaultYes;
+ else
+ {
+ // if there's no yes/no, then use a default OK button
+ nDialogStyle = ( bHaveCancel ? MessBoxStyle::OkCancel : MessBoxStyle::Ok ) | MessBoxStyle::DefaultOk;
+ }
+
+ // If there's a "Retry" continuation, have a "Retry" button
+ if ( nRetryPos != -1 )
+ {
+ nDialogStyle = MessBoxStyle::RetryCancel | MessBoxStyle::DefaultRetry;
+ }
+
+ // execute the dialog
+ OSQLMessageBox aDialog(nullptr, _rSqlInfo, nDialogStyle);
+ // TODO: need a way to specify the parent window
+ sal_Int16 nResult = aDialog.run();
+ try
+ {
+ switch (nResult)
+ {
+ case RET_YES:
+ case RET_OK:
+ if ( nApprovePos != -1 )
+ _rContinuations[ nApprovePos ]->select();
+ else
+ OSL_ENSURE( nResult != RET_YES, "BasicInteractionHandler::implHandle: no handler for YES!" );
+ break;
+
+ case RET_NO:
+ if ( nDisapprovePos != -1 )
+ _rContinuations[ nDisapprovePos ]->select();
+ else
+ OSL_FAIL( "BasicInteractionHandler::implHandle: no handler for NO!" );
+ break;
+
+ case RET_CANCEL:
+ if ( nAbortPos != -1 )
+ _rContinuations[ nAbortPos ]->select();
+ else if ( nDisapprovePos != -1 )
+ _rContinuations[ nDisapprovePos ]->select();
+ else
+ OSL_FAIL( "BasicInteractionHandler::implHandle: no handler for CANCEL!" );
+ break;
+ case RET_RETRY:
+ if ( nRetryPos != -1 )
+ _rContinuations[ nRetryPos ]->select();
+ else
+ OSL_FAIL( "BasicInteractionHandler::implHandle: where does the RETRY come from?" );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ void BasicInteractionHandler::implHandle(const DocumentSaveRequest& _rDocuRequest, const Sequence< Reference< XInteractionContinuation > >& _rContinuations)
+ {
+ SolarMutexGuard aGuard;
+ // want to open a dialog...
+
+ sal_Int32 nApprovePos = getContinuation(APPROVE, _rContinuations);
+ sal_Int32 nDisApprovePos = getContinuation(DISAPPROVE, _rContinuations);
+ sal_Int32 nAbortPos = getContinuation(ABORT, _rContinuations);
+
+ short nRet = RET_YES;
+ if ( -1 != nApprovePos )
+ {
+ // ask whether it should be saved
+ nRet = ExecuteQuerySaveDocument(Application::GetFrameWeld(m_xParentWindow), _rDocuRequest.Name);
+ }
+
+ if ( RET_CANCEL == nRet )
+ {
+ if (-1 != nAbortPos)
+ _rContinuations[nAbortPos]->select();
+ return;
+ }
+ else if ( RET_YES == nRet )
+ {
+ sal_Int32 nDocuPos = getContinuation(SUPPLY_DOCUMENTSAVE, _rContinuations);
+
+ if (-1 != nDocuPos)
+ {
+ Reference< XInteractionDocumentSave > xCallback(_rContinuations[nDocuPos], UNO_QUERY);
+ OSL_ENSURE(xCallback.is(), "BasicInteractionHandler::implHandle(DocumentSaveRequest): can't save document without an appropriate interaction handler!s");
+
+ OCollectionView aDlg(Application::GetFrameWeld(m_xParentWindow), _rDocuRequest.Content, _rDocuRequest.Name, m_xContext);
+ sal_Int16 nResult = aDlg.run();
+ try
+ {
+ switch (nResult)
+ {
+ case RET_OK:
+ if (xCallback.is())
+ {
+ xCallback->setName(aDlg.getName(), aDlg.getSelectedFolder());
+ xCallback->select();
+ }
+ break;
+ default:
+ if (-1 != nAbortPos)
+ _rContinuations[nAbortPos]->select();
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ else if ( -1 != nApprovePos )
+ _rContinuations[nApprovePos]->select();
+ }
+ else if ( -1 != nDisApprovePos )
+ _rContinuations[nDisApprovePos]->select();
+ }
+
+ bool BasicInteractionHandler::implHandleUnknown( const Reference< XInteractionRequest >& _rxRequest )
+ {
+ if ( m_xContext.is() )
+ {
+ Reference< XInteractionHandler2 > xFallbackHandler(
+ InteractionHandler::createWithParent(m_xContext, nullptr) );
+ xFallbackHandler->handle( _rxRequest );
+ return true;
+ }
+ return false;
+ }
+
+ sal_Int32 BasicInteractionHandler::getContinuation(Continuation _eCont, const Sequence< Reference< XInteractionContinuation > >& _rContinuations)
+ {
+ const Reference< XInteractionContinuation >* pContinuations = _rContinuations.getConstArray();
+ for (sal_Int32 i=0; i<_rContinuations.getLength(); ++i, ++pContinuations)
+ {
+ switch (_eCont)
+ {
+ case APPROVE:
+ if (Reference< XInteractionApprove >(*pContinuations, UNO_QUERY).is())
+ return i;
+ break;
+ case DISAPPROVE:
+ if (Reference< XInteractionDisapprove >(*pContinuations, UNO_QUERY).is())
+ return i;
+ break;
+ case RETRY:
+ if (Reference< XInteractionRetry >(*pContinuations, UNO_QUERY).is())
+ return i;
+ break;
+ case ABORT:
+ if (Reference< XInteractionAbort >(*pContinuations, UNO_QUERY).is())
+ return i;
+ break;
+ case SUPPLY_PARAMETERS:
+ if (Reference< XInteractionSupplyParameters >(*pContinuations, UNO_QUERY).is())
+ return i;
+ break;
+ case SUPPLY_DOCUMENTSAVE:
+ if (Reference< XInteractionDocumentSave >(*pContinuations, UNO_QUERY).is())
+ return i;
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ // SQLExceptionInteractionHandler
+ OUString SAL_CALL SQLExceptionInteractionHandler::getImplementationName()
+ {
+ return "com.sun.star.comp.dbaccess.DatabaseInteractionHandler";
+ }
+ sal_Bool SAL_CALL SQLExceptionInteractionHandler::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+ css::uno::Sequence< OUString > SAL_CALL SQLExceptionInteractionHandler::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.DatabaseInteractionHandler" };
+ }
+
+ // LegacyInteractionHandler
+ OUString SAL_CALL LegacyInteractionHandler::getImplementationName()
+ {
+ return "com.sun.star.comp.dbaccess.LegacyInteractionHandler";
+ }
+ sal_Bool SAL_CALL LegacyInteractionHandler::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+ css::uno::Sequence< OUString > SAL_CALL LegacyInteractionHandler::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.InteractionHandler" };
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/dbinteraction.hxx b/dbaccess/source/ui/uno/dbinteraction.hxx
new file mode 100644
index 000000000..fdb0dbd2c
--- /dev/null
+++ b/dbaccess/source/ui/uno/dbinteraction.hxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <connectivity/CommonTools.hxx>
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/task/XInteractionHandler2.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdb/DocumentSaveRequest.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace dbtools
+{
+ class SQLExceptionInfo;
+}
+
+namespace dbaui
+{
+
+ // BasicInteractionHandler
+ typedef ::cppu::WeakImplHelper< css::lang::XServiceInfo
+ , css::lang::XInitialization
+ , css::task::XInteractionHandler2
+ > BasicInteractionHandler_Base;
+ /** implements an <type scope="com.sun.star.task">XInteractionHandler</type> for
+ database related interaction requests.
+ <p/>
+ Supported interaction requests by now (specified by an exception: The appropriate exception
+ has to be returned by the getRequest method of the object implementing the
+ <type scope="com.sun.star.task">XInteractionRequest</type> interface.
+ <ul>
+ <li><b><type scope="com.sun.star.sdbc">SQLException</type></b>: requests to display a
+ standard error dialog for the (maybe chained) exception given</li>
+ </ul>
+ */
+ class BasicInteractionHandler
+ :public BasicInteractionHandler_Base
+ {
+ css::uno::Reference< css::awt::XWindow > m_xParentWindow;
+ const css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+ const bool m_bFallbackToGeneric;
+
+ public:
+ BasicInteractionHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const bool i_bFallbackToGeneric
+ );
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rArgs ) override;
+
+ // XInteractionHandler2
+ virtual sal_Bool SAL_CALL handleInteractionRequest( const css::uno::Reference< css::task::XInteractionRequest >& Request ) override;
+
+ // XInteractionHandler
+ virtual void SAL_CALL handle( const css::uno::Reference< css::task::XInteractionRequest >& Request ) override;
+
+ protected:
+ bool
+ impl_handle_throw( const css::uno::Reference< css::task::XInteractionRequest >& i_Request );
+
+ /// handle SQLExceptions (and derived classes)
+ static void implHandle(
+ const ::dbtools::SQLExceptionInfo& _rSqlInfo,
+ const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations);
+
+ /// handle parameter requests
+ void implHandle(
+ const css::sdb::ParametersRequest& _rParamRequest,
+ const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations);
+
+ /// handle document save requests
+ void implHandle(
+ const css::sdb::DocumentSaveRequest& _rParamRequest,
+ const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations);
+
+ /// handles requests which are not SDB-specific
+ bool implHandleUnknown(
+ const css::uno::Reference< css::task::XInteractionRequest >& _rxRequest );
+
+ /// known continuation types
+ enum Continuation
+ {
+ APPROVE,
+ DISAPPROVE,
+ RETRY,
+ ABORT,
+ SUPPLY_PARAMETERS,
+ SUPPLY_DOCUMENTSAVE
+ };
+ /** check if a given continuation sequence contains a given continuation type<p/>
+ @return the index within <arg>_rContinuations</arg> of the first occurrence of a continuation
+ of the requested type, -1 of no such continuation exists
+ */
+ static sal_Int32 getContinuation(
+ Continuation _eCont,
+ const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& _rContinuations);
+ };
+
+ // SQLExceptionInteractionHandler
+ class SQLExceptionInteractionHandler : public BasicInteractionHandler
+ {
+ public:
+ explicit SQLExceptionInteractionHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext
+ )
+ :BasicInteractionHandler( rxContext, false )
+ {
+ }
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ };
+
+ // SQLExceptionInteractionHandler
+ /** an implementation for the legacy css.sdb.InteractionHandler
+
+ css.sdb.InteractionHandler is deprecated, as it does not only handle database related interactions,
+ but also delegates all kind of unknown requests to a css.task.InteractionHandler.
+
+ In today's architecture, there's only one central css.task.InteractionHandler, which is to be used
+ for all requests. Depending on configuration information, it decides which handler implementation
+ to delegate a request to.
+
+ SQLExceptionInteractionHandler is the delegatee which handles only database related interactions.
+ LegacyInteractionHandler is the version which first checks for a database related interaction, and
+ forwards everything else to the css.task.InteractionHandler.
+ */
+ class LegacyInteractionHandler : public BasicInteractionHandler
+ {
+ public:
+ explicit LegacyInteractionHandler(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext
+ )
+ :BasicInteractionHandler( rxContext, true )
+ {
+ }
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx b/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx
new file mode 100644
index 000000000..5b1636f90
--- /dev/null
+++ b/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <textconnectionsettings.hxx>
+#include <unoadmin.hxx>
+#include <stringconstants.hxx>
+#include <propertystorage.hxx>
+
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdb/XTextConnectionSettings.hpp>
+
+#include <comphelper/proparrhlp.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::beans::Property;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+
+ // OTextConnectionSettingsDialog
+
+ namespace {
+
+ class OTextConnectionSettingsDialog;
+
+ }
+
+ typedef ::cppu::ImplInheritanceHelper< ODatabaseAdministrationDialog
+ , css::sdb::XTextConnectionSettings
+ > OTextConnectionSettingsDialog_BASE;
+ typedef ::comphelper::OPropertyArrayUsageHelper< OTextConnectionSettingsDialog > OTextConnectionSettingsDialog_PBASE;
+
+ namespace {
+
+ class OTextConnectionSettingsDialog
+ :public OTextConnectionSettingsDialog_BASE
+ ,public OTextConnectionSettingsDialog_PBASE
+ {
+ PropertyValues m_aPropertyValues;
+
+ public:
+ explicit OTextConnectionSettingsDialog( const Reference<XComponentContext>& _rContext );
+
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ DECLARE_SERVICE_INFO();
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const override;
+
+ // Overrides to resolve inheritance ambiguity
+ virtual void SAL_CALL setPropertyValue(const OUString& p1, const css::uno::Any& p2) override
+ { ODatabaseAdministrationDialog::setPropertyValue(p1, p2); }
+ virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& p1) override
+ { return ODatabaseAdministrationDialog::getPropertyValue(p1); }
+ virtual void SAL_CALL addPropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
+ { ODatabaseAdministrationDialog::addPropertyChangeListener(p1, p2); }
+ virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
+ { ODatabaseAdministrationDialog::removePropertyChangeListener(p1, p2); }
+ virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
+ { ODatabaseAdministrationDialog::addVetoableChangeListener(p1, p2); }
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
+ { ODatabaseAdministrationDialog::removeVetoableChangeListener(p1, p2); }
+ virtual void SAL_CALL setTitle(const OUString& p1) override
+ { ODatabaseAdministrationDialog::setTitle(p1); }
+ virtual sal_Int16 SAL_CALL execute() override
+ { return ODatabaseAdministrationDialog::execute(); }
+
+ protected:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ using OTextConnectionSettingsDialog_BASE::getFastPropertyValue;
+ };
+
+ }
+
+ // OTextConnectionSettingsDialog
+ OTextConnectionSettingsDialog::OTextConnectionSettingsDialog( const Reference<XComponentContext>& _rContext )
+ :OTextConnectionSettingsDialog_BASE( _rContext )
+ {
+ TextConnectionSettingsDialog::bindItemStorages( *m_pDatasourceItems, m_aPropertyValues );
+ }
+
+ css::uno::Sequence<sal_Int8>
+ OTextConnectionSettingsDialog::getImplementationId()
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+ OUString SAL_CALL OTextConnectionSettingsDialog::getImplementationName()
+ {
+ return "com.sun.star.comp.dbaccess.OTextConnectionSettingsDialog";
+ }
+ sal_Bool SAL_CALL OTextConnectionSettingsDialog::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+ css::uno::Sequence< OUString > SAL_CALL OTextConnectionSettingsDialog::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.TextConnectionSettings" };
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL OTextConnectionSettingsDialog::getPropertySetInfo()
+ {
+ return createPropertySetInfo( getInfoHelper() );
+ }
+
+ ::cppu::IPropertyArrayHelper& OTextConnectionSettingsDialog::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OTextConnectionSettingsDialog::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+
+ // in addition to the properties registered by the base class, we have
+ // more properties which are not even handled by the PropertyContainer implementation,
+ // but whose values are stored in our item set
+ sal_Int32 nProp = aProps.getLength();
+ aProps.realloc( nProp + 6 );
+ auto pProps = aProps.getArray();
+
+ pProps[ nProp++ ] = Property(
+ "HeaderLine",
+ PROPERTY_ID_HEADER_LINE,
+ ::cppu::UnoType< sal_Bool >::get(),
+ PropertyAttribute::TRANSIENT
+ );
+
+ pProps[ nProp++ ] = Property(
+ "FieldDelimiter",
+ PROPERTY_ID_FIELD_DELIMITER,
+ ::cppu::UnoType< OUString >::get(),
+ PropertyAttribute::TRANSIENT
+ );
+
+ pProps[ nProp++ ] = Property(
+ "StringDelimiter",
+ PROPERTY_ID_STRING_DELIMITER,
+ ::cppu::UnoType< OUString >::get(),
+ PropertyAttribute::TRANSIENT
+ );
+
+ pProps[ nProp++ ] = Property(
+ "DecimalDelimiter",
+ PROPERTY_ID_DECIMAL_DELIMITER,
+ ::cppu::UnoType< OUString >::get(),
+ PropertyAttribute::TRANSIENT
+ );
+
+ pProps[ nProp++ ] = Property(
+ "ThousandDelimiter",
+ PROPERTY_ID_THOUSAND_DELIMITER,
+ ::cppu::UnoType< OUString >::get(),
+ PropertyAttribute::TRANSIENT
+ );
+
+ pProps[ nProp++ ] = Property(
+ "CharSet",
+ PROPERTY_ID_ENCODING,
+ ::cppu::UnoType< OUString >::get(),
+ PropertyAttribute::TRANSIENT
+ );
+
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+ std::unique_ptr<weld::DialogController> OTextConnectionSettingsDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ return std::make_unique<TextConnectionSettingsDialog>(Application::GetFrameWeld(rParent), *m_pDatasourceItems);
+ }
+
+ void SAL_CALL OTextConnectionSettingsDialog::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
+ {
+ PropertyValues::const_iterator pos = m_aPropertyValues.find( _nHandle );
+ if ( pos != m_aPropertyValues.end() )
+ {
+ pos->second->setPropertyValue( _rValue );
+ }
+ else
+ {
+ OTextConnectionSettingsDialog::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
+ }
+ }
+
+ sal_Bool SAL_CALL OTextConnectionSettingsDialog::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
+ {
+ bool bModified = false;
+
+ PropertyValues::const_iterator pos = m_aPropertyValues.find( _nHandle );
+ if ( pos != m_aPropertyValues.end() )
+ {
+ // we're lazy here ...
+ _rConvertedValue = _rValue;
+ pos->second->getPropertyValue( _rOldValue );
+ bModified = true;
+ }
+ else
+ {
+ bModified = OTextConnectionSettingsDialog::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue );
+ }
+
+ return bModified;
+ }
+
+ void SAL_CALL OTextConnectionSettingsDialog::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ PropertyValues::const_iterator pos = m_aPropertyValues.find( _nHandle );
+ if ( pos != m_aPropertyValues.end() )
+ {
+ pos->second->getPropertyValue( _rValue );
+ }
+ else
+ {
+ OTextConnectionSettingsDialog::getFastPropertyValue( _rValue, _nHandle );
+ }
+ }
+
+} // namespace dbaui
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbaccess_OTextConnectionSettingsDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(static_cast<dbaui::ODatabaseAdministrationDialog*>(new ::dbaui::OTextConnectionSettingsDialog(context)));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/unoDirectSql.cxx b/dbaccess/source/ui/uno/unoDirectSql.cxx
new file mode 100644
index 000000000..7b3a4cc6c
--- /dev/null
+++ b/dbaccess/source/ui/uno/unoDirectSql.cxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "unoDirectSql.hxx"
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/connection/XConnection.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <directsql.hxx>
+#include <datasourceconnector.hxx>
+#include <strings.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sdb_DirectSQLDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::ODirectSQLDialog(context));
+}
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::sdbc;
+
+ // ODirectSQLDialog
+ ODirectSQLDialog::ODirectSQLDialog(const Reference< XComponentContext >& _rxORB)
+ :ODirectSQLDialog_BASE( _rxORB )
+ {
+
+ }
+
+ ODirectSQLDialog::~ODirectSQLDialog()
+ {
+
+ }
+
+ css::uno::Sequence<sal_Int8> ODirectSQLDialog::getImplementationId()
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+ OUString SAL_CALL ODirectSQLDialog::getImplementationName()
+ {
+ return "com.sun.star.comp.sdb.DirectSQLDialog";
+ }
+ sal_Bool SAL_CALL ODirectSQLDialog::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+ css::uno::Sequence< OUString > SAL_CALL ODirectSQLDialog::getSupportedServiceNames( )
+ {
+ return { SERVICE_SDB_DIRECTSQLDIALOG };
+ }
+
+ css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODirectSQLDialog::getPropertySetInfo()
+ {
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+ ::cppu::IPropertyArrayHelper& ODirectSQLDialog::getInfoHelper()
+ {
+ return *ODirectSQLDialog::getArrayHelper();
+ }
+ ::cppu::IPropertyArrayHelper* ODirectSQLDialog::createArrayHelper( ) const
+ {
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+
+ std::unique_ptr<weld::DialogController> ODirectSQLDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ // obtain all the objects needed for the dialog
+ Reference< XConnection > xConnection = m_xActiveConnection;
+ weld::Window* pParent = Application::GetFrameWeld(rParent);
+ if ( !xConnection.is() )
+ {
+ try
+ {
+ // the connection the row set is working with
+ ODatasourceConnector aDSConnector(m_aContext, pParent);
+ xConnection = aDSConnector.connect( m_sInitialSelection, nullptr );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ if (!xConnection.is())
+ {
+ // can't create the dialog if I have improper settings
+ return nullptr;
+ }
+
+ return std::make_unique<DirectSQLDialog>(pParent, xConnection);
+ }
+
+ void ODirectSQLDialog::implInitialize(const Any& _rValue)
+ {
+ PropertyValue aProperty;
+ if (_rValue >>= aProperty)
+ {
+ if (aProperty.Name == "InitialSelection")
+ {
+ OSL_VERIFY( aProperty.Value >>= m_sInitialSelection );
+ return;
+ }
+ else if (aProperty.Name == "ActiveConnection")
+ {
+ m_xActiveConnection.set( aProperty.Value, UNO_QUERY );
+ OSL_ENSURE( m_xActiveConnection.is(), "ODirectSQLDialog::implInitialize: invalid connection!" );
+ return;
+ }
+ }
+ ODirectSQLDialog_BASE::implInitialize(_rValue);
+ }
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/unoDirectSql.hxx b/dbaccess/source/ui/uno/unoDirectSql.hxx
new file mode 100644
index 000000000..c83f975d6
--- /dev/null
+++ b/dbaccess/source/ui/uno/unoDirectSql.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svtools/genericunodialog.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <connectivity/CommonTools.hxx>
+
+namespace dbaui
+{
+
+ // ODirectSQLDialog
+ class ODirectSQLDialog;
+ typedef ::svt::OGenericUnoDialog ODirectSQLDialog_BASE;
+ typedef ::comphelper::OPropertyArrayUsageHelper< ODirectSQLDialog > ODirectSQLDialog_PBASE;
+
+ class ODirectSQLDialog
+ :public ODirectSQLDialog_BASE
+ ,public ODirectSQLDialog_PBASE
+ {
+ OUString m_sInitialSelection;
+ css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection;
+ public:
+ explicit ODirectSQLDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+ virtual ~ODirectSQLDialog() override;
+
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+ protected:
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ virtual void implInitialize(const css::uno::Any& _rValue) override;
+ };
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/unoadmin.cxx b/dbaccess/source/ui/uno/unoadmin.cxx
new file mode 100644
index 000000000..3d863b92e
--- /dev/null
+++ b/dbaccess/source/ui/uno/unoadmin.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unoadmin.hxx>
+#include <dbadmin.hxx>
+
+#include <osl/mutex.hxx>
+
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+ODatabaseAdministrationDialog::ODatabaseAdministrationDialog(const Reference< XComponentContext >& _rxORB)
+ :ODatabaseAdministrationDialogBase(_rxORB)
+ ,m_pItemPoolDefaults(nullptr)
+{
+ m_pCollection.reset( new ::dbaccess::ODsnTypeCollection(_rxORB) );
+ ODbAdminDialog::createItemSet(m_pDatasourceItems, m_pItemPool, m_pItemPoolDefaults, m_pCollection.get());
+}
+
+ODatabaseAdministrationDialog::~ODatabaseAdministrationDialog()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (m_xDialog)
+ destroyDialog();
+ ODbAdminDialog::destroyItemSet(m_pDatasourceItems, m_pItemPool, m_pItemPoolDefaults);
+}
+
+void ODatabaseAdministrationDialog::implInitialize(const Any& _rValue)
+{
+ PropertyValue aProperty;
+ if (_rValue >>= aProperty)
+ {
+ if (aProperty.Name == "InitialSelection")
+ {
+ m_aInitialSelection = aProperty.Value;
+ }
+ else if (aProperty.Name == "ActiveConnection")
+ {
+ m_xActiveConnection.set(aProperty.Value,UNO_QUERY);
+ }
+ else
+ ODatabaseAdministrationDialogBase::implInitialize(_rValue);
+ }
+ else
+ ODatabaseAdministrationDialogBase::implInitialize(_rValue);
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/uno/unosqlmessage.cxx b/dbaccess/source/ui/uno/unosqlmessage.cxx
new file mode 100644
index 000000000..39364ba25
--- /dev/null
+++ b/dbaccess/source/ui/uno/unosqlmessage.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sqlmessage.hxx>
+#include <unosqlmessage.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <connectivity/dbexception.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using namespace dbaui;
+using namespace dbtools;
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OSQLMessageDialog_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new OSQLMessageDialog(context));
+}
+
+namespace dbaui
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+OSQLMessageDialog::OSQLMessageDialog(const Reference< XComponentContext >& _rxORB)
+ :OSQLMessageDialogBase(_rxORB)
+{
+ registerMayBeVoidProperty(PROPERTY_SQLEXCEPTION, PROPERTY_ID_SQLEXCEPTION, PropertyAttribute::TRANSIENT | PropertyAttribute::MAYBEVOID,
+ &m_aException, ::cppu::UnoType<SQLException>::get());
+ registerProperty( PROPERTY_HELP_URL, PROPERTY_ID_HELP_URL, PropertyAttribute::TRANSIENT,
+ &m_sHelpURL, cppu::UnoType<decltype(m_sHelpURL)>::get() );
+}
+
+Sequence<sal_Int8> SAL_CALL OSQLMessageDialog::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+OUString SAL_CALL OSQLMessageDialog::getImplementationName()
+{
+ return "org.openoffice.comp.dbu.OSQLMessageDialog";
+}
+
+css::uno::Sequence<OUString> SAL_CALL OSQLMessageDialog::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.ErrorMessageDialog" };
+}
+
+void OSQLMessageDialog::initialize(Sequence<Any> const & args)
+{
+ OUString title;
+ Reference< css::awt::XWindow > parentWindow;
+
+ if ((args.getLength() == 3) && (args[0] >>= title) && (args[1] >>= parentWindow)) {
+ Sequence<Any> s(comphelper::InitAnyPropertySequence(
+ {
+ {"Title", Any(title)},
+ {"ParentWindow", Any(parentWindow)},
+ {"SQLException", args[2]}
+ }));
+ OGenericUnoDialog::initialize(s);
+ } else {
+ OGenericUnoDialog::initialize(args);
+ }
+}
+
+sal_Bool SAL_CALL OSQLMessageDialog::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
+{
+ switch (_nHandle)
+ {
+ case PROPERTY_ID_SQLEXCEPTION:
+ {
+ SQLExceptionInfo aInfo(_rValue);
+ if (!aInfo.isValid())
+ throw IllegalArgumentException();
+
+ _rOldValue = m_aException;
+ _rConvertedValue = aInfo.get();
+
+ return true;
+ // always assume "modified", don't bother with comparing the two values
+ }
+ default:
+ return OSQLMessageDialogBase::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
+ }
+}
+
+Reference<XPropertySetInfo> SAL_CALL OSQLMessageDialog::getPropertySetInfo()
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+::cppu::IPropertyArrayHelper& OSQLMessageDialog::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OSQLMessageDialog::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+std::unique_ptr<weld::DialogController> OSQLMessageDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ weld::Window* pParent = Application::GetFrameWeld(rParent);
+ if ( m_aException.hasValue() )
+ return std::make_unique<OSQLMessageBox>(pParent, SQLExceptionInfo(m_aException), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, m_sHelpURL);
+
+ OSL_FAIL("OSQLMessageDialog::createDialog : You should use the SQLException property to specify the error to display!");
+ return std::make_unique<OSQLMessageBox>(pParent, SQLException());
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */